diff --git a/.CMake/alg_support.cmake b/.CMake/alg_support.cmake index d499d99a3b..4176e91d63 100644 --- a/.CMake/alg_support.cmake +++ b/.CMake/alg_support.cmake @@ -97,6 +97,20 @@ cmake_dependent_option(OQS_ENABLE_KEM_bike_l1 "" ON "OQS_ENABLE_KEM_BIKE" OFF) cmake_dependent_option(OQS_ENABLE_KEM_bike_l3 "" ON "OQS_ENABLE_KEM_BIKE" OFF) cmake_dependent_option(OQS_ENABLE_KEM_bike_l5 "" ON "OQS_ENABLE_KEM_BIKE" OFF) +# SDitH is not supported on Windows: its reference code uses __uint128_t and GCC/Clang function +# attributes, neither of which MSVC provides. +# SDitH is also not supported on S390X or PPC64 (big endian): the code reinterprets uint64_t and +# __uint128_t words as byte strings in several places (e.g. the AES-CTR domain separation in +# sdith_prng_private.h and the proof-of-work counter in the signature), so it is little endian only. +# This does not conflict with the later `option(OQS_ENABLE_SIG_SDITH ...)`, +# since `option()` does nothing if the variable is already set as a normal or +# cache variable: https://cmake.org/cmake/help/latest/command/option.html +cmake_dependent_option(OQS_ENABLE_SIG_SDITH "Enable sdith algorithm family" ON "NOT WIN32; NOT ARCH_S390X; NOT ARCH_PPC64" OFF) +# SDitH doesn't work on any 32-bit platform: __uint128_t requires 128-bit int support +if(CMAKE_SIZEOF_VOID_P MATCHES "4") +set(OQS_ENABLE_SIG_SDITH OFF) +endif() + option(OQS_ENABLE_KEM_FRODOKEM "Enable Frodo algorithm family" ON) cmake_dependent_option(OQS_ENABLE_KEM_frodokem_640_aes "" ON "OQS_ENABLE_KEM_FRODOKEM" OFF) cmake_dependent_option(OQS_ENABLE_KEM_frodokem_640_shake "" ON "OQS_ENABLE_KEM_FRODOKEM" OFF) @@ -299,6 +313,20 @@ cmake_dependent_option(OQS_ENABLE_SIG_mqom_mqom3_cat5_gf16_short_ct "" ON "OQS_E cmake_dependent_option(OQS_ENABLE_SIG_mqom_mqom3_cat5_gf16_short_ot "" ON "OQS_ENABLE_SIG_MQOM" OFF) cmake_dependent_option(OQS_ENABLE_SIG_mqom_mqom3_cat5_gf2_shorter_ct "" ON "OQS_ENABLE_SIG_MQOM" OFF) cmake_dependent_option(OQS_ENABLE_SIG_mqom_mqom3_cat5_gf2_shorter_ot "" ON "OQS_ENABLE_SIG_MQOM" OFF) + +option(OQS_ENABLE_SIG_SDITH "Enable sdith algorithm family" ON) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_short "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_fast "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_short "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_fast "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_short "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_fast "" ON "OQS_ENABLE_SIG_SDITH" OFF) +cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow "" ON "OQS_ENABLE_SIG_SDITH" OFF) ##### OQS_COPY_FROM_UPSTREAM_FRAGMENT_ADD_ENABLE_BY_ALG_END ##### OQS_COPY_FROM_SLH_DSA_FRAGMENT_ADD_ENABLE_BY_ALG_START option(OQS_ENABLE_SIG_SLH_DSA "Enable slh_dsa algorithm family" ON) @@ -1786,6 +1814,79 @@ if(OQS_DIST_ARM64_V8_BUILD OR (OQS_USE_ARM_NEON_INSTRUCTIONS AND OQS_USE_ARM_NEO endif() endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2 "" ON "OQS_ENABLE_SIG_sdith_l1_gf2_short" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2 "" ON "OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2 "" ON "OQS_ENABLE_SIG_sdith_l1_gf2_fast" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2 "" ON "OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2 "" ON "OQS_ENABLE_SIG_sdith_l3_gf2_short" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2 "" ON "OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2 "" ON "OQS_ENABLE_SIG_sdith_l3_gf2_fast" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2 "" ON "OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2 "" ON "OQS_ENABLE_SIG_sdith_l5_gf2_short" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2 "" ON "OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2 "" ON "OQS_ENABLE_SIG_sdith_l5_gf2_fast" OFF) +endif() +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OQS_DIST_X86_64_BUILD OR (OQS_USE_AVX2_INSTRUCTIONS AND OQS_USE_AVX_INSTRUCTIONS AND OQS_USE_AES_INSTRUCTIONS AND OQS_USE_PCLMULQDQ_INSTRUCTIONS)) + cmake_dependent_option(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2 "" ON "OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow" OFF) +endif() +endif() + ##### OQS_COPY_FROM_UPSTREAM_FRAGMENT_ADD_ENABLE_BY_ALG_CONDITIONAL_END ##### OQS_COPY_FROM_LIBJADE_FRAGMENT_ADD_ENABLE_BY_ALG_CONDITIONAL_START diff --git a/ALGORITHMS.md b/ALGORITHMS.md index 3d34a1da0e..11e2379c5c 100644 --- a/ALGORITHMS.md +++ b/ALGORITHMS.md @@ -39,17 +39,18 @@ The **OQS tier** column records OQS's own support commitment for each algorithm. ## Signature schemes -| Algorithm family | Standardization | Primary implementation | Upstream maintenance | OQS tier | NIST levels | Constant-time | Formally verified | Optimization targets | -|:-------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------|:-------------------|:--------------|:----------------|:--------------------|:----------------------------------------------| -| CROSS | Under [NIST](https://www.cross-crypto.com/CROSS_Specification_v2.2.pdf) consideration | [`CROSS-signature/CROSS-lib-oqs@ce9933c`](https://github.com/CROSS-signature/CROSS-lib-oqs/commit/ce9933c7023a7aace4ac05b779995334a9996e6a) | [Actively maintained](https://github.com/CROSS-signature/CROSS-lib-oqs/blob/main/docs/oqs-statement.txt) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, x86_64 (avx2) | -| Falcon | Selected by [NIST](https://csrc.nist.gov/CSRC/media/Projects/post-quantum-cryptography/documents/round-3/submissions/Falcon-Round3.zip) for upcoming standardization | [`PQClean/PQClean@1eacfda`](https://github.com/PQClean/PQClean/commit/1eacfdafc15ddc5d5759d0b85b4cef26627df181) | TBD | Tier 3 (Community) | 1, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | -| MAYO | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`PQCMayo/MAYO-C@74de637`](https://github.com/PQCMayo/MAYO-C/commit/74de637a7c4a7f9fafa888183bc05f5cf920cd2d) | [Actively maintained](https://github.com/PQCMayo/MAYO-C) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | -| ML-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/204/final) | [`pq-code-package/mldsa-native@834a90d`](https://github.com/pq-code-package/mldsa-native/commit/834a90d5e846ffa1e1611bd24e160bb2e9b86d35) | [Actively maintained](https://github.com/pq-code-package/mldsa-native) | Tier 2 (Supported) | 2, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2+bmi2+popcnt) | -| MQOM | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`mqom/mqom-v3@df26239`](https://github.com/mqom/mqom-v3/commit/df26239dd22f194371003f403ec1a9920772b769) | [Actively maintained](https://github.com/mqom/mqom-v3/blob/main/integration/liboqs/SUPPORT.md) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8 (sha3), x86_64 (aes+avx2) | -| QR-UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`0rlych1kk4/round3@df619f4`](https://github.com/0rlych1kk4/round3/commit/df619f46a6c937c1b14907a933f74ae7d82a202d) | TBD | Tier 3 (Community) | 1, 3, 5 | — | — | portable, x86_64 (aes+avx2+bmi2) | -| SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@a0fc1ff`](https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88) | Best effort | Tier 3 (Community) | 1, 3, 5 | — | — | portable | -| SNOVA | Under [NIST](https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-3/spec-files/snova-spec-round3-web.pdf) consideration | [`PQCLAB-SNOVA/S@9b29c1e`](https://github.com/PQCLAB-SNOVA/S/commit/9b29c1e332cbd85757c8d6362a57b9a8c8298a38) | Best effort | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | -| UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`pqov/pqov@fac2ec1`](https://github.com/pqov/pqov/commit/fac2ec1fe6d8ea508eab4b98eb5341e1eed930a4) | Best effort | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | +| Algorithm family | Standardization | Primary implementation | Upstream maintenance | OQS tier | NIST levels | Constant-time | Formally verified | Optimization targets | +|:-------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------|:-------------------|:--------------|:----------------|:--------------------|:------------------------------------------------------| +| CROSS | Under [NIST](https://www.cross-crypto.com/CROSS_Specification_v2.2.pdf) consideration | [`CROSS-signature/CROSS-lib-oqs@ce9933c`](https://github.com/CROSS-signature/CROSS-lib-oqs/commit/ce9933c7023a7aace4ac05b779995334a9996e6a) | [Actively maintained](https://github.com/CROSS-signature/CROSS-lib-oqs/blob/main/docs/oqs-statement.txt) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, x86_64 (avx2) | +| Falcon | Selected by [NIST](https://csrc.nist.gov/CSRC/media/Projects/post-quantum-cryptography/documents/round-3/submissions/Falcon-Round3.zip) for upcoming standardization | [`PQClean/PQClean@1eacfda`](https://github.com/PQClean/PQClean/commit/1eacfdafc15ddc5d5759d0b85b4cef26627df181) | TBD | Tier 3 (Community) | 1, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | +| MAYO | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`PQCMayo/MAYO-C@74de637`](https://github.com/PQCMayo/MAYO-C/commit/74de637a7c4a7f9fafa888183bc05f5cf920cd2d) | [Actively maintained](https://github.com/PQCMayo/MAYO-C) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | +| ML-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/204/final) | [`pq-code-package/mldsa-native@834a90d`](https://github.com/pq-code-package/mldsa-native/commit/834a90d5e846ffa1e1611bd24e160bb2e9b86d35) | [Actively maintained](https://github.com/pq-code-package/mldsa-native) | Tier 2 (Supported) | 2, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2+bmi2+popcnt) | +| MQOM | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`mqom/mqom-v3@df26239`](https://github.com/mqom/mqom-v3/commit/df26239dd22f194371003f403ec1a9920772b769) | [Actively maintained](https://github.com/mqom/mqom-v3/blob/main/integration/liboqs/SUPPORT.md) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8 (sha3), x86_64 (aes+avx2) | +| QR-UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`0rlych1kk4/round3@df619f4`](https://github.com/0rlych1kk4/round3/commit/df619f46a6c937c1b14907a933f74ae7d82a202d) | TBD | Tier 3 (Community) | 1, 3, 5 | — | — | portable, x86_64 (aes+avx2+bmi2) | +| SDitH | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`sdith/sdith@ce7adf0`](https://github.com/sdith/sdith/commit/ce7adf06476674d4ff990f378f83f9981cd6745b) | TBD | Tier 3 (Community) | 1, 3, 5 | — | — | 64-bit little-endian, x86_64 (aes+avx+avx2+pclmulqdq) | +| SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@a0fc1ff`](https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88) | Best effort | Tier 3 (Community) | 1, 3, 5 | — | — | portable | +| SNOVA | Under [NIST](https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-3/spec-files/snova-spec-round3-web.pdf) consideration | [`PQCLAB-SNOVA/S@9b29c1e`](https://github.com/PQCLAB-SNOVA/S/commit/9b29c1e332cbd85757c8d6362a57b9a8c8298a38) | Best effort | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | +| UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`pqov/pqov@fac2ec1`](https://github.com/pqov/pqov/commit/fac2ec1fe6d8ea508eab4b98eb5341e1eed930a4) | Best effort | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) | ## Stateful signature schemes diff --git a/CMakeLists.txt b/CMakeLists.txt index 0357cba896..8203d77765 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -296,6 +296,9 @@ endif() if(OQS_ENABLE_SIG_MQOM) set(PUBLIC_HEADERS ${PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/src/sig/mqom/sig_mqom.h) endif() +if(OQS_ENABLE_SIG_SDITH) + set(PUBLIC_HEADERS ${PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/src/sig/sdith/sig_sdith.h) +endif() ##### OQS_COPY_FROM_UPSTREAM_FRAGMENT_INCLUDE_HEADERS_END if(OQS_ENABLE_SIG_SLH_DSA) set(PUBLIC_HEADERS ${PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/src/sig/slh_dsa/sig_slh_dsa.h) diff --git a/README.md b/README.md index e02e7c2786..1998693d66 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Names of algorithms standardized by NIST — [`ML-KEM`](https://csrc.nist.gov/pu | ML-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/204/final) | [`pq-code-package/mldsa-native@834a90d`](https://github.com/pq-code-package/mldsa-native/commit/834a90d5e846ffa1e1611bd24e160bb2e9b86d35) | [Actively maintained](https://github.com/pq-code-package/mldsa-native) | Tier 2 (Supported) | | MQOM | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`mqom/mqom-v3@df26239`](https://github.com/mqom/mqom-v3/commit/df26239dd22f194371003f403ec1a9920772b769) | [Actively maintained](https://github.com/mqom/mqom-v3/blob/main/integration/liboqs/SUPPORT.md) | Tier 3 (Community) | | QR-UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`0rlych1kk4/round3@df619f4`](https://github.com/0rlych1kk4/round3/commit/df619f46a6c937c1b14907a933f74ae7d82a202d) | TBD | Tier 3 (Community) | +| SDitH | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`sdith/sdith@ce7adf0`](https://github.com/sdith/sdith/commit/ce7adf06476674d4ff990f378f83f9981cd6745b) | TBD | Tier 3 (Community) | | SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@a0fc1ff`](https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88) | Best effort | Tier 3 (Community) | | SNOVA | Under [NIST](https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-3/spec-files/snova-spec-round3-web.pdf) consideration | [`PQCLAB-SNOVA/S@9b29c1e`](https://github.com/PQCLAB-SNOVA/S/commit/9b29c1e332cbd85757c8d6362a57b9a8c8298a38) | Best effort | Tier 3 (Community) | | UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`pqov/pqov@fac2ec1`](https://github.com/pqov/pqov/commit/fac2ec1fe6d8ea508eab4b98eb5341e1eed930a4) | Best effort | Tier 3 (Community) | diff --git a/docs/algorithms/sig/sdith.md b/docs/algorithms/sig/sdith.md new file mode 100644 index 0000000000..e9aaa48037 --- /dev/null +++ b/docs/algorithms/sig/sdith.md @@ -0,0 +1,151 @@ +# SDitH + +- **Algorithm type**: Digital signature scheme. +- **Main cryptographic assumption**: Hardness of syndrom decoding problem for random linear codes on a finite field.. +- **Principal submitters**: Carlos Aguilar Melchor, Slim Bettaieb, Loïc Bidoux, Thibauld Feneuil, Philippe Gaborit, Nicolas Gama, Shay Gueron, James Howe, Andreas Hülsing, David Joseph, Antoine Joux, Mukul Kulkarni, Edoardo Persichetti, Tovohery H. Randrianarisoa, Matthieu Rivain, Dongze Yue. +- **Authors' website**: https://sdith.org/ +- **Specification version**: NIST Round 3. +- **Primary Source**: + - **Source**: https://github.com/sdith/sdith/commit/ce7adf06476674d4ff990f378f83f9981cd6745b with copy_from_upstream patches + - **Implementation license (SPDX-Identifier)**: Apache-2.0 +- **Optimized Implementation sources**: + - **avx2**: + - **Source**: https://github.com/sdith/sdith/commit/ce7adf06476674d4ff990f378f83f9981cd6745b with copy_from_upstream patches + - **Implementation license (SPDX-Identifier)**: Apache-2.0 + + +## Support + +- **Upstream maintenance**: TBD +- **OQS support tier**: Tier 3 + +## Parameter set summary + +| Parameter set | Parameter set alias | Security model | Claimed NIST Level | Public key size (bytes) | Secret key size (bytes) | Signature size (bytes) | +|:-----------------------------:|:----------------------|:-----------------|---------------------:|--------------------------:|--------------------------:|-------------------------:| +| SDitH3-L1-gf2-short | NA | EUF-CMA | 1 | 70 | 147 | 3721 | +| SDitH3-L1-gf2-short-cipherpow | NA | EUF-CMA | 1 | 70 | 147 | 3721 | +| SDitH3-L1-gf2-fast | NA | EUF-CMA | 1 | 70 | 147 | 4914 | +| SDitH3-L1-gf2-fast-cipherpow | NA | EUF-CMA | 1 | 70 | 147 | 4643 | +| SDitH3-L3-gf2-short | NA | EUF-CMA | 3 | 98 | 208 | 8484 | +| SDitH3-L3-gf2-short-cipherpow | NA | EUF-CMA | 3 | 98 | 208 | 8484 | +| SDitH3-L3-gf2-fast | NA | EUF-CMA | 3 | 98 | 208 | 10852 | +| SDitH3-L3-gf2-fast-cipherpow | NA | EUF-CMA | 3 | 98 | 208 | 10452 | +| SDitH3-L5-gf2-short | NA | EUF-CMA | 5 | 132 | 275 | 15147 | +| SDitH3-L5-gf2-short-cipherpow | NA | EUF-CMA | 5 | 132 | 275 | 15147 | +| SDitH3-L5-gf2-fast | NA | EUF-CMA | 5 | 132 | 275 | 19144 | +| SDitH3-L5-gf2-fast-cipherpow | NA | EUF-CMA | 5 | 132 | 275 | 19144 | + +## SDitH3-L1-gf2-short implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage?‡ | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:----------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + + ‡For an explanation of what this denotes, consult the [Explanation of Terms](#explanation-of-terms) section at the end of this file. + +## SDitH3-L1-gf2-short-cipherpow implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L1-gf2-fast implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L1-gf2-fast-cipherpow implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L3-gf2-short implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L3-gf2-short-cipherpow implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L3-gf2-fast implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L3-gf2-fast-cipherpow implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L5-gf2-short implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L5-gf2-short-cipherpow implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L5-gf2-fast implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## SDitH3-L5-gf2-fast-cipherpow implementation characteristics + +| Implementation source | Identifier in upstream | Supported architecture(s) | Supported operating system(s) | CPU extension(s) used | No branching-on-secrets claimed? | No branching-on-secrets checked by valgrind? | Large stack usage? | +|:---------------------------------:|:-------------------------|:----------------------------|:--------------------------------|:------------------------|:-----------------------------------|:-----------------------------------------------|:---------------------| +| [Primary Source](#primary-source) | ref | 64-bit little-endian | Linux,Darwin | None | False | False | False | +| [Primary Source](#primary-source) | avx2 | x86\_64 | Linux | AES,AVX,AVX2,PCLMULQDQ | True | False | False | + +Are implementations chosen based on runtime CPU feature detection? **Yes**. + +## Explanation of Terms + +- **Large Stack Usage**: Implementations identified as having such may cause failures when running in threads or in constrained environments. \ No newline at end of file diff --git a/docs/algorithms/sig/sdith.yml b/docs/algorithms/sig/sdith.yml new file mode 100644 index 0000000000..5991944e74 --- /dev/null +++ b/docs/algorithms/sig/sdith.yml @@ -0,0 +1,514 @@ +name: SDitH +type: signature +principal-submitters: +- Carlos Aguilar Melchor +- Slim Bettaieb +- Loïc Bidoux +- Thibauld Feneuil +- Philippe Gaborit +- Nicolas Gama +- Shay Gueron +- James Howe +- Andreas Hülsing +- David Joseph +- Antoine Joux +- Mukul Kulkarni +- Edoardo Persichetti +- Tovohery H. Randrianarisoa +- Matthieu Rivain +- Dongze Yue +crypto-assumption: Hardness of syndrom decoding problem for random linear codes on + a finite field. +website: https://sdith.org/ +nist-round: 3 +standardization-status: Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration +spec-version: NIST Round 3 +primary-upstream: + source: https://github.com/sdith/sdith/commit/ce7adf06476674d4ff990f378f83f9981cd6745b + with copy_from_upstream patches + spdx-license-identifier: Apache-2.0 +parameter-sets: +- name: SDitH3-L1-gf2-short + oqs_alg: OQS_SIG_sdith_sdith3_l1_gf2_short + claimed-nist-level: 1 + claimed-security: EUF-CMA + length-public-key: 70 + length-secret-key: 147 + length-signature: 3721 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L1-gf2-short-cipherpow + oqs_alg: OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow + claimed-nist-level: 1 + claimed-security: EUF-CMA + length-public-key: 70 + length-secret-key: 147 + length-signature: 3721 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L1-gf2-fast + oqs_alg: OQS_SIG_sdith_sdith3_l1_gf2_fast + claimed-nist-level: 1 + claimed-security: EUF-CMA + length-public-key: 70 + length-secret-key: 147 + length-signature: 4914 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L1-gf2-fast-cipherpow + oqs_alg: OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow + claimed-nist-level: 1 + claimed-security: EUF-CMA + length-public-key: 70 + length-secret-key: 147 + length-signature: 4643 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L3-gf2-short + oqs_alg: OQS_SIG_sdith_sdith3_l3_gf2_short + claimed-nist-level: 3 + claimed-security: EUF-CMA + length-public-key: 98 + length-secret-key: 208 + length-signature: 8484 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L3-gf2-short-cipherpow + oqs_alg: OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow + claimed-nist-level: 3 + claimed-security: EUF-CMA + length-public-key: 98 + length-secret-key: 208 + length-signature: 8484 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L3-gf2-fast + oqs_alg: OQS_SIG_sdith_sdith3_l3_gf2_fast + claimed-nist-level: 3 + claimed-security: EUF-CMA + length-public-key: 98 + length-secret-key: 208 + length-signature: 10852 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L3-gf2-fast-cipherpow + oqs_alg: OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow + claimed-nist-level: 3 + claimed-security: EUF-CMA + length-public-key: 98 + length-secret-key: 208 + length-signature: 10452 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L5-gf2-short + oqs_alg: OQS_SIG_sdith_sdith3_l5_gf2_short + claimed-nist-level: 5 + claimed-security: EUF-CMA + length-public-key: 132 + length-secret-key: 275 + length-signature: 15147 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L5-gf2-short-cipherpow + oqs_alg: OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow + claimed-nist-level: 5 + claimed-security: EUF-CMA + length-public-key: 132 + length-secret-key: 275 + length-signature: 15147 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L5-gf2-fast + oqs_alg: OQS_SIG_sdith_sdith3_l5_gf2_fast + claimed-nist-level: 5 + claimed-security: EUF-CMA + length-public-key: 132 + length-secret-key: 275 + length-signature: 19144 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +- name: SDitH3-L5-gf2-fast-cipherpow + oqs_alg: OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow + claimed-nist-level: 5 + claimed-security: EUF-CMA + length-public-key: 132 + length-secret-key: 275 + length-signature: 19144 + implementations-switch-on-runtime-cpu-features: true + implementations: + - upstream: primary-upstream + upstream-id: ref + supported-platforms: + - architecture: 64-bit little-endian + operating_systems: + - Linux + - Darwin + common-crypto: + - SHA3: liboqs + - AES: liboqs + no-secret-dependent-branching-claimed: false + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false + default: true + - upstream: primary-upstream + upstream-id: avx2 + supported-platforms: + - architecture: x86_64 + operating_systems: + - Linux + required_flags: + - aes + - avx + - avx2 + - pclmulqdq + common-crypto: + - SHA3: liboqs + - AES: primary-upstream + no-secret-dependent-branching-claimed: true + no-secret-dependent-branching-checked-by-valgrind: false + large-stack-usage: false +upstream-maintenance: TBD +upstream-statement-url: null +oqs-support-tier: 3 +auxiliary-submitters: [] diff --git a/docs/cbom.json b/docs/cbom.json index 7238c09962..f33d24f740 100644 --- a/docs/cbom.json +++ b/docs/cbom.json @@ -2,23 +2,23 @@ "$schema": "https://raw.githubusercontent.com/CycloneDX/specification/1.6/schema/bom-1.6.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.6", - "serialNumber": "urn:uuid:8aef1183-a364-451a-be1d-f35fc5b2cef3", + "serialNumber": "urn:uuid:1902a28f-41dc-40cb-9f24-b45e8980ad1c", "version": 1, "metadata": { - "timestamp": "2026-09-22T16:48:43.819494+00:00", + "timestamp": "2026-10-21T19:46:14.525685+00:00", "component": { "type": "library", - "bom-ref": "pkg:github/open-quantum-safe/liboqs@078c4d3c73b982de8d7a1665d68073bfdaf48147", + "bom-ref": "pkg:github/open-quantum-safe/liboqs@eb61e0df7fb9eb34d0a1d54f16b2c5a5085c467c", "name": "liboqs", - "version": "078c4d3c73b982de8d7a1665d68073bfdaf48147" + "version": "eb61e0df7fb9eb34d0a1d54f16b2c5a5085c467c" } }, "components": [ { "type": "library", - "bom-ref": "pkg:github/open-quantum-safe/liboqs@078c4d3c73b982de8d7a1665d68073bfdaf48147", + "bom-ref": "pkg:github/open-quantum-safe/liboqs@eb61e0df7fb9eb34d0a1d54f16b2c5a5085c467c", "name": "liboqs", - "version": "078c4d3c73b982de8d7a1665d68073bfdaf48147" + "version": "eb61e0df7fb9eb34d0a1d54f16b2c5a5085c467c" }, { "type": "cryptographic-asset", @@ -5100,6 +5100,246 @@ } } }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L1-gf2-short:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L1-gf2-short", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 1, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L1-gf2-short-cipherpow:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L1-gf2-short-cipherpow", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 1, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L1-gf2-fast:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L1-gf2-fast", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 1, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L1-gf2-fast-cipherpow:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L1-gf2-fast-cipherpow", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 1, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L3-gf2-short:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L3-gf2-short", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 3, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L3-gf2-short-cipherpow:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L3-gf2-short-cipherpow", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 3, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L3-gf2-fast:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L3-gf2-fast", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 3, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L3-gf2-fast-cipherpow:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L3-gf2-fast-cipherpow", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 3, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L5-gf2-short:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L5-gf2-short", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 5, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L5-gf2-short-cipherpow:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L5-gf2-short-cipherpow", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 5, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L5-gf2-fast:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L5-gf2-fast", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 5, + "implementationPlatform": "x86_64" + } + } + }, + { + "type": "cryptographic-asset", + "bom-ref": "alg:SDitH3-L5-gf2-fast-cipherpow:avx2:x86_64", + "name": "SDitH", + "cryptoProperties": { + "assetType": "algorithm", + "algorithmProperties": { + "parameterSetIdentifier": "SDitH3-L5-gf2-fast-cipherpow", + "primitive": "signature", + "executionEnvironment": "software-plain-ram", + "cryptoFunctions": [ + "keygen", + "sign", + "verify" + ], + "nistQuantumSecurityLevel": 5, + "implementationPlatform": "x86_64" + } + } + }, { "type": "cryptographic-asset", "bom-ref": "alg:SLH_DSA_PURE_SHA2_128S:slhdsa-c:generic", @@ -10407,7 +10647,7 @@ ], "dependencies": [ { - "ref": "pkg:github/open-quantum-safe/liboqs@078c4d3c73b982de8d7a1665d68073bfdaf48147", + "ref": "pkg:github/open-quantum-safe/liboqs@eb61e0df7fb9eb34d0a1d54f16b2c5a5085c467c", "provides": [ "alg:BIKE-L1:master:x86_64", "alg:BIKE-L3:master:x86_64", @@ -10663,6 +10903,18 @@ "alg:QRUOV-5q31L3-shake:avx2:x86_64", "alg:QRUOV-5q7L10-aes:avx2:x86_64", "alg:QRUOV-5q7L10-shake:avx2:x86_64", + "alg:SDitH3-L1-gf2-short:avx2:x86_64", + "alg:SDitH3-L1-gf2-short-cipherpow:avx2:x86_64", + "alg:SDitH3-L1-gf2-fast:avx2:x86_64", + "alg:SDitH3-L1-gf2-fast-cipherpow:avx2:x86_64", + "alg:SDitH3-L3-gf2-short:avx2:x86_64", + "alg:SDitH3-L3-gf2-short-cipherpow:avx2:x86_64", + "alg:SDitH3-L3-gf2-fast:avx2:x86_64", + "alg:SDitH3-L3-gf2-fast-cipherpow:avx2:x86_64", + "alg:SDitH3-L5-gf2-short:avx2:x86_64", + "alg:SDitH3-L5-gf2-short-cipherpow:avx2:x86_64", + "alg:SDitH3-L5-gf2-fast:avx2:x86_64", + "alg:SDitH3-L5-gf2-fast-cipherpow:avx2:x86_64", "alg:SLH_DSA_PURE_SHA2_128S:slhdsa-c:generic", "alg:SLH_DSA_PURE_SHA2_128F:slhdsa-c:generic", "alg:SLH_DSA_PURE_SHA2_192S:slhdsa-c:generic", @@ -12507,6 +12759,90 @@ "alg:sha3" ] }, + { + "ref": "alg:SDitH3-L1-gf2-short:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L1-gf2-short-cipherpow:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L1-gf2-fast:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L1-gf2-fast-cipherpow:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L3-gf2-short:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L3-gf2-short-cipherpow:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L3-gf2-fast:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L3-gf2-fast-cipherpow:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L5-gf2-short:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L5-gf2-short-cipherpow:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L5-gf2-fast:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, + { + "ref": "alg:SDitH3-L5-gf2-fast-cipherpow:avx2:x86_64", + "dependsOn": [ + "alg:sha3", + "alg:aes" + ] + }, { "ref": "alg:SNOVA_I_K:opt:generic", "dependsOn": [ diff --git a/scripts/copy_from_upstream/copy_from_upstream.yml b/scripts/copy_from_upstream/copy_from_upstream.yml index 2b6ae6e43f..7322783f62 100644 --- a/scripts/copy_from_upstream/copy_from_upstream.yml +++ b/scripts/copy_from_upstream/copy_from_upstream.yml @@ -29,7 +29,7 @@ upstreams: kem_scheme_path: 'crypto_kem/{pqclean_scheme}' sig_scheme_path: 'crypto_sign/{pqclean_scheme}' patches: [classic_mceliece_memset.patch] - ignore: pqclean_kyber512_aarch64, pqclean_kyber1024_aarch64, pqclean_kyber768_aarch64 + ignore: pqclean_kyber512_aarch64, pqclean_kyber1024_aarch64, pqclean_kyber768_aarch64 - name: pqcrystals-kyber git_url: https://github.com/pq-crystals/kyber.git @@ -117,6 +117,14 @@ upstreams: sig_scheme_path: '.' sig_meta_path: 'integration/liboqs/META_{pretty_name_full}.yml' common_meta_path: 'integration/liboqs/META_Common.yml' + - name: sdith + git_url: https://github.com/sdith/sdith.git + git_branch: main + git_commit: ce7adf06476674d4ff990f378f83f9981cd6745b + sig_scheme_path: '.' + sig_meta_path: 'integration/liboqs/schemes/{pretty_name_full}/META_{pretty_name_full}.yml' + common_meta_path: 'integration/liboqs/META_Common.yml' + patches: [sdith-liboqs-integration.patch] kems: - name: classic_mceliece @@ -812,3 +820,68 @@ sigs: pqclean_scheme: mqom3_cat5_gf2_shorter_ot pretty_name_full: mqom3_cat5_gf2_shorter_ot signed_msg_order: msg_then_sig + - + name: sdith + default_implementation: ref + upstream_location: sdith + schemes: + - + scheme: "l1_gf2_short" + pqclean_scheme: l1_gf2_short + pretty_name_full: SDitH3-L1-gf2-short + signed_msg_order: msg_then_sig + - + scheme: "l1_gf2_short_cipherpow" + pqclean_scheme: l1_gf2_short_cipherpow + pretty_name_full: SDitH3-L1-gf2-short-cipherpow + signed_msg_order: msg_then_sig + - + scheme: "l1_gf2_fast" + pqclean_scheme: l1_gf2_fast + pretty_name_full: SDitH3-L1-gf2-fast + signed_msg_order: msg_then_sig + - + scheme: "l1_gf2_fast_cipherpow" + pqclean_scheme: l1_gf2_fast_cipherpow + pretty_name_full: SDitH3-L1-gf2-fast-cipherpow + signed_msg_order: msg_then_sig + - + scheme: "l3_gf2_short" + pqclean_scheme: l3_gf2_short + pretty_name_full: SDitH3-L3-gf2-short + signed_msg_order: msg_then_sig + - + scheme: "l3_gf2_short_cipherpow" + pqclean_scheme: l3_gf2_short_cipherpow + pretty_name_full: SDitH3-L3-gf2-short-cipherpow + signed_msg_order: msg_then_sig + - + scheme: "l3_gf2_fast" + pqclean_scheme: l3_gf2_fast + pretty_name_full: SDitH3-L3-gf2-fast + signed_msg_order: msg_then_sig + - + scheme: "l3_gf2_fast_cipherpow" + pqclean_scheme: l3_gf2_fast_cipherpow + pretty_name_full: SDitH3-L3-gf2-fast-cipherpow + signed_msg_order: msg_then_sig + - + scheme: "l5_gf2_short" + pqclean_scheme: l5_gf2_short + pretty_name_full: SDitH3-L5-gf2-short + signed_msg_order: msg_then_sig + - + scheme: "l5_gf2_short_cipherpow" + pqclean_scheme: l5_gf2_short_cipherpow + pretty_name_full: SDitH3-L5-gf2-short-cipherpow + signed_msg_order: msg_then_sig + - + scheme: "l5_gf2_fast" + pqclean_scheme: l5_gf2_fast + pretty_name_full: SDitH3-L5-gf2-fast + signed_msg_order: msg_then_sig + - + scheme: "l5_gf2_fast_cipherpow" + pqclean_scheme: l5_gf2_fast_cipherpow + pretty_name_full: SDitH3-L5-gf2-fast-cipherpow + signed_msg_order: msg_then_sig diff --git a/scripts/copy_from_upstream/patches/sdith-liboqs-integration.patch b/scripts/copy_from_upstream/patches/sdith-liboqs-integration.patch new file mode 100644 index 0000000000..441a496b48 --- /dev/null +++ b/scripts/copy_from_upstream/patches/sdith-liboqs-integration.patch @@ -0,0 +1,4538 @@ +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..378eac2 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1 @@ ++build +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 3e2d667..2517560 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -75,6 +75,9 @@ set( + CAT5_FAST_CIPHERPOW + ) + ++# Common includes for src and lib ++include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) ++ + add_subdirectory(lib/sha3) + add_subdirectory(lib/aes) + +diff --git a/include/sdith_inline.h b/include/sdith_inline.h +new file mode 100644 +index 0000000..b55b41d +--- /dev/null ++++ b/include/sdith_inline.h +@@ -0,0 +1,21 @@ ++#ifndef sdith_inline_H ++#define sdith_inline_H ++ ++// Force inlining of a file-local helper. ++// Designed to be behaviourally consistent across different compilers. ++#if defined(_MSC_VER) ++#define SDITH_ALWAYS_INLINE static __forceinline ++#elif defined(__GNUC__) || defined(__clang__) ++#define SDITH_ALWAYS_INLINE static inline __attribute__((__always_inline__)) ++#else ++#define SDITH_ALWAYS_INLINE static inline ++#endif ++ ++// Mark a variable as possibly unused, to suppress compiler warnings. ++#if defined(__GNUC__) || defined(__clang__) ++#define SDITH_MAYBE_UNUSED __attribute__((__unused__)) ++#else ++#define SDITH_MAYBE_UNUSED ++#endif ++ ++#endif // sdith_inline_H +diff --git a/integration/liboqs/META_Common.yml b/integration/liboqs/META_Common.yml +new file mode 100644 +index 0000000..c96b6fb +--- /dev/null ++++ b/integration/liboqs/META_Common.yml +@@ -0,0 +1,141 @@ ++commons: ++ # The shared code, built for the ref variants. ++ - name: sdith_common ++ folder_name: . ++ sources: >- #aes128_ctrle_special_ref.c is excluded and liboqs AES is used instead ++ LICENSE.txt ++ NOTICE ++ integration/liboqs/fips202_glue.h ++ integration/liboqs/fips202x4_glue.h ++ integration/liboqs/aes_glue.c ++ integration/liboqs/sdith_namespace.h ++ include/sdith_inline.h ++ lib/aes/aes_ansi_ref.h ++ lib/aes/aes128_ctrle.h ++ lib/aes/aes128_ctrle_special_ref.c ++ lib/aes/rijndael256.c ++ lib/aes/rijndael256.h ++ lib/aes/rijndael256_ctrle.h ++ lib/aes/rijndael256_ctrle_special_ref.c ++ src/commons.c ++ src/commons.h ++ src/ct_utils.c ++ src/gf128.c ++ src/gf192.c ++ src/gf256.c ++ src/ggm.c ++ src/ggm.h ++ src/matrix_transpose_f2.c ++ src/matrix_vector_products_f2.c ++ src/piop_circuit.c ++ src/rsd.c ++ src/sdith_algebra.h ++ src/sdith_arithmetic.h ++ src/sdith_ct_utils.h ++ src/sdith_piop_circuits.h ++ src/sdith_prng.c ++ src/sdith_prng.h ++ src/sdith_prng_private.h ++ src/sdith_rsd.h ++ src/sdith_signature.c ++ src/sdith_signature.h ++ src/sdith_signature_parameters.c ++ src/sdith_vole_to_piop.h ++ src/vole_expansion.c ++ src/vole_generation.h ++ src/vole_parameters.c ++ src/vole_parameters.h ++ src/vole_private.h ++ src/vole_to_piop.c ++ include_only: false ++ compile_opts: >- ++ -DSDITH3_FOR_LIBOQS ++ -DNDEBUG ++ -DONLY_REF_IMPLEMENTATION ++ -DAPPLY_NAMESPACE=oqs_sig_private_sdith_ref_ ++ # A second copy of the shared code, built with the avx2 flags alongside the ++ # avx2 sources for the avx2 variants. The first block matches sdith_common. ++ - name: sdith_common_avx2 ++ folder_name: . ++ sources: >- # aes128_ctrle_special_avx2.c is intentionally included and isn't shimmed, since it offers improvements over liboqs AES ++ LICENSE.txt ++ NOTICE ++ integration/liboqs/fips202_glue.h ++ integration/liboqs/fips202x4_glue.h ++ integration/liboqs/aes_glue.c ++ integration/liboqs/sdith_namespace.h ++ include/sdith_inline.h ++ lib/aes/aes_ansi_ref.h ++ lib/aes/aes128_ctrle.h ++ lib/aes/aes128_ctrle_special_ref.c ++ lib/aes/rijndael256.c ++ lib/aes/rijndael256.h ++ lib/aes/rijndael256_ctrle.h ++ lib/aes/rijndael256_ctrle_special_ref.c ++ src/commons.c ++ src/commons.h ++ src/ct_utils.c ++ src/gf128.c ++ src/gf192.c ++ src/gf256.c ++ src/ggm.c ++ src/ggm.h ++ src/matrix_transpose_f2.c ++ src/matrix_vector_products_f2.c ++ src/piop_circuit.c ++ src/rsd.c ++ src/sdith_algebra.h ++ src/sdith_arithmetic.h ++ src/sdith_ct_utils.h ++ src/sdith_piop_circuits.h ++ src/sdith_prng.c ++ src/sdith_prng.h ++ src/sdith_prng_private.h ++ src/sdith_rsd.h ++ src/sdith_signature.c ++ src/sdith_signature.h ++ src/sdith_signature_parameters.c ++ src/sdith_vole_to_piop.h ++ src/vole_expansion.c ++ src/vole_generation.h ++ src/vole_parameters.c ++ src/vole_parameters.h ++ src/vole_private.h ++ src/vole_to_piop.c ++ lib/aes/rijndael256_avx.c ++ lib/aes/rijndael256_avx.h ++ lib/aes/aes128_ctrle_special_avx2.c ++ lib/aes/rijndael256_ctrle_special_avx2.c ++ src/ct_utils_avx2.c ++ src/gf128_avx2.c ++ src/gf192_avx2.c ++ src/gf256_avx2.c ++ src/matrix_vector_products_f2_avx2.c ++ src/sdith_prng_avx2.c ++ src/vole_parameters_avx2.c ++ include_only: false ++ compile_opts: >- ++ -DSDITH3_FOR_LIBOQS ++ -DNDEBUG ++ -DAPPLY_NAMESPACE=oqs_sig_private_sdith_avx2_ ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 SDitH builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ - Linux ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq ++ # Headers only. Each variant copies api.c and its params.h into its own folder, ++ # and this puts the shared headers api.c includes on that variant's include path. ++ - name: sdith_common_headers ++ folder_name: . ++ sources: >- ++ LICENSE.txt ++ NOTICE ++ integration/liboqs/sdith_namespace.h ++ src/commons.h ++ src/sdith_signature.h ++ include_only: true +diff --git a/integration/liboqs/README.md b/integration/liboqs/README.md +new file mode 100644 +index 0000000..23be7ec +--- /dev/null ++++ b/integration/liboqs/README.md +@@ -0,0 +1,81 @@ ++# liboqs integration ++ ++Metadata and glue code that let `liboqs`' `scripts/copy_from_upstream` pull SDitH3 ++into `src/sig/sdith/`. Nothing here is used by a standalone SDitH build. ++ ++The different files involves in the integration are: ++- `META_Common.yml`: the shared object libraries liboqs builds, and their sources ++- `schemes/{scheme}/META_{scheme}.yml`: one file per scheme variant specifying sizes, submitters, sources ++- `schemes/{scheme}/{impl}/params.h`: the sizes, parameter set and prefixes of one implementation ++- `api.c`, `api.h`: the liboqs wrapper around `sdith_sign` / `sdith_verify`. Each implementation ++ copies them into its own `src/sig/sdith/sdith_{scheme}_{impl}/` folder next to its `params.h`, so the entry ++ point for a given scheme can be read in one place ++- `aes_glue.h`, `fips202_glue.h`, `fips202x4_glue.h`: shim SDitH's AES and Keccak at liboqs' implementations where appropriate ++- `sdith_namespace.h`: generated symbol prefixes (see below) ++- `gen_namespace.sh`: regenerates `sdith_namespace.h` ++ ++## KAT checksums ++ ++`liboqs` runs the NIST KATs to verify correctness of the integration. ++Instead of comparing the results strictly, the SHA256 checksum of the output is compared instead. ++This is computed as the hash of the standard NIST output format. For example (truncated): ++``` ++count = 0 ++seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 ++mlen = 33 ++msg = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8 ++pk = 7C9935A0B... ++sk = 7C9935A... ++smlen = 4947 ++sm = D81C... ++``` ++The above output (with `count=0`) is the hash input for the `nistkat-sha256` checksum included in each scheme's `META_*.yml`. ++The `all` hash must be added to liboqs' `tests/KATs/sig/kats.json` by hand, and consists of the hash of all of the above outputs for `count`s 0 through 99, with each followed by a newline. ++ ++As of writing, sdith comes with their KAT outputs at `kat_r3//PQCsignKAT_*.rsp` (eg. `kat_r3/SDITH_CAT1_FAST/PQCsignKAT_147.rsp`) ++ ++Getting the checksum for a single test (`nistkat-sha256` in the `.yml`) requires hashing the first output block (ignoring the comment at the top of each `.rsp` file): ++```sh ++tail -n +3 kat_r3/SDITH_CAT1_FAST/PQCsignKAT_147.rsp | head -n 8 | sha256sum ++``` ++and getting the "all" checksum involves hashing the whole file (ignoring the comment and extra trailing newline) ++```sh ++tail -n +3 kat_r3/SDITH_CAT1_FAST/PQCsignKAT_147.rsp | head -n -1 | sha256sum ++``` ++ ++## Namespacing ++ ++`liboqs` compiles the common code into a set of global symbols ++that can be shared among each scheme. As a result, the global symbols within ++`sdith` need to be namespaced to meet liboqs' convention and avoid conflicts. ++ ++Instead of updating hundereds of symbols within the `sdith` source, a generated ++`sdith_namespace.h` header uses `# define` to prefix global defined symbols. ++ ++Regenerate it after adding, renaming, or removing any symbol in the shared ++sources: ++ ++```sh ++./integration/liboqs/gen_namespace.sh /path/to/liboqs/build ++# or, if $LIBOQS_BUILD_DIR is defined: ++# ./integration/liboqs/gen_namespace.sh $LIBOQS_BUILD_DIR ++``` ++ ++The directory is searched for the object files of the `sdith_common` targets ++under `src/sig/sdith/CMakeFiles/sdith_sdith_common*.dir/`. ++ ++`sdith_common_avx2` is only compiled on x86_64, so use an x86_64 build tree or ++the header will be missing the avx2 symbols. ++ ++Re-running over a build that already applied the header will not update it ++(avoids adding the prefix twice). ++ ++## Reference vs avx2 ++ ++`sdith_common` and `sdith_common_avx2` each compile their own copy of the shared ++sources, so the shared file list appears in both. The ref copy is built with ++`ONLY_REF_IMPLEMENTATION`, the avx2 copy with the avx2 flags and the avx2 sources. ++ ++The two copies carry different `APPLY_NAMESPACE` prefixes: `oqs_sig_private_sdith_ref_` and ++`oqs_sig_private_sdith_avx2_`. Each implementation's `params.h` sets the prefix of the copy it links against. ++`gen_namespace.sh` strips either prefix, so the single generated header serves both. +diff --git a/integration/liboqs/aes_glue.c b/integration/liboqs/aes_glue.c +new file mode 100644 +index 0000000..6b80b56 +--- /dev/null ++++ b/integration/liboqs/aes_glue.c +@@ -0,0 +1,48 @@ ++#include ++ ++#include "aes_ansi_ref.h" ++ ++#include ++#include ++ ++ ++EXPORT void aes128_set_key_ref(void* rk, const void* key128) { ++ // Allocates a schedule via liboqs and writes the pointer to the schedule into the rk buffer ++ void* schedule = NULL; ++ OQS_AES128_ECB_load_schedule(key128, &schedule); ++ memcpy(rk, &schedule, sizeof(void*)); ++} ++ ++EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk) { ++ // Interprets first sizeof(void *) bytes of rk as a schedule pointer for liboqs ctx ++ void* schedule = NULL; ++ memcpy(&schedule, rk, sizeof(void*)); ++ OQS_AES128_ECB_enc_sch(in_pt128, 16, schedule, out_ct128); ++} ++ ++EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes) { ++ // Marks every slot empty by zeroing its schedule pointer. ++ // No schedule is allocated here: `aes128_set_key_reuse_ref` does this in a later call ++ uint8_t* p = (uint8_t*) rk; ++ for (uint64_t i = 0; i < nslots; ++i) { ++ memset(p + i * slot_bytes, 0, sizeof(void*)); ++ } ++} ++ ++EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128) { ++ // The slot holds a schedule rather than round keys, so replacing the key means ++ // freeing any schedule already there and loading a new one in its place. ++ aes128_release_key(rk); ++ aes128_set_key_ref(rk, key128); ++} ++ ++ ++EXPORT void aes128_release_key(void* rk) { ++ // Interprets first sizeof(void *) bytes of rk as a schedule pointer for liboqs ctx ++ void* schedule = NULL; ++ memcpy(&schedule, rk, sizeof(void*)); ++ // An empty slot has nothing to free. ++ if (schedule == NULL) return; ++ OQS_AES128_free_schedule(schedule); ++ OQS_MEM_cleanse(rk, sizeof(void*)); ++} +diff --git a/integration/liboqs/api.c b/integration/liboqs/api.c +new file mode 100644 +index 0000000..64c3088 +--- /dev/null ++++ b/integration/liboqs/api.c +@@ -0,0 +1,92 @@ ++// The scheme's sizes, parameter set and symbol prefixes. liboqs copies ++// this file next to the params.h of each scheme and implementation. ++#include "params.h" ++ ++#include ++#include ++ ++#include ++#include ++ ++#include "sdith_signature.h" ++#include "api.h" ++ ++ ++OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { ++ if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || ++ CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || ++ CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) ++ return OQS_ERROR; ++ uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); ++ uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); ++ uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); ++ if (entropy == NULL) return OQS_ERROR; ++ uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); ++ if (tmp_space == NULL) { ++ OQS_MEM_insecure_free(entropy); ++ return OQS_ERROR; ++ } ++ ++ OQS_randombytes(entropy, entropy_bytes); ++ sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); ++ ++ // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. ++ OQS_MEM_secure_free(tmp_space, tmp_bytes); ++ OQS_MEM_secure_free(entropy, entropy_bytes); ++ return OQS_SUCCESS; ++} ++ ++OQS_STATUS crypto_sign_sign( ++ uint8_t *signature, ++ size_t *signature_len, ++ const uint8_t *message, ++ size_t message_len, ++ const uint8_t *secret_key) ++{ ++ // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space ++ // when repeatedly signing/verifying. Tracked in liboqs as: ++ // https://github.com/open-quantum-safe/liboqs/issues/2619 ++ uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); ++ uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); ++ uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); ++ if (entropy == NULL) return OQS_ERROR; ++ uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); ++ if (tmp_space == NULL) { ++ OQS_MEM_insecure_free(entropy); ++ return OQS_ERROR; ++ } ++ ++ OQS_randombytes(entropy, entropy_bytes); ++ sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); ++ *signature_len = CRYPTO_BYTES; ++ ++ // tmp_space and entropy hold secret signing state: wipe both. ++ OQS_MEM_secure_free(tmp_space, tmp_bytes); ++ OQS_MEM_secure_free(entropy, entropy_bytes); ++ return OQS_SUCCESS; ++} ++ ++OQS_STATUS crypto_sign_verify( ++ const uint8_t *signature, ++ size_t signature_len, ++ const uint8_t *message, ++ size_t message_len, ++ const uint8_t *public_key ++) { ++ if (signature_len != CRYPTO_BYTES) return OQS_ERROR; ++ uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); ++ uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); ++ if (tmp_space == NULL) return OQS_ERROR; ++ ++ uint8_t res = sdith_verify( ++ &SIGNATURE_PARAMS, ++ signature, ++ message, ++ message_len, ++ public_key, ++ tmp_space ++ ); ++ ++ OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data ++ return res ? OQS_SUCCESS : OQS_ERROR; ++} +diff --git a/integration/liboqs/api.h b/integration/liboqs/api.h +new file mode 100644 +index 0000000..fe7891b +--- /dev/null ++++ b/integration/liboqs/api.h +@@ -0,0 +1,68 @@ ++#ifndef API_H ++#define API_H ++ ++#include ++ ++// This header wraps the SDiTH signature API for use in liboqs ++ ++#include "sdith_signature.h" ++#include "commons.h" ++ ++#include ++ ++/* Public API */ ++#ifndef SDITH_PUBLIC_API_NAMESPACE ++#ifdef APPLY_PUBLIC_API_NAMESPACE ++#ifndef concat2 ++#define _concat2(a, b) a ## b ++#define concat2(a, b) _concat2(a, b) ++#endif ++#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) ++#else ++#define SDITH_PUBLIC_API_NAMESPACE(s) s ++#endif ++#endif ++ ++#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) ++#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) ++#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) ++ ++/** ++ * Generates the public and private key ++ * @param public_key [out] public key ++ * @param secret_key [out] secret key ++ * @return OQS_SUCCESS on success, OQS_FAILURE on failure ++ */ ++EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, ++ uint8_t* secret_key); ++ ++/** ++ * Signs a message with the private key ++ * @param signature [out] signature ++ * @param signature_len [out] length of the signature ++ * @param message [in] message to sign ++ * @param message_len [in] length of the message ++ * @param secret_key [in] secret key ++ */ ++EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, ++ size_t *signature_len, ++ const uint8_t *message, ++ size_t message_len, ++ const uint8_t *secret_key); ++ ++/** ++ * Verifies a signature with the public key ++ * @param message [in] message to verify ++ * @param message_len [in] length of the message ++ * @param signature [in] signature to verify ++ * @param signature_len [in] length of the signature ++ * @param public_key [in] public key ++ * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure ++ */ ++EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, ++ size_t signature_len, ++ const uint8_t *message, ++ size_t message_len, ++ const uint8_t *public_key); ++ ++#endif // API_H +diff --git a/integration/liboqs/fips202_glue.h b/integration/liboqs/fips202_glue.h +new file mode 100644 +index 0000000..70e1cf1 +--- /dev/null ++++ b/integration/liboqs/fips202_glue.h +@@ -0,0 +1,44 @@ ++#ifndef FIPS202_GLUE_H ++#define FIPS202_GLUE_H ++ ++#include ++ ++typedef xof_ctx Keccak_HashInstance; // defined in sdith_prng.h ++ ++static inline void Keccak_HashInitialize_SHAKE128(Keccak_HashInstance* inst) { ++ inst->shake = 128; ++ OQS_SHA3_shake128_inc_init(&inst->shake128_state); ++} ++ ++static inline void Keccak_HashInitialize_SHAKE256(Keccak_HashInstance* inst) { ++ inst->shake = 256; ++ OQS_SHA3_shake256_inc_init(&inst->shake256_state); ++} ++ ++// XKCP lengths are in bits, liboqs lengths are in bytes ++static inline void Keccak_HashUpdate(Keccak_HashInstance* inst, const void* data, uint64_t databitlen) { ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_inc_absorb(&inst->shake128_state, data, databitlen >> 3); ++ } else { ++ OQS_SHA3_shake256_inc_absorb(&inst->shake256_state, data, databitlen >> 3); ++ } ++} ++ ++static inline void Keccak_HashFinal(Keccak_HashInstance* inst, void* hashval) { ++ (void)hashval; // XKCP ignores it for SHAKE ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_inc_finalize(&inst->shake128_state); ++ } else { ++ OQS_SHA3_shake256_inc_finalize(&inst->shake256_state); ++ } ++} ++ ++static inline void Keccak_HashSqueeze(Keccak_HashInstance* inst, void* data, uint64_t databitlen) { ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_inc_squeeze(data, databitlen >> 3, &inst->shake128_state); ++ } else { ++ OQS_SHA3_shake256_inc_squeeze(data, databitlen >> 3, &inst->shake256_state); ++ } ++} ++ ++#endif +diff --git a/integration/liboqs/fips202x4_glue.h b/integration/liboqs/fips202x4_glue.h +new file mode 100644 +index 0000000..a9dc109 +--- /dev/null ++++ b/integration/liboqs/fips202x4_glue.h +@@ -0,0 +1,109 @@ ++#ifndef FIPS202X4_GLUE_H ++#define FIPS202X4_GLUE_H ++ ++#include ++ ++#include ++#include ++ ++typedef struct { ++ uint32_t shake; // 128 or 256, set by SpongeInitialize ++ union { ++ OQS_SHA3_shake128_inc_ctx shake128_state; ++ OQS_SHA3_shake256_inc_ctx shake256_state; ++ }; ++} KeccakWidth1600_SpongeInstance; ++ ++typedef struct { ++ uint32_t shake; // 128 or 256, set by SpongeInitialize ++ union { ++ OQS_SHA3_shake128_x4_inc_ctx shake128_state; ++ OQS_SHA3_shake256_x4_inc_ctx shake256_state; ++ }; ++} KeccakWidth1600times4_SpongeInstance; ++ ++ ++static inline void KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance* inst, unsigned int rate, ++ unsigned int capacity) { ++ (void)rate; // only read by the asserts, which NDEBUG removes ++ inst->shake = capacity / 2; // SHAKE128 has capacity 256 and SHAKE256 has capacity 512 ++ if (inst->shake == 128) { ++ assert(rate == (OQS_SHA3_SHAKE128_RATE << 3)); // XKCP rates are in bits, liboqs rates in bytes ++ OQS_SHA3_shake128_inc_init(&inst->shake128_state); ++ } else { ++ assert(rate == (OQS_SHA3_SHAKE256_RATE << 3)); ++ OQS_SHA3_shake256_inc_init(&inst->shake256_state); ++ } ++} ++ ++static inline void KeccakWidth1600_SpongeAbsorb(KeccakWidth1600_SpongeInstance* inst, const unsigned char* data, ++ size_t dataByteLen) { ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_inc_absorb(&inst->shake128_state, data, dataByteLen); ++ } else { ++ OQS_SHA3_shake256_inc_absorb(&inst->shake256_state, data, dataByteLen); ++ } ++} ++ ++// sdith always passes 0x1F (the SHAKE padding), which liboqs's finalize applies ++static inline void KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance* inst, ++ unsigned char delimitedData) { ++ (void)delimitedData; // liboqs finalize applies the delimiter already ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_inc_finalize(&inst->shake128_state); ++ } else { ++ OQS_SHA3_shake256_inc_finalize(&inst->shake256_state); ++ } ++} ++ ++static inline void KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance* inst, unsigned char* data, ++ size_t dataByteLen) { ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_inc_squeeze(data, dataByteLen, &inst->shake128_state); ++ } else { ++ OQS_SHA3_shake256_inc_squeeze(data, dataByteLen, &inst->shake256_state); ++ } ++} ++ ++static inline void KeccakWidth1600times4_SpongeInitialize(KeccakWidth1600times4_SpongeInstance* inst, ++ unsigned int rate, unsigned int capacity) { ++ (void)rate; // implied by capacity ++ inst->shake = capacity / 2; // SHAKE128 has capacity 256 and SHAKE256 has capacity 512 ++ if (inst->shake == 128) { ++ assert(rate == (OQS_SHA3_SHAKE128_RATE << 3)); // XKCP in bits, liboqs in bytes ++ OQS_SHA3_shake128_x4_inc_init(&inst->shake128_state); ++ } else { ++ assert(rate == (OQS_SHA3_SHAKE256_RATE << 3)); ++ OQS_SHA3_shake256_x4_inc_init(&inst->shake256_state); ++ } ++} ++ ++static inline void KeccakWidth1600times4_SpongeAbsorb(KeccakWidth1600times4_SpongeInstance* inst, ++ const unsigned char** data, size_t dataByteLen) { ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_x4_inc_absorb(&inst->shake128_state, data[0], data[1], data[2], data[3], dataByteLen); ++ } else { ++ OQS_SHA3_shake256_x4_inc_absorb(&inst->shake256_state, data[0], data[1], data[2], data[3], dataByteLen); ++ } ++} ++ ++static inline void KeccakWidth1600times4_SpongeAbsorbLastFewBits(KeccakWidth1600times4_SpongeInstance* inst, ++ unsigned char delimitedData) { ++ (void)delimitedData; // liboqs finalize applies the delimiter already ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_x4_inc_finalize(&inst->shake128_state); ++ } else { ++ OQS_SHA3_shake256_x4_inc_finalize(&inst->shake256_state); ++ } ++} ++ ++static inline void KeccakWidth1600times4_SpongeSqueeze(KeccakWidth1600times4_SpongeInstance* inst, ++ unsigned char** data, size_t dataByteLen) { ++ if (inst->shake == 128) { ++ OQS_SHA3_shake128_x4_inc_squeeze(data[0], data[1], data[2], data[3], dataByteLen, &inst->shake128_state); ++ } else { ++ OQS_SHA3_shake256_x4_inc_squeeze(data[0], data[1], data[2], data[3], dataByteLen, &inst->shake256_state); ++ } ++} ++ ++#endif +diff --git a/integration/liboqs/gen_namespace.sh b/integration/liboqs/gen_namespace.sh +new file mode 100755 +index 0000000..0794080 +--- /dev/null ++++ b/integration/liboqs/gen_namespace.sh +@@ -0,0 +1,86 @@ ++#!/bin/sh ++# Regenerate sdith_namespace.h from the compiled shared libraries. ++# ++# liboqs builds the shared SDitH code once, as sdith_common and (if available) ++# sdith_common_avx2, so every symbol they define is global in liboqs' library. ++# The header maps those names under a prefix; see README.md. ++# ++# ./gen_namespace.sh ++# ++set -eu ++ ++# Pin the collation so the generated order does not depend on the machine: a run ++# that only appends should show up as only an append. ++export LC_ALL=C ++ ++if [ $# -ne 1 ] || [ ! -d "$1" ]; then ++ echo "usage: $0 " >&2 ++ exit 1 ++fi ++ ++objects=$( ++ find "$1" \ ++ -type d -name 'sdith_sdith_common*.dir' \ ++ -exec find {} -name '*.o' -print \; ++) ++if [ -z "$objects" ]; then ++ echo "$0: no sdith_sdith_common*.dir objects under $1" >&2 ++ exit 1 ++fi ++ ++header="$(dirname "$0")/sdith_namespace.h" ++if [ -f "$header" ]; then ++ existing=$(sed -n 's/^#define \([A-Za-z_][A-Za-z0-9_]*\) *SDITH_NAMESPACE_FOR_LIBOQS(.*/\1/p' "$header") ++else ++ existing= ++fi ++ ++symbols=$( ++ echo "$objects" | ++ tr '\n' '\0' | ++ xargs -0 nm -P | # `nm -P` prints "name type value size" ++ awk '$2 ~ /^[ABCDGIRSTVW]$/ { print $1 }' | # filter for defined external symbols (caps) ++ sed 's/^_//; s/^oqs_sig_private_sdith_ref_//; s/^oqs_sig_private_sdith_avx2_//' | # strip leading underscore and existing liboqs prefixes ++ sort -u ++) ++if [ -z "$symbols" ]; then ++ echo "$0: nm reported no defined symbols" >&2 ++ exit 1 ++fi ++ ++new=$(echo "$symbols" | grep -Fxv "$existing" || true) # symbols the header lacks, for the report ++symbols=$(printf %s\\n "$symbols" "$existing" | grep . | sort -u) ++ ++defines=$( ++ echo "$symbols" | ++ awk '{ printf "#define %-61s SDITH_NAMESPACE_FOR_LIBOQS(%s)\n", $1, $1 }' ++) ++ ++cat > "$header" <&2 +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/META_SDitH3-L1-gf2-fast-cipherpow.yml b/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/META_SDitH3-L1-gf2-fast-cipherpow.yml +new file mode 100644 +index 0000000..1dc50cb +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/META_SDitH3-L1-gf2-fast-cipherpow.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L1-gf2-fast-cipherpow ++type: signature ++claimed-nist-level: 1 ++claimed-security: EUF-CMA ++length-public-key: 70 ++length-secret-key: 147 ++length-signature: 4643 ++nistkat-sha256: ce37d051dba74715aa3b5286970b688e2828a685279630e0ceac68b79c2e5607 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/avx2/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/avx2/params.h +new file mode 100644 +index 0000000..9202e22 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-fast-cipherpow, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 4643 ++#define SIGNATURE_PARAMS CAT1_FAST_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/ref/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/ref/params.h +new file mode 100644 +index 0000000..e8fd8ed +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-fast-cipherpow/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-fast-cipherpow, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 4643 ++#define SIGNATURE_PARAMS CAT1_FAST_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-fast/META_SDitH3-L1-gf2-fast.yml b/integration/liboqs/schemes/SDitH3-L1-gf2-fast/META_SDitH3-L1-gf2-fast.yml +new file mode 100644 +index 0000000..bef6bed +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-fast/META_SDitH3-L1-gf2-fast.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L1-gf2-fast ++type: signature ++claimed-nist-level: 1 ++claimed-security: EUF-CMA ++length-public-key: 70 ++length-secret-key: 147 ++length-signature: 4914 ++nistkat-sha256: 41ccb6bad2eefe684dca736393e8c29bec7f2f3672492df6cff17c84f333cc03 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-fast/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-fast/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-fast/avx2/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-fast/avx2/params.h +new file mode 100644 +index 0000000..60088c0 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-fast/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-fast, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 4914 ++#define SIGNATURE_PARAMS CAT1_FAST_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-fast/ref/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-fast/ref/params.h +new file mode 100644 +index 0000000..9a6b658 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-fast/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-fast, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 4914 ++#define SIGNATURE_PARAMS CAT1_FAST_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/META_SDitH3-L1-gf2-short-cipherpow.yml b/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/META_SDitH3-L1-gf2-short-cipherpow.yml +new file mode 100644 +index 0000000..1c016b0 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/META_SDitH3-L1-gf2-short-cipherpow.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L1-gf2-short-cipherpow ++type: signature ++claimed-nist-level: 1 ++claimed-security: EUF-CMA ++length-public-key: 70 ++length-secret-key: 147 ++length-signature: 3721 ++nistkat-sha256: cc0d9688a9c4b5f99e90746657da5cdd1804b5012b3c934975599512d5061e4c ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/avx2/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/avx2/params.h +new file mode 100644 +index 0000000..c3030cc +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-short-cipherpow, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 3721 ++#define SIGNATURE_PARAMS CAT1_SHORT_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/ref/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/ref/params.h +new file mode 100644 +index 0000000..67598ae +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-short-cipherpow/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-short-cipherpow, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 3721 ++#define SIGNATURE_PARAMS CAT1_SHORT_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-short/META_SDitH3-L1-gf2-short.yml b/integration/liboqs/schemes/SDitH3-L1-gf2-short/META_SDitH3-L1-gf2-short.yml +new file mode 100644 +index 0000000..ff545a5 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-short/META_SDitH3-L1-gf2-short.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L1-gf2-short ++type: signature ++claimed-nist-level: 1 ++claimed-security: EUF-CMA ++length-public-key: 70 ++length-secret-key: 147 ++length-signature: 3721 ++nistkat-sha256: d50d495fd8a0f2cb0463fcd3aef1398cf84b94bf0aff0fd69b5a1026b47e2047 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-short/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L1-gf2-short/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-short/avx2/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-short/avx2/params.h +new file mode 100644 +index 0000000..16c5d53 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-short/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-short, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_avx2_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 3721 ++#define SIGNATURE_PARAMS CAT1_SHORT_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L1-gf2-short/ref/params.h b/integration/liboqs/schemes/SDitH3-L1-gf2-short/ref/params.h +new file mode 100644 +index 0000000..4c39055 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L1-gf2-short/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L1-gf2-short, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_ ++#define CRYPTO_SECRETKEYBYTES 147 ++#define CRYPTO_PUBLICKEYBYTES 70 ++#define CRYPTO_BYTES 3721 ++#define SIGNATURE_PARAMS CAT1_SHORT_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/META_SDitH3-L3-gf2-fast-cipherpow.yml b/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/META_SDitH3-L3-gf2-fast-cipherpow.yml +new file mode 100644 +index 0000000..385bd6b +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/META_SDitH3-L3-gf2-fast-cipherpow.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L3-gf2-fast-cipherpow ++type: signature ++claimed-nist-level: 3 ++claimed-security: EUF-CMA ++length-public-key: 98 ++length-secret-key: 208 ++length-signature: 10452 ++nistkat-sha256: e14a0f9964f77f455f633e5a498a0efc9657a7393c07a2226f730864aca79966 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/avx2/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/avx2/params.h +new file mode 100644 +index 0000000..2f647fa +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-fast-cipherpow, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 10452 ++#define SIGNATURE_PARAMS CAT3_FAST_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/ref/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/ref/params.h +new file mode 100644 +index 0000000..592c5ef +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-fast-cipherpow/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-fast-cipherpow, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 10452 ++#define SIGNATURE_PARAMS CAT3_FAST_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-fast/META_SDitH3-L3-gf2-fast.yml b/integration/liboqs/schemes/SDitH3-L3-gf2-fast/META_SDitH3-L3-gf2-fast.yml +new file mode 100644 +index 0000000..73c0802 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-fast/META_SDitH3-L3-gf2-fast.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L3-gf2-fast ++type: signature ++claimed-nist-level: 3 ++claimed-security: EUF-CMA ++length-public-key: 98 ++length-secret-key: 208 ++length-signature: 10852 ++nistkat-sha256: b4778b069b8c58c803cb8bc8e3d4557c67e0ec5555a6ba2e82186beb0fdb1309 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-fast/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-fast/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-fast/avx2/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-fast/avx2/params.h +new file mode 100644 +index 0000000..1011e24 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-fast/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-fast, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 10852 ++#define SIGNATURE_PARAMS CAT3_FAST_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-fast/ref/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-fast/ref/params.h +new file mode 100644 +index 0000000..00ea3cd +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-fast/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-fast, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 10852 ++#define SIGNATURE_PARAMS CAT3_FAST_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/META_SDitH3-L3-gf2-short-cipherpow.yml b/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/META_SDitH3-L3-gf2-short-cipherpow.yml +new file mode 100644 +index 0000000..433c8be +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/META_SDitH3-L3-gf2-short-cipherpow.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L3-gf2-short-cipherpow ++type: signature ++claimed-nist-level: 3 ++claimed-security: EUF-CMA ++length-public-key: 98 ++length-secret-key: 208 ++length-signature: 8484 ++nistkat-sha256: e8a4ba0d333235fa061b79de0d65bc3932b73b6ee2322b3b6ed4fb3598356b4f ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/avx2/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/avx2/params.h +new file mode 100644 +index 0000000..4a96170 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-short-cipherpow, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 8484 ++#define SIGNATURE_PARAMS CAT3_SHORT_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/ref/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/ref/params.h +new file mode 100644 +index 0000000..6027ddf +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-short-cipherpow/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-short-cipherpow, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 8484 ++#define SIGNATURE_PARAMS CAT3_SHORT_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-short/META_SDitH3-L3-gf2-short.yml b/integration/liboqs/schemes/SDitH3-L3-gf2-short/META_SDitH3-L3-gf2-short.yml +new file mode 100644 +index 0000000..df89c83 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-short/META_SDitH3-L3-gf2-short.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L3-gf2-short ++type: signature ++claimed-nist-level: 3 ++claimed-security: EUF-CMA ++length-public-key: 98 ++length-secret-key: 208 ++length-signature: 8484 ++nistkat-sha256: 7fa8b98407d4ac073a01c754824b66d8c0a8f6eb1e984082593e1d101c83c9e1 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-short/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L3-gf2-short/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-short/avx2/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-short/avx2/params.h +new file mode 100644 +index 0000000..d22a932 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-short/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-short, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_avx2_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 8484 ++#define SIGNATURE_PARAMS CAT3_SHORT_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L3-gf2-short/ref/params.h b/integration/liboqs/schemes/SDitH3-L3-gf2-short/ref/params.h +new file mode 100644 +index 0000000..cd23de8 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L3-gf2-short/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L3-gf2-short, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_ ++#define CRYPTO_SECRETKEYBYTES 208 ++#define CRYPTO_PUBLICKEYBYTES 98 ++#define CRYPTO_BYTES 8484 ++#define SIGNATURE_PARAMS CAT3_SHORT_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/META_SDitH3-L5-gf2-fast-cipherpow.yml b/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/META_SDitH3-L5-gf2-fast-cipherpow.yml +new file mode 100644 +index 0000000..8b12b0d +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/META_SDitH3-L5-gf2-fast-cipherpow.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L5-gf2-fast-cipherpow ++type: signature ++claimed-nist-level: 5 ++claimed-security: EUF-CMA ++length-public-key: 132 ++length-secret-key: 275 ++length-signature: 19144 ++nistkat-sha256: d5622fa5a18563a873dc3eb8aa4c324b64843dbc2449856d94ab5960941b0c90 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/avx2/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/avx2/params.h +new file mode 100644 +index 0000000..3979ada +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-fast-cipherpow, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 19144 ++#define SIGNATURE_PARAMS CAT5_FAST_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/ref/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/ref/params.h +new file mode 100644 +index 0000000..adbcb34 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-fast-cipherpow/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-fast-cipherpow, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 19144 ++#define SIGNATURE_PARAMS CAT5_FAST_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-fast/META_SDitH3-L5-gf2-fast.yml b/integration/liboqs/schemes/SDitH3-L5-gf2-fast/META_SDitH3-L5-gf2-fast.yml +new file mode 100644 +index 0000000..976cf9a +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-fast/META_SDitH3-L5-gf2-fast.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L5-gf2-fast ++type: signature ++claimed-nist-level: 5 ++claimed-security: EUF-CMA ++length-public-key: 132 ++length-secret-key: 275 ++length-signature: 19144 ++nistkat-sha256: 9ea0519ec21823dd72be5c81a8617decc67cff01345c2a93a7b1421fd59474e8 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-fast/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-fast/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-fast/avx2/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-fast/avx2/params.h +new file mode 100644 +index 0000000..3fd541d +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-fast/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-fast, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 19144 ++#define SIGNATURE_PARAMS CAT5_FAST_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-fast/ref/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-fast/ref/params.h +new file mode 100644 +index 0000000..09374c3 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-fast/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-fast, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 19144 ++#define SIGNATURE_PARAMS CAT5_FAST_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/META_SDitH3-L5-gf2-short-cipherpow.yml b/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/META_SDitH3-L5-gf2-short-cipherpow.yml +new file mode 100644 +index 0000000..3ac00c1 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/META_SDitH3-L5-gf2-short-cipherpow.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L5-gf2-short-cipherpow ++type: signature ++claimed-nist-level: 5 ++claimed-security: EUF-CMA ++length-public-key: 132 ++length-secret-key: 275 ++length-signature: 15147 ++nistkat-sha256: 097cc28abf7afc193824ed98bf145ac8239a7f23757a687f30f3683f9b4e5495 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/avx2/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/avx2/params.h +new file mode 100644 +index 0000000..dc0d4e5 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-short-cipherpow, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 15147 ++#define SIGNATURE_PARAMS CAT5_SHORT_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/ref/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/ref/params.h +new file mode 100644 +index 0000000..2634d8b +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-short-cipherpow/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-short-cipherpow, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 15147 ++#define SIGNATURE_PARAMS CAT5_SHORT_CIPHERPOW_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-short/META_SDitH3-L5-gf2-short.yml b/integration/liboqs/schemes/SDitH3-L5-gf2-short/META_SDitH3-L5-gf2-short.yml +new file mode 100644 +index 0000000..cdbcd8b +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-short/META_SDitH3-L5-gf2-short.yml +@@ -0,0 +1,67 @@ ++name: SDitH3-L5-gf2-short ++type: signature ++claimed-nist-level: 5 ++claimed-security: EUF-CMA ++length-public-key: 132 ++length-secret-key: 275 ++length-signature: 15147 ++nistkat-sha256: e37006ef04589adff3fb96948e35e370e4540d10bbf4a4c6c22eff83c8942062 ++principal-submitters: ++- Carlos Aguilar Melchor ++- Slim Bettaieb ++- Loïc Bidoux ++- Thibauld Feneuil ++- Philippe Gaborit ++- Nicolas Gama ++- Shay Gueron ++- James Howe ++- Andreas Hülsing ++- David Joseph ++- Antoine Joux ++- Mukul Kulkarni ++- Edoardo Persichetti ++- Tovohery H. Randrianarisoa ++- Matthieu Rivain ++- Dongze Yue ++auxiliary-submitters: [] ++implementations: ++- name: ref ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-short/ref/params.h ++ supported_platforms: ++ # __uint128_t only exists on targets with 128-bit integer support, so the ++ # reference code does not build on any 32-bit architecture. ++ - architecture: 64-bit little-endian ++ operating_systems: ++ - Linux ++ - Darwin ++ # - Windows # The reference code uses __uint128_t and GCC/Clang function attributes, so it does not build with MSVC ++- name: avx2 ++ version: round3 ++ folder_name: . ++ common_dep: sdith_common_headers sdith_common_avx2 ++ signature_keypair: oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_keypair # prefix + crypto_sign_keypair ++ signature_signature: oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_sign # prefix + crypto_sign_sign ++ signature_verify: oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_verify # prefix + crypto_sign_verify ++ sources: >- ++ integration/liboqs/api.c ++ integration/liboqs/api.h ++ integration/liboqs/schemes/SDitH3-L5-gf2-short/avx2/params.h ++ supported_platforms: ++ - architecture: x86_64 ++ operating_systems: ++ - Linux ++ # - Darwin # TODO: needs small upstream build patches for support. As of writing, all x86 builds assume x86_LINUX. Darwin is missing a glibc header file for `__always_inline` ++ required_flags: ++ - avx2 ++ - avx ++ - aes ++ - pclmulqdq +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-short/avx2/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-short/avx2/params.h +new file mode 100644 +index 0000000..0b5f024 +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-short/avx2/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-short, avx2 implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_avx2_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 15147 ++#define SIGNATURE_PARAMS CAT5_SHORT_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/schemes/SDitH3-L5-gf2-short/ref/params.h b/integration/liboqs/schemes/SDitH3-L5-gf2-short/ref/params.h +new file mode 100644 +index 0000000..18564aa +--- /dev/null ++++ b/integration/liboqs/schemes/SDitH3-L5-gf2-short/ref/params.h +@@ -0,0 +1,20 @@ ++#ifndef SDITH_LIBOQS_PARAMS_H ++#define SDITH_LIBOQS_PARAMS_H ++ ++/* SDitH3-L5-gf2-short, ref implementation: the settings api.c is built with. */ ++ ++#ifndef SDITH3_FOR_LIBOQS ++#define SDITH3_FOR_LIBOQS ++#endif ++#ifndef NDEBUG ++#define NDEBUG ++#endif ++ ++#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ ++#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_ ++#define CRYPTO_SECRETKEYBYTES 275 ++#define CRYPTO_PUBLICKEYBYTES 132 ++#define CRYPTO_BYTES 15147 ++#define SIGNATURE_PARAMS CAT5_SHORT_PARAMETERS ++ ++#endif // SDITH_LIBOQS_PARAMS_H +diff --git a/integration/liboqs/sdith_namespace.h b/integration/liboqs/sdith_namespace.h +new file mode 100644 +index 0000000..8691c1c +--- /dev/null ++++ b/integration/liboqs/sdith_namespace.h +@@ -0,0 +1,528 @@ ++#ifndef SDITH_NAMESPACE_H ++#define SDITH_NAMESPACE_H ++ ++/** ++ * Generated by integration/liboqs/gen_namespace.sh. Do not edit by hand. ++ * ++ * liboqs compiles the shared SDitH sources once and links every scheme variant ++ * against that single copy, so these symbols are global in liboqs' own library. ++ */ ++ ++#ifdef APPLY_NAMESPACE ++ ++#ifndef concat2 ++#define _concat2(a, b) a##b ++#define concat2(a, b) _concat2(a, b) ++#endif ++#define SDITH_NAMESPACE_FOR_LIBOQS(s) concat2(APPLY_NAMESPACE, s) ++ ++#define CAT1_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_CIPHERPOW_PARAMETERS) ++#define CAT1_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_PARAMETERS) ++#define CAT1_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_CIPHERPOW_PARAMETERS) ++#define CAT1_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_PARAMETERS) ++#define CAT3_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_CIPHERPOW_PARAMETERS) ++#define CAT3_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_PARAMETERS) ++#define CAT3_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_CIPHERPOW_PARAMETERS) ++#define CAT3_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_PARAMETERS) ++#define CAT5_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_CIPHERPOW_PARAMETERS) ++#define CAT5_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_PARAMETERS) ++#define CAT5_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_CIPHERPOW_PARAMETERS) ++#define CAT5_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_PARAMETERS) ++#define FLAMBDA_2P32 SDITH_NAMESPACE_FOR_LIBOQS(FLAMBDA_2P32) ++#define GF128_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF128_ONE) ++#define GF128_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF128_ZERO) ++#define GF192_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF192_ONE) ++#define GF192_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF192_ZERO) ++#define GF256_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF256_ONE) ++#define GF256_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF256_ZERO) ++#define HASH_AUX_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_AUX_PREFIX) ++#define HASH_BAVC_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_BAVC_PREFIX) ++#define HASH_LINES_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_LINES_PREFIX) ++#define HASH_PIOP_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_PIOP_PREFIX) ++#define PROOFOW_CTR_REVEALED_BYTES SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_CTR_REVEALED_BYTES) ++#define PROOFOW_H0_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H0_PREFIX) ++#define PROOFOW_H1_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H1_PREFIX) ++#define aes128_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_avx2) ++#define aes128_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_ref) ++#define aes128_ctrle_nocarry_2blk_x4keys_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2blk_x4keys_avx2) ++#define aes128_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_avx2) ++#define aes128_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_ref) ++#define aes128_ctrle_nocarry_3blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_avx2) ++#define aes128_ctrle_nocarry_3blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_ref) ++#define aes128_ctrle_nocarry_4blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_avx2) ++#define aes128_ctrle_nocarry_4blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_ref) ++#define aes128_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_avx2) ++#define aes128_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_ref) ++#define aes128_ctrle_set_key_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_set_key_avx2) ++#define aes128_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_encrypt_1block_ref) ++#define aes128_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_avx2) ++#define aes128_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_ref) ++#define aes128_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_avx2) ++#define aes128_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_ref) ++#define aes128_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_avx2) ++#define aes128_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_ref) ++#define aes128_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_avx2) ++#define aes128_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_ref) ++#define aes128_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(aes128_keyexp_x4_enclast) ++#define aes128_prepare_rk_buffer SDITH_NAMESPACE_FOR_LIBOQS(aes128_prepare_rk_buffer) ++#define aes128_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_proofow_grind_avx2) ++#define aes128_release_key SDITH_NAMESPACE_FOR_LIBOQS(aes128_release_key) ++#define aes128_set_key_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_ref) ++#define aes128_set_key_reuse_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_reuse_ref) ++#define binval_of SDITH_NAMESPACE_FOR_LIBOQS(binval_of) ++#define binval_of_compat SDITH_NAMESPACE_FOR_LIBOQS(binval_of_compat) ++#define bit_of SDITH_NAMESPACE_FOR_LIBOQS(bit_of) ++#define bitmat_get_value SDITH_NAMESPACE_FOR_LIBOQS(bitmat_get_value) ++#define bitvec_cascade_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_avx2) ++#define bitvec_cascade_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_ref) ++#define bitvec_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(bitvec_is_zero_nonct) ++#define bitvec_xor_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_avx2) ++#define bitvec_xor_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_ref) ++#define bitvec_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_avx2) ++#define bitvec_xor_to_masked_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_avx) ++#define bitvec_xor_to_masked_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_ref) ++#define bitvec_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_ref) ++#define bitvec_xorbit_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_avx) ++#define bitvec_xorbit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_ref) ++#define bitvec_xoru32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_avx) ++#define bitvec_xoru32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_ref) ++#define both_vole_consistency_check_matrix SDITH_NAMESPACE_FOR_LIBOQS(both_vole_consistency_check_matrix) ++#define bytes_of_proofow_ctx_cipher_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat1) ++#define bytes_of_proofow_ctx_cipher_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat3) ++#define bytes_of_proofow_ctx_cipher_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat5) ++#define bytes_of_proofow_ctx_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat1) ++#define bytes_of_proofow_ctx_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat3) ++#define bytes_of_proofow_ctx_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat5) ++#define ceil_log2i SDITH_NAMESPACE_FOR_LIBOQS(ceil_log2i) ++#define compute_extended_parameters SDITH_NAMESPACE_FOR_LIBOQS(compute_extended_parameters) ++#define compute_rsd_codim SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim) ++#define compute_rsd_codim_slice SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim_slice) ++#define compute_tweaked_salts SDITH_NAMESPACE_FOR_LIBOQS(compute_tweaked_salts) ++#define delta1_from_delta0_ref SDITH_NAMESPACE_FOR_LIBOQS(delta1_from_delta0_ref) ++#define delta2_from_delta1_ref SDITH_NAMESPACE_FOR_LIBOQS(delta2_from_delta1_ref) ++#define div_rem_u32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_avx) ++#define div_rem_u32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_ref) ++#define estimate_topen SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen) ++#define estimate_topen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen_tmp_bytes) ++#define extend_leaf_seed_cat1_aes128_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_avx2) ++#define extend_leaf_seed_cat1_aes128_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_ref) ++#define extend_leaf_seed_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_avx2) ++#define extend_leaf_seed_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_ref) ++#define extend_leaf_seed_cat3_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_avx2) ++#define extend_leaf_seed_cat3_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_ref) ++#define extend_leaf_seed_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_avx2) ++#define extend_leaf_seed_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_ref) ++#define extend_leaf_seed_cat5_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_avx2) ++#define extend_leaf_seed_cat5_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_ref) ++#define extend_leaf_seed_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_avx2) ++#define extend_leaf_seed_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_ref) ++#define extended_node_seed_bytes_cat1_aes128 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat1_aes128) ++#define extended_node_seed_bytes_cat3_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat3_rijndael256) ++#define extended_node_seed_bytes_cat5_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat5_rijndael256) ++#define extract_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(extract_kappabit_uint) ++#define extseed_buf_noop SDITH_NAMESPACE_FOR_LIBOQS(extseed_buf_noop) ++#define flambda_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(flambda_is_zero_nonct) ++#define flambda_power SDITH_NAMESPACE_FOR_LIBOQS(flambda_power) ++#define floor_log2i SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i) ++#define floor_log2i_compat SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i_compat) ++#define full_ggm_tree_open_sibling_path_from_root SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root) ++#define full_ggm_tree_open_sibling_path_from_root_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root_tmp_bytes) ++#define gf128_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_pclmul) ++#define gf128_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_ref) ++#define gf128_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_avx2) ++#define gf128_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_ref) ++#define gf128_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_pclmul) ++#define gf128_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_ref) ++#define gf128_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_avx) ++#define gf128_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_naive) ++#define gf128_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_ref) ++#define gf128_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_pclmul) ++#define gf128_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_ref) ++#define gf128_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_avx2) ++#define gf128_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_ref) ++#define gf128_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_pclmul) ++#define gf128_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_ref) ++#define gf128_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_avx) ++#define gf128_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_ref) ++#define gf128_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_pclmul) ++#define gf128_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_ref) ++#define gf128_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_f2_ref) ++#define gf128_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul) ++#define gf128_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul_f2) ++#define gf128_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_ref) ++#define gf128_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_set_ref) ++#define gf128_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_avx2) ++#define gf128_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_pow2_ref) ++#define gf128_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_ref) ++#define gf128_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_pclmul) ++#define gf128_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_ref) ++#define gf128_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_f2_ref) ++#define gf128_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul) ++#define gf128_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul_f2) ++#define gf128_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_ref) ++#define gf128_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_set_ref) ++#define gf128_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_avx2) ++#define gf128_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_naive) ++#define gf128_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_ref) ++#define gf128_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_ref) ++#define gf128p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_lsh) ++#define gf128p_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128p_mul) ++#define gf128p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_rsh) ++#define gf128p_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128p_sum) ++#define gf128v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf128v_bitof) ++#define gf128v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf128v_equals) ++#define gf128v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_lsh) ++#define gf128v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128v_mul) ++#define gf128v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_rsh) ++#define gf128v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128v_sum) ++#define gf192_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_pclmul) ++#define gf192_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_ref) ++#define gf192_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_avx2) ++#define gf192_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_ref) ++#define gf192_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_pclmul) ++#define gf192_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_ref) ++#define gf192_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_avx) ++#define gf192_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_naive) ++#define gf192_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_ref) ++#define gf192_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_pclmul) ++#define gf192_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_ref) ++#define gf192_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_avx2) ++#define gf192_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_ref) ++#define gf192_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_pclmul) ++#define gf192_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_ref) ++#define gf192_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_avx) ++#define gf192_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_ref) ++#define gf192_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_pclmul) ++#define gf192_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_ref) ++#define gf192_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_f2_ref) ++#define gf192_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_pclmul) ++#define gf192_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_ref) ++#define gf192_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_set_ref) ++#define gf192_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_pow2_ref) ++#define gf192_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_ref) ++#define gf192_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_pclmul) ++#define gf192_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_ref) ++#define gf192_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_f2_ref) ++#define gf192_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_pclmul) ++#define gf192_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_ref) ++#define gf192_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_set_ref) ++#define gf192_sum_pow2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_avx2) ++#define gf192_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_naive) ++#define gf192_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_ref) ++#define gf192_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_ref) ++#define gf192p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_lsh) ++#define gf192p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_rsh) ++#define gf192v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf192v_bitof) ++#define gf192v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf192v_equals) ++#define gf192v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_lsh) ++#define gf192v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf192v_mul) ++#define gf192v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_rsh) ++#define gf192v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf192v_sum) ++#define gf256_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_pclmul) ++#define gf256_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_ref) ++#define gf256_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_avx2) ++#define gf256_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_ref) ++#define gf256_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_pclmul) ++#define gf256_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_ref) ++#define gf256_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_avx) ++#define gf256_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_naive) ++#define gf256_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_ref) ++#define gf256_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_pclmul) ++#define gf256_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_ref) ++#define gf256_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_avx2) ++#define gf256_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_ref) ++#define gf256_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_pclmul) ++#define gf256_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_ref) ++#define gf256_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_avx) ++#define gf256_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_ref) ++#define gf256_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_pclmul) ++#define gf256_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_ref) ++#define gf256_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_f2_ref) ++#define gf256_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul) ++#define gf256_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul_f2) ++#define gf256_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_ref) ++#define gf256_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_set_ref) ++#define gf256_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_avx2) ++#define gf256_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_pow2_ref) ++#define gf256_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_ref) ++#define gf256_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_pclmul) ++#define gf256_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_ref) ++#define gf256_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_f2_ref) ++#define gf256_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul) ++#define gf256_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul_f2) ++#define gf256_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_ref) ++#define gf256_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_set_ref) ++#define gf256_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_avx2) ++#define gf256_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_naive) ++#define gf256_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_ref) ++#define gf256_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_ref) ++#define gf256p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_lsh) ++#define gf256p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_rsh) ++#define gf256v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf256v_bitof) ++#define gf256v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf256v_equals) ++#define gf256v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_lsh) ++#define gf256v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf256v_mul) ++#define gf256v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_rsh) ++#define gf256v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf256v_sum) ++#define gfprod128 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128) ++#define gfprod128_f2 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128_f2) ++#define ggm_commit_rng_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_avx2) ++#define ggm_commit_rng_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_ref) ++#define ggm_commit_rng_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_avx2) ++#define ggm_commit_rng_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_ref) ++#define ggm_commit_rng_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_avx2) ++#define ggm_commit_rng_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_ref) ++#define ggm_seed_rng_lr_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_avx2) ++#define ggm_seed_rng_lr_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_ref) ++#define ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2) ++#define ggm_seed_rng_lr_ext_cat1_aes128_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_ref) ++#define ggm_seed_rng_lr_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_avx2) ++#define ggm_seed_rng_lr_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_ref) ++#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2) ++#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref) ++#define ggm_seed_rng_lr_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_avx2) ++#define ggm_seed_rng_lr_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_ref) ++#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2) ++#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref) ++#define grey_of SDITH_NAMESPACE_FOR_LIBOQS(grey_of) ++#define hidden_leaves_indexes SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes) ++#define hidden_leaves_indexes2 SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes2) ++#define inv_grey_of SDITH_NAMESPACE_FOR_LIBOQS(inv_grey_of) ++#define keygen_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_avx) ++#define keygen_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_ref) ++#define keygen_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_avx) ++#define keygen_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_ref) ++#define keygen_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_avx) ++#define keygen_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_ref) ++#define keygen_rng_next_u32_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_avx) ++#define keygen_rng_next_u32_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_ref) ++#define keygen_rng_next_u32_rijndael256_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_avx) ++#define keygen_rng_next_u32_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_ref) ++#define keygen_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_aes128_cat1_ref) ++#define keygen_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_noop) ++#define map_public_key SDITH_NAMESPACE_FOR_LIBOQS(map_public_key) ++#define map_secret_key SDITH_NAMESPACE_FOR_LIBOQS(map_secret_key) ++#define map_signature SDITH_NAMESPACE_FOR_LIBOQS(map_signature) ++#define mask_eq_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_avx) ++#define mask_eq_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_ref) ++#define mask_lt_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_avx) ++#define mask_lt_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_ref) ++#define matrix_f2_times_vector_flambda_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_avx2) ++#define matrix_f2_times_vector_flambda_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_ref) ++#define matrix_rng_get_row_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_avx) ++#define matrix_rng_get_row_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_ref) ++#define matrix_rng_get_row_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_avx) ++#define matrix_rng_get_row_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_ref) ++#define matrix_rng_get_row_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_avx) ++#define matrix_rng_get_row_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_ref) ++#define matrix_rng_get_rows_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_avx) ++#define matrix_rng_get_rows_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_ref) ++#define matrix_rng_get_rows_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_avx) ++#define matrix_rng_get_rows_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_ref) ++#define matrix_rng_get_rows_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_avx) ++#define matrix_rng_get_rows_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_ref) ++#define matrix_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_avx) ++#define matrix_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_ref) ++#define matrix_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_avx) ++#define matrix_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_ref) ++#define matrix_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_avx) ++#define matrix_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_ref) ++#define matrix_rng_preprocess_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_avx) ++#define matrix_rng_preprocess_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_ref) ++#define matrix_rng_preprocess_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_avx) ++#define matrix_rng_preprocess_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_ref) ++#define matrix_rng_preprocess_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_avx) ++#define matrix_rng_preprocess_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_ref) ++#define matrix_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_aes128_cat1_ref) ++#define matrix_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_noop) ++#define matrix_rng_rows_times_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_avx) ++#define matrix_rng_rows_times_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_ref) ++#define matrix_rng_rows_times_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_avx) ++#define matrix_rng_rows_times_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_ref) ++#define matrix_rng_rows_times_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_avx) ++#define matrix_rng_rows_times_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_ref) ++#define matrix_vector_product_f2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_avx2) ++#define matrix_vector_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_ref) ++#define partition SDITH_NAMESPACE_FOR_LIBOQS(partition) ++#define prepare_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(prepare_extseed_buf_cat1_aes128_ref) ++#define proofow_grind_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_avx) ++#define proofow_grind_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_ref) ++#define proofow_grind_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_avx) ++#define proofow_grind_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_ref) ++#define proofow_grind_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_avx) ++#define proofow_grind_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_ref) ++#define proofow_grind_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1) ++#define proofow_grind_w_shake_cat1_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1_4way) ++#define proofow_grind_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3) ++#define proofow_grind_w_shake_cat3_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3_4way) ++#define proofow_grind_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5) ++#define proofow_grind_w_shake_cat5_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5_4way) ++#define proofow_init_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_avx) ++#define proofow_init_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_ref) ++#define proofow_init_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_avx) ++#define proofow_init_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_ref) ++#define proofow_init_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_avx) ++#define proofow_init_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_ref) ++#define proofow_init_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat1) ++#define proofow_init_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat3) ++#define proofow_init_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat5) ++#define proofow_release_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_cipher_cat1_ref) ++#define proofow_release_noop SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_noop) ++#define proofow_verify_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_avx) ++#define proofow_verify_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_ref) ++#define proofow_verify_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_avx) ++#define proofow_verify_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_ref) ++#define proofow_verify_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_avx) ++#define proofow_verify_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_ref) ++#define proofow_verify_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat1) ++#define proofow_verify_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat3) ++#define proofow_verify_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat5) ++#define prover_cst_check_unitary_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref) ++#define prover_cst_check_unitary_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref_tmp_bytes) ++#define prover_cst_mux_circuit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref) ++#define prover_cst_mux_circuit_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref_tmp_bytes) ++#define prover_cst_vole_check_zero_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_check_zero_gate_ct_ref) ++#define prover_cst_vole_echelon_pow2_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_echelon_pow2_ct_ref) ++#define prover_cst_vole_mul_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_mul_gate_ct_ref) ++#define prover_cst_vole_packed_secret_input_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_packed_secret_input_ct_ref) ++#define prover_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_ctrl_bytes) ++#define prover_cst_vole_qary_mux_gate_ct_f2_prep SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_prep) ++#define prover_cst_vole_qary_mux_gate_ct_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref) ++#define prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes) ++#define prover_cst_vole_qary_mux_gate_ct_naive SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_naive) ++#define prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes) ++#define prover_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_prepare_ctrl) ++#define prover_cst_vole_xor_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_xor_gate_ct_ref) ++#define prover_f2_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_std_to_cst_vole_ct_ref) ++#define prover_f2_to_flambda_deg1_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_to_flambda_deg1_std_vole_ct_ref) ++#define prover_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_deg1_to_degd_vole_ref) ++#define prover_flambda_degd_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_degd_std_to_cst_vole_ct_ref) ++#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref) ++#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes) ++#define prover_midsize_to_fullsize_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_midsize_to_fullsize_std_vole_ct_ref) ++#define prover_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(prover_vole_consistency_check) ++#define quickSort SDITH_NAMESPACE_FOR_LIBOQS(quickSort) ++#define release_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(release_extseed_buf_cat1_aes128_ref) ++#define rijndael256_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_avx2) ++#define rijndael256_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_ref) ++#define rijndael256_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_avx2) ++#define rijndael256_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_ref) ++#define rijndael256_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_avx2) ++#define rijndael256_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_ref) ++#define rijndael256_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_encrypt_1block_ref) ++#define rijndael256_key_schedule_avx SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_avx) ++#define rijndael256_key_schedule_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_ref) ++#define rijndael256_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_avx2) ++#define rijndael256_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_ref) ++#define rijndael256_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_avx2) ++#define rijndael256_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_ref) ++#define rijndael256_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_avx2) ++#define rijndael256_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_ref) ++#define rijndael256_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_avx2) ++#define rijndael256_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_ref) ++#define rijndael256_keyexp_x1_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x1_enclast) ++#define rijndael256_keyexp_x2_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x2_enclast) ++#define rijndael256_keyexp_x3_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x3_enclast) ++#define rijndael256_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x4_enclast) ++#define rijndael256_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_proofow_grind_avx2) ++#define rijndaelEncrypt SDITH_NAMESPACE_FOR_LIBOQS(rijndaelEncrypt) ++#define rijndaelKeySetupEnc SDITH_NAMESPACE_FOR_LIBOQS(rijndaelKeySetupEnc) ++#define rsd_encode_solution_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_encode_solution_ref) ++#define rsd_expand_public_key_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_expand_public_key_ref) ++#define rsd_generate_random_instance_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_ref) ++#define rsd_generate_random_instance_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_tmp_bytes) ++#define rsd_public_key_times_challenge_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_ref) ++#define rsd_public_key_times_challenge_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_tmp_bytes) ++#define sdith_keygen SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen) ++#define sdith_keygen_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_entropy_bytes) ++#define sdith_keygen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_tmp_bytes) ++#define sdith_public_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_public_key_bytes) ++#define sdith_secret_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_secret_key_bytes) ++#define sdith_sign SDITH_NAMESPACE_FOR_LIBOQS(sdith_sign) ++#define sdith_signature_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_bytes) ++#define sdith_signature_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_entropy_bytes) ++#define sdith_signature_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_tmp_bytes) ++#define sdith_verify SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify) ++#define sdith_verify_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify_tmp_bytes) ++#define swap SDITH_NAMESPACE_FOR_LIBOQS(swap) ++#define tmp_bytes_init SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_init) ++#define tmp_bytes_reserve_call SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_call) ++#define tmp_bytes_reserve_local_var SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var) ++#define tmp_bytes_reserve_local_var_aligned SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var_aligned) ++#define transpose_128_128_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_naive) ++#define transpose_128_128_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_ref) ++#define transpose_128_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_naive) ++#define transpose_128_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_ref) ++#define transpose_192_192_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_naive) ++#define transpose_192_192_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_ref) ++#define transpose_192_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_naive) ++#define transpose_192_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_ref) ++#define transpose_256_256_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_naive) ++#define transpose_256_256_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_ref) ++#define transpose_256_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_naive) ++#define transpose_256_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_ref) ++#define verifier_cst_check_unitary_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref) ++#define verifier_cst_check_unitary_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref_tmp_bytes) ++#define verifier_cst_mux_circuit_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref) ++#define verifier_cst_mux_circuit_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref_tmp_bytes) ++#define verifier_cst_vole_check_zero_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_check_zero_gate_ref) ++#define verifier_cst_vole_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_echelon_pow2_ref) ++#define verifier_cst_vole_mul_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_mul_gate_ref) ++#define verifier_cst_vole_packed_secret_input_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_packed_secret_input_ref) ++#define verifier_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_ctrl_bytes) ++#define verifier_cst_vole_qary_mux_gate_prep SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_prep) ++#define verifier_cst_vole_qary_mux_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref) ++#define verifier_cst_vole_qary_mux_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref_tmp_bytes) ++#define verifier_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_prepare_ctrl) ++#define verifier_cst_vole_xor_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_xor_gate_ref) ++#define verifier_f2_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_std_to_cst_vole_ref) ++#define verifier_f2_to_flambda_deg1_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_to_flambda_deg1_std_vole_ref) ++#define verifier_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_deg1_to_degd_vole_ref) ++#define verifier_flambda_degd_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_degd_std_to_cst_vole_ref) ++#define verifier_midsize_to_fullsize_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_midsize_to_fullsize_std_vole_ref) ++#define verifier_open_midsize_grey_vole_from_seeds_bfs_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_ref) ++#define verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes) ++#define verifier_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(verifier_vole_consistency_check) ++#define vole_consistency_check_matrix_ncols SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_ncols) ++#define vole_consistency_check_matrix_nrows SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_nrows) ++#define vole_parameters_init SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init) ++#define vole_parameters_init_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_avx) ++#define vole_parameters_init_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_ref) ++#define vole_parameters_init_with_variant SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant) ++#define vole_parameters_init_with_variant_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_avx) ++#define vole_parameters_init_with_variant_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_ref) ++#define vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2) ++#define vole_rng_ext_cat1_aes128_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_ref) ++#define vole_rng_ext_cat3_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_avx2) ++#define vole_rng_ext_cat3_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_ref) ++#define vole_rng_ext_cat5_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_avx2) ++#define vole_rng_ext_cat5_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_ref) ++#define xof_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake128) ++#define xof_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake256) ++#define xof_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake128) ++#define xof_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake256) ++#define xof_finalize_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake128) ++#define xof_finalize_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake256) ++#define xof_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake128) ++#define xof_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake256) ++#define xof_init_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake128) ++#define xof_init_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake256) ++#define xof_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake128) ++#define xof_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake256) ++#define xof_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake128) ++#define xof_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake256) ++#define xof_vector_ctx_bytes_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake128) ++#define xof_vector_ctx_bytes_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake256) ++#define xof_vector_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake128) ++#define xof_vector_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake256) ++#define xof_vector_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake128) ++#define xof_vector_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake256) ++#define xof_vector_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake128) ++#define xof_vector_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake256) ++#define xof_vector_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake128) ++#define xof_vector_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake256) ++#define xorto_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(xorto_kappabit_uint) ++ ++#endif // APPLY_NAMESPACE ++ ++#endif // SDITH_NAMESPACE_H +diff --git a/lib/aes/aes128_ctrle.h b/lib/aes/aes128_ctrle.h +index 7685ea9..49c9544 100644 +--- a/lib/aes/aes128_ctrle.h ++++ b/lib/aes/aes128_ctrle.h +@@ -1,5 +1,11 @@ + #ifndef AES128_CTRLE_H + #define AES128_CTRLE_H ++ ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif + #include "rijndael256_ctrle.h" + + #ifdef __cplusplus +diff --git a/lib/aes/aes128_ctrle_special_avx2.c b/lib/aes/aes128_ctrle_special_avx2.c +index 54c6e3f..d443de8 100644 +--- a/lib/aes/aes128_ctrle_special_avx2.c ++++ b/lib/aes/aes128_ctrle_special_avx2.c +@@ -20,6 +20,12 @@ + #include + #include + ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif ++ + /* new round key = g ^ w ^ (w<<4) ^ (w<<8) ^ (w<<12), with g broadcast to all 4 words. + * The w-terms are a byte-word prefix-XOR of w, which factors into log steps: + * a = w ^ (w<<4) -> [w0, w0^w1, w1^w2, w2^w3] +diff --git a/lib/aes/aes128_ctrle_special_ref.c b/lib/aes/aes128_ctrle_special_ref.c +index e74c628..6c3dddd 100644 +--- a/lib/aes/aes128_ctrle_special_ref.c ++++ b/lib/aes/aes128_ctrle_special_ref.c +@@ -3,6 +3,9 @@ + #include "aes128_ctrle.h" + #include "aes_ansi_ref.h" + ++#ifdef SDITH3_FOR_LIBOQS ++#include ++#endif + + /* -------- batched key schedule (ref: just loop the scalar x1) -------- */ + EXPORT void aes128_key_schedule_x1_ref(void* rk0, const void* k0) { aes128_set_key_ref(rk0, k0); } +@@ -31,10 +34,24 @@ static inline void aes128_nocarry_ref_impl(void* out, const void* round_keys, co + ctr128_t ctr; + uint8_t* oo = (uint8_t*)out; + memcpy(ctr.v8, ctr_block, 16); ++#ifndef SDITH3_FOR_LIBOQS ++ /* reference implementation */ + for (uint64_t i = 0; i < nblocks; ++i) { + aes128_encrypt_1block_ref(oo + 16 * i, ctr.v8, round_keys); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } ++#else ++ /* LIBOQS implementation: round_keys caches a schedule pointer (see aes_glue.c), ++ * it is not a raw key. ECB over nblocks*16 bytes is nblocks independent block ++ * encryptions, so the whole counter run goes out in a single call. */ ++ void* schedule = NULL; ++ memcpy(&schedule, round_keys, sizeof(void*)); ++ for (uint64_t i = 0; i < nblocks; ++i) { ++ memcpy(oo + 16 * i, ctr.v8, 16); ++ ctr.v64[0] += 1; // low-64 increment only, no middle carry ++ } ++ OQS_AES128_ECB_enc_sch(oo, 16 * nblocks, schedule, oo); ++#endif + } + EXPORT void aes128_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 1); +diff --git a/lib/aes/aes_ansi_littleendian_ref.c b/lib/aes/aes_ansi_littleendian_ref.c +index 8671f2f..cdb251f 100644 +--- a/lib/aes/aes_ansi_littleendian_ref.c ++++ b/lib/aes/aes_ansi_littleendian_ref.c +@@ -455,3 +455,17 @@ EXPORT void aes128_set_key_ref(void* rk, const void* key128) { rijndaelKeySetupE + EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk) { + rijndaelEncrypt(rk, 10, in_pt128, out_ct128); + } ++ ++EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes) { ++ // no op. schedule is later expanded in-place ++ (void) rk; (void) nslots; (void) slot_bytes; ++} ++ ++EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128) { ++ aes128_set_key_ref(rk, key128); ++} ++ ++EXPORT void aes128_release_key(void* rk) { ++ // no internals to release ++ (void) rk; ++} +diff --git a/lib/aes/aes_ansi_ref.c b/lib/aes/aes_ansi_ref.c +index 7eb5e18..4f02c45 100644 +--- a/lib/aes/aes_ansi_ref.c ++++ b/lib/aes/aes_ansi_ref.c +@@ -470,3 +470,19 @@ EXPORT void aes128_set_key_ref(void* rk, const void* key128) { rijndaelKeySetupE + EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk) { + rijndaelEncrypt(rk, 10, in_pt128, out_ct128); + } ++ ++EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes) { ++ // schedule is expanded in-place; nothing to prepare ++ (void) rk; (void) nslots; (void) slot_bytes; ++} ++ ++EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128) { ++ // rijndaelKeySetupEnc overwrites rk, so a plain set_key is all reuse needs here ++ aes128_set_key_ref(rk, key128); ++} ++ ++ ++EXPORT void aes128_release_key(void *rk) { ++ // no internals to release ++ (void) rk; ++} +diff --git a/lib/aes/aes_ansi_ref.h b/lib/aes/aes_ansi_ref.h +index 8630747..f3ec931 100644 +--- a/lib/aes/aes_ansi_ref.h ++++ b/lib/aes/aes_ansi_ref.h +@@ -1,6 +1,12 @@ + #ifndef AES_ANSI_REF_H + #define AES_ANSI_REF_H + ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif ++ + #ifdef __cplusplus + #define EXPORT extern "C" + #include +@@ -9,9 +15,42 @@ + #include "stdint.h" + #endif + ++/* References implimentations */ ++ + /* aes128 reference implementation of the key scheduling (warning:big endian round keys) */ + EXPORT void aes128_set_key_ref(void* rk, const void* key128); + /* aes128 reference implementation of the encryption (1 single block) */ + EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk); + ++ ++/* LIBOQS integration glue */ ++ ++/* The below functions are either no-ops or just call the above functions when ++ * not building for liboqs. When building for liboqs,`integration/liboqs/aes_glue.c` ++ * impliments these to dispatch to liboqs' AES. ++ * ++ * LIBOQS uses a heap-allocated schedule for each key, so a single schedule ++ * pointer is written into each round-key buffer instead of the round keys ++ * themselves, and that schedule is replaced when the buffer is reused. The ++ * following functions help to prepare, reuse, and release the round-key ++ * buffers. ++ */ ++ ++/* Prepare an nslots x slot_bytes array of round-key buffers. ++ * ++ * Marks every slot empty, so that the first aes128_set_key_reuse_ref call on a ++ * slot loads a schedule and every later one replaces it. ++ */ ++EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes); ++ ++/* Replace the key of the schedule held by a prepared buffer. ++ * ++ * @warning The buffer MUST have been prepared with aes128_prepare_rk_buffer first. ++ */ ++EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128); ++ ++/* Release a key schedule created by aes128_set_key_ref or aes128_set_key_reuse_ref. ++ * A no-op on a prepared buffer whose slot was never keyed. */ ++EXPORT void aes128_release_key(void *rk); ++ + #endif // AES_ANSI_REF_H +diff --git a/lib/aes/rijndael256.h b/lib/aes/rijndael256.h +index 2e5976a..489c897 100644 +--- a/lib/aes/rijndael256.h ++++ b/lib/aes/rijndael256.h +@@ -1,6 +1,14 @@ + #ifndef RIJNDAEL256__H + #define RIJNDAEL256__H + ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif ++ ++#include "sdith_inline.h" ++ + #ifdef __cplusplus + #define EXPORT extern "C" + #include +diff --git a/lib/aes/rijndael256_avx.c b/lib/aes/rijndael256_avx.c +index 88c0bb9..bc9c96d 100644 +--- a/lib/aes/rijndael256_avx.c ++++ b/lib/aes/rijndael256_avx.c +@@ -46,18 +46,18 @@ static const uint8_t r256_rcon[KEY_SCHEDULE_ROUNDS] = {0x01, 0x02, 0x04, 0x08, 0 + // The w-terms are a byte-word prefix-XOR of w, factored into log steps to drop one + // pslldq + one xor per half per round (the schedule is port-5 bound). Byte-identical: + // a = w ^ (w<<4); t = a ^ (a<<8); result = t ^ g. +-static __always_inline __m128i r256_cascade(__m128i w, __m128i g) { ++SDITH_ALWAYS_INLINE __m128i r256_cascade(__m128i w, __m128i g) { + __m128i a = _mm_xor_si128(w, SLL(w, 4)); + __m128i t = _mm_xor_si128(a, SLL(a, 8)); + return _mm_xor_si128(t, g); + } + + // g for the low half (i%8==0): SubWord(RotWord(w7)) ^ rcon, broadcast. +-static __always_inline __m128i r256_g_lo(__m128i hi, int rc) { ++SDITH_ALWAYS_INLINE __m128i r256_g_lo(__m128i hi, int rc) { + return AESENCLAST(SHUF8(hi, R256_RWBC), _mm_set1_epi32(rc)); + } + // g for the high half (i%8==4): SubWord(w3 of the updated lo), broadcast. +-static __always_inline __m128i r256_g_hi(__m128i lo) { ++SDITH_ALWAYS_INLINE __m128i r256_g_hi(__m128i lo) { + return AESENCLAST(SHUF8(lo, R256_WBC), _mm_setzero_si128()); + } + +diff --git a/lib/aes/rijndael256_avx.h b/lib/aes/rijndael256_avx.h +index 0c4d251..f4bd0c4 100644 +--- a/lib/aes/rijndael256_avx.h ++++ b/lib/aes/rijndael256_avx.h +@@ -1,6 +1,14 @@ + #ifndef RIJNDAEL256_AVX2__H + #define RIJNDAEL256_AVX2__H + ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif ++ ++#include "sdith_inline.h" ++ + #ifdef __cplusplus + #define EXPORT extern "C" + #include +diff --git a/lib/aes/rijndael256_ctrle.h b/lib/aes/rijndael256_ctrle.h +index 32fcde5..1ec160c 100644 +--- a/lib/aes/rijndael256_ctrle.h ++++ b/lib/aes/rijndael256_ctrle.h +@@ -1,6 +1,12 @@ + #ifndef RIJNDAEL256_CTRLE_H + #define RIJNDAEL256_CTRLE_H + ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif ++ + #ifdef __cplusplus + #define EXPORT extern "C" + #include +diff --git a/lib/aes/rijndael256_ctrle_special_avx2.c b/lib/aes/rijndael256_ctrle_special_avx2.c +index 44632ab..c2bc7a3 100644 +--- a/lib/aes/rijndael256_ctrle_special_avx2.c ++++ b/lib/aes/rijndael256_ctrle_special_avx2.c +@@ -37,7 +37,7 @@ void rijndael256_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3 + enum { R256_ROUNDS = 14 }; + + /* encrypt n (1..4) interleaved blocks: plaintext in (lo[k],hi[k]) -> ciphertext to out. */ +-static __always_inline void sdith_rij_encN(uint8_t* out, const uint8_t* rk, __m128i* lo, __m128i* hi, int n) { ++SDITH_ALWAYS_INLINE void sdith_rij_encN(uint8_t* out, const uint8_t* rk, __m128i* lo, __m128i* hi, int n) { + const __m128i RMASK = _mm_set_epi32(0x03020d0c, 0x0f0e0908, 0x0b0a0504, 0x07060100); + const __m128i BMASK = _mm_set_epi32(0x80000000, 0x80800000, 0x80800000, 0x80808000); + +@@ -71,7 +71,7 @@ static __always_inline void sdith_rij_encN(uint8_t* out, const uint8_t* rk, __m1 + } + + /* block halves for base with only its low 64 bits incremented by i (no carry). */ +-static __always_inline void sdith_rij_ctr_lo(__m128i base_lo, __m128i base_hi, uint64_t i, // ++SDITH_ALWAYS_INLINE void sdith_rij_ctr_lo(__m128i base_lo, __m128i base_hi, uint64_t i, // + __m128i* lo, __m128i* hi) { + *lo = _mm_add_epi64(base_lo, _mm_set_epi64x(0, (long long)i)); + *hi = base_hi; +diff --git a/lib/aes/rijndael256_ctrle_special_ref.c b/lib/aes/rijndael256_ctrle_special_ref.c +index 15130ab..e5d0e88 100644 +--- a/lib/aes/rijndael256_ctrle_special_ref.c ++++ b/lib/aes/rijndael256_ctrle_special_ref.c +@@ -3,10 +3,6 @@ + #include "rijndael256.h" + #include "rijndael256_ctrle.h" + +-#if defined(_WIN32) || defined(__APPLE__) +-#define __always_inline inline __attribute((always_inline)) +-#endif +- + /* -------- batched key schedule (ref: just loop the scalar x1) -------- */ + EXPORT void rijndael256_key_schedule_x1_ref(void* rk0, const void* k0) { rijndael256_key_schedule_ref(rk0, k0); } + EXPORT void rijndael256_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1) { +diff --git a/lib/sha3/brg_endian.h b/lib/sha3/brg_endian.h +index 2558f87..59432a7 100644 +--- a/lib/sha3/brg_endian.h ++++ b/lib/sha3/brg_endian.h +@@ -1,7 +1,7 @@ + #ifndef _BRG_ENDIAN_H + #define _BRG_ENDIAN_H + +-#include "../endian_compat.h" ++#include "endian_compat.h" + + #if defined(PICNIC_IS_LITTLE_ENDIAN) + #define IS_LITTLE_ENDIAN 1 +diff --git a/src/commons.h b/src/commons.h +index cad5828..d30521b 100644 +--- a/src/commons.h ++++ b/src/commons.h +@@ -1,6 +1,12 @@ + #ifndef COMMONS_H + #define COMMONS_H + ++/* liboqs links one shared copy of this code into every scheme variant, so the ++ * internal symbols need a namespace of their own. See gen_namespace.sh. */ ++#ifdef SDITH3_FOR_LIBOQS ++#include "sdith_namespace.h" ++#endif ++ + #ifdef __cplusplus + #define EXPORT extern "C" + #define EXPORT_DECL extern "C" +@@ -15,6 +21,19 @@ + #define CPU_SUPPORTS(feature) __builtin_cpu_supports(feature) + #endif + ++/* Namespacing with the appropriate prefix */ ++#ifndef SDITH_PUBLIC_API_NAMESPACE ++#ifdef APPLY_PUBLIC_API_NAMESPACE ++#ifndef concat2 ++#define _concat2(a, b) a ## b ++#define concat2(a, b) _concat2(a, b) ++#endif ++#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) ++#else ++#define SDITH_PUBLIC_API_NAMESPACE(s) s ++#endif ++#endif ++ + typedef void bitvec_t; // vector of bits row major (dimensions provided at runtime) + typedef void bitmat_t; // matrix of bits row major (dimensions provided at runtime) + typedef void flambda_t; // at runtime, the size of a big fielf elem is lam (i.e. lambda/8) +diff --git a/src/gf128.c b/src/gf128.c +index 26a4bd1..9bc5a9a 100644 +--- a/src/gf128.c ++++ b/src/gf128.c +@@ -4,11 +4,11 @@ + const gf128 GF128_ZERO = {.v128 = 0}; + const gf128 GF128_ONE = {.v128 = 1}; + +-__always_inline uint8_t gf128p_equals(const gf128* const a, const gf128* const b) { return a->v128 == b->v128; } ++SDITH_ALWAYS_INLINE uint8_t gf128p_equals(const gf128* const a, const gf128* const b) { return a->v128 == b->v128; } + + void gf128p_sum(gf128* const res, const gf128* const a, const gf128* const b) { gf128_sum_ref(res, a, b); } + +-__always_inline uint8_t gf128p_bitof(const gf128* const a, const uint64_t position) { ++SDITH_ALWAYS_INLINE uint8_t gf128p_bitof(const gf128* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 128, "bad bit position %" PRIu64, position); + return (a->v128 >> position) & 1; + } +diff --git a/src/gf128_avx2.c b/src/gf128_avx2.c +index 87122d7..eb5e42a 100644 +--- a/src/gf128_avx2.c ++++ b/src/gf128_avx2.c +@@ -66,7 +66,7 @@ EXPORT void gf128_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, + // res = sum_i x[i . x_byte_slice]*y[i] (accumulated on top of res if accumulate). + // The clmul products are aggregated per Karatsuba term across the whole vector + // (3 accumulators) and a single reduction is done at the end. +-static __always_inline void gf128_dot_product_core_pclmul(gf128* res, const uint8_t* x, const uint64_t x_byte_slice, ++SDITH_ALWAYS_INLINE void gf128_dot_product_core_pclmul(gf128* res, const uint8_t* x, const uint64_t x_byte_slice, + const gf128* y, const uint64_t size, + const int accumulate) { + const __m128i p = _mm_set_epi64x(0, GF128_P); +diff --git a/src/gf192.c b/src/gf192.c +index 6358026..f42ab6c 100644 +--- a/src/gf192.c ++++ b/src/gf192.c +@@ -9,15 +9,15 @@ + const gf192 GF192_ZERO = {.v64 = {0, 0, 0}}; + const gf192 GF192_ONE = {.v64 = {1, 0, 0}}; + +-__always_inline uint8_t gf192p_equals(const gf192* const a, const gf192* const b) { ++SDITH_ALWAYS_INLINE uint8_t gf192p_equals(const gf192* const a, const gf192* const b) { + return memcmp(a->v, b->v, 24) == 0; + } + +-__always_inline void gf192p_sum(gf192* const res, const gf192* const a, const gf192* const b) { ++SDITH_ALWAYS_INLINE void gf192p_sum(gf192* const res, const gf192* const a, const gf192* const b) { + gf192_sum_ref(res, a, b); + } + +-__always_inline uint8_t gf192p_bitof(const gf192* const a, const uint64_t position) { ++SDITH_ALWAYS_INLINE uint8_t gf192p_bitof(const gf192* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 192, "bad bit position %" PRIu64, position); + const uint64_t q8 = position >> 3; + const uint64_t r8 = position & 7; +@@ -66,7 +66,7 @@ void gf192p_rsh(gf192* const res, const gf192* const a, const uint64_t amount) { + res->v64[2] = o[2]; + } + +-__always_inline void gf192p_mul(gf192* const res, const gf192* const a, const gf192* const b) { ++SDITH_ALWAYS_INLINE void gf192p_mul(gf192* const res, const gf192* const a, const gf192* const b) { + gf192_product_ref(res, a, b); + } + +diff --git a/src/gf192_avx2.c b/src/gf192_avx2.c +index 1080de2..d2fe408 100644 +--- a/src/gf192_avx2.c ++++ b/src/gf192_avx2.c +@@ -162,7 +162,7 @@ EXPORT void gf192_flambda_product_pclmul(flambda_t* res, const flambda_t* a, con + // res = sum_i x[i . x_byte_slice]*y[i] (accumulated on top of res if accumulate). + // The clmul products are aggregated per Karatsuba term across the whole vector + // (6 accumulators) and a single reduction is done at the end. +-static __always_inline void gf192_dot_product_core_pclmul(gf192* res, const uint8_t* x, const uint64_t x_byte_slice, ++SDITH_ALWAYS_INLINE void gf192_dot_product_core_pclmul(gf192* res, const uint8_t* x, const uint64_t x_byte_slice, + const gf192* y, const uint64_t size, + const int accumulate) { + const __m128i p = _mm_set_epi64x(0, GF192_P); +diff --git a/src/gf256.c b/src/gf256.c +index f4db445..0864013 100644 +--- a/src/gf256.c ++++ b/src/gf256.c +@@ -9,15 +9,15 @@ + const gf256 GF256_ZERO = {.v64 = {0, 0, 0, 0}}; + const gf256 GF256_ONE = {.v64 = {1, 0, 0, 0}}; + +-__always_inline uint8_t gf256p_equals(const gf256* const a, const gf256* const b) { ++SDITH_ALWAYS_INLINE uint8_t gf256p_equals(const gf256* const a, const gf256* const b) { + return memcmp(a->v, b->v, 32) == 0; + } + +-__always_inline void gf256p_sum(gf256* const res, const gf256* const a, const gf256* const b) { ++SDITH_ALWAYS_INLINE void gf256p_sum(gf256* const res, const gf256* const a, const gf256* const b) { + gf256_sum_ref(res, a, b); + } + +-__always_inline uint8_t gf256p_bitof(const gf256* const a, const uint64_t position) { ++SDITH_ALWAYS_INLINE uint8_t gf256p_bitof(const gf256* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 256, "bad bit position %" PRIu64, position); + const uint64_t q8 = position >> 3; + const uint64_t r8 = position & 7; +@@ -66,7 +66,7 @@ void gf256p_rsh(gf256* const res, const gf256* const a, const uint64_t amount) { + res->v64[3] = o[3]; + } + +-__always_inline void gf256p_mul(gf256* const res, const gf256* const a, const gf256* const b) { ++SDITH_ALWAYS_INLINE void gf256p_mul(gf256* const res, const gf256* const a, const gf256* const b) { + gf256_product_ref(res, a, b); + } + +diff --git a/src/gf256_avx2.c b/src/gf256_avx2.c +index 026cc49..c76eea1 100644 +--- a/src/gf256_avx2.c ++++ b/src/gf256_avx2.c +@@ -182,7 +182,7 @@ EXPORT void gf256_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, + // res = sum_i x[i . x_byte_slice]*y[i] (accumulated on top of res if accumulate). + // The clmul products are aggregated per Karatsuba term across the whole vector + // (10 accumulators) and a single reduction is done at the end. +-static __always_inline void gf256_dot_product_core_pclmul(gf256* res, const uint8_t* x, const uint64_t x_byte_slice, ++SDITH_ALWAYS_INLINE void gf256_dot_product_core_pclmul(gf256* res, const uint8_t* x, const uint64_t x_byte_slice, + const gf256* y, const uint64_t size, + const int accumulate) { + const __m128i p = _mm_set_epi64x(0, GF256_P); +diff --git a/src/ggm.c b/src/ggm.c +index cdc2d56..3d8b305 100644 +--- a/src/ggm.c ++++ b/src/ggm.c +@@ -55,7 +55,6 @@ uint32_t floor_log2i_compat(uint32_t x) { + } + if (t >> 1) { + res += 1; +- t >>= 1; + } + return res; + } +@@ -116,7 +115,7 @@ void quickSort(uint32_t arr[], int low, int high) { + } + } + +-__always_inline uint32_t extract_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, const uint64_t* data) { ++SDITH_ALWAYS_INLINE uint32_t extract_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, const uint64_t* data) { + const uint64_t kappa_mask = (UINT64_C(1) << kappa) - 1; + uint64_t limb_pos = bitpos >> 6; + uint64_t limb_rem = bitpos & UINT64_C(63); +@@ -126,7 +125,7 @@ __always_inline uint32_t extract_kappabit_uint_inline(uint64_t kappa, uint64_t b + return ((data[limb_pos] >> limb_rem) | (data[limb_pos + 1] << (64 - limb_rem))) & kappa_mask; + } + } +-__always_inline void xorto_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, uint64_t* data, uint64_t value) { ++SDITH_ALWAYS_INLINE void xorto_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, uint64_t* data, uint64_t value) { + const uint64_t kappa_mask = (UINT64_C(1) << kappa) - 1; + uint64_t limb_pos = bitpos >> 6; + uint64_t limb_rem = bitpos & UINT64_C(63); +diff --git a/src/matrix_transpose_f2.c b/src/matrix_transpose_f2.c +index a97f737..1c11df9 100644 +--- a/src/matrix_transpose_f2.c ++++ b/src/matrix_transpose_f2.c +@@ -51,7 +51,7 @@ EXPORT void transpose_256_256_naive(void* out, const void* in) { + } + } + +-__always_inline void transpose8(uint8_t *a, uint64_t stride) { ++SDITH_ALWAYS_INLINE void transpose8(uint8_t *a, uint64_t stride) { + int j, k; + uint64_t m, t; + m = 0x0F; +@@ -64,7 +64,7 @@ __always_inline void transpose8(uint8_t *a, uint64_t stride) { + } + } + +-__always_inline void transpose64(uint64_t *a, uint64_t stride) { ++SDITH_ALWAYS_INLINE void transpose64(uint64_t *a, uint64_t stride) { + int j, k; + uint64_t m, t; + m = 0x00000000FFFFFFFFULL; +@@ -77,7 +77,8 @@ __always_inline void transpose64(uint64_t *a, uint64_t stride) { + } + } + +-__always_inline void transpose64_unaligned(uint8_t *a, uint64_t byte_stride) ++/* Not called anywhere in the current build; kept as a utility. */ ++SDITH_MAYBE_UNUSED SDITH_ALWAYS_INLINE void transpose64_unaligned(uint8_t *a, uint64_t byte_stride) + { + uint64_t tmp[64]; + for (size_t i = 0; i < 64; i++) +@@ -91,7 +92,7 @@ __always_inline void transpose64_unaligned(uint8_t *a, uint64_t byte_stride) + } + } + +-__always_inline void transpose128(__uint128_t *a, uint64_t stride) { ++SDITH_ALWAYS_INLINE void transpose128(__uint128_t *a, uint64_t stride) { + int j, k; + __uint128_t m, t; + m = 1; +diff --git a/src/matrix_vector_products_f2.c b/src/matrix_vector_products_f2.c +index 62a8ef9..ee9f5d5 100755 +--- a/src/matrix_vector_products_f2.c ++++ b/src/matrix_vector_products_f2.c +@@ -15,7 +15,7 @@ static inline uint8_t bitvec_get_value(const bitvec_t* v, uint64_t idx) { + return ( (vec[idx/8] >> (idx%8)) & 1 ); + } + +-static __always_inline void bitvec_xor_inline_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, ++SDITH_ALWAYS_INLINE void bitvec_xor_inline_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, + const bitvec_t* b) { + uint8_t* r = (uint8_t*)res; + const uint8_t* aa = (uint8_t*)a; +diff --git a/src/rsd.c b/src/rsd.c +index 2e251c1..b200730 100644 +--- a/src/rsd.c ++++ b/src/rsd.c +@@ -62,6 +62,7 @@ EXPORT void rsd_generate_random_instance_ref( // + uint32_t quo; + vole_params->ct.div_rem_u32(&quo, &solution[i], pos, npw); + } ++ vole_params->keygen_rng.release(&sk_rng); + // prepare the pk_rng to draw rows of h (row-wise matrix prng) + matrix_rng_t pk_rng; + vole_params->matrix_prg.matrix_rng_init(&pk_rng, pk_seed, rsd_codim); +@@ -88,6 +89,7 @@ EXPORT void rsd_generate_random_instance_ref( // + // mask, but the position must stay inside y for the debug range check) + vole_params->ct.bitvec_xorbit(y, col_bytes, real_index & in_id, in_id); + } ++ vole_params->matrix_prg.matrix_rng_release(&pk_rng); + } + + /** expand the public key from the pubkey seed */ +@@ -126,6 +128,7 @@ EXPORT void rsd_expand_public_key_ref( // + vole_params->matrix_prg.matrix_rng_get_row(&h_rng, hh + h_slice_bytes * i, i); + } + } ++ vole_params->matrix_prg.matrix_rng_release(&h_rng); + } + + EXPORT uint64_t rsd_public_key_times_challenge_tmp_bytes(const vole_parameters* vole_params, // +@@ -211,8 +214,11 @@ EXPORT void rsd_public_key_times_challenge_ref( // + vole_params->matrix_prg.matrix_rng_init(&h_rng, pk_seed, rsd_codim); + vole_params->matrix_prg.matrix_rng_preprocess_chall(&h_rng, scratch, chall_a); + vole_params->matrix_prg.matrix_rng_rows_times_chall(&h_rng, dest, scratch, 0, n_minus_k); ++ vole_params->matrix_prg.matrix_rng_release(&h_rng); ++#ifndef NDEBUG + dest += n_minus_k * lambda_bytes; + CASSERT(dest == chall_a_H + rsd_n * lambda_bytes, "bug!"); ++#endif // NDEBUG + } + + /** unary encoding of the solution (for mux circuits). Constant-time in the +diff --git a/src/sdith_prng.c b/src/sdith_prng.c +index 4edd685..743a82e 100644 +--- a/src/sdith_prng.c ++++ b/src/sdith_prng.c +@@ -3,9 +3,18 @@ + #include + #include + ++#ifdef SDITH3_FOR_LIBOQS ++#include "aes128_ctrle.h" ++#include "aes_ansi_ref.h" ++#include "fips202_glue.h" ++#include "fips202x4_glue.h" ++#else + #include "../aes/aes128_ctrle.h" ++#include "../aes/aes_ansi_ref.h" + #include "../sha3/KeccakHash.h" + #include "../sha3/KeccakHashtimes4.h" ++#endif ++ + #include "rijndael256_ctrle.h" + #include "sdith_prng_private.h" + #include "vole_private.h" +@@ -59,7 +68,9 @@ GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref, // + // mirrors the raw commit/vole paths exactly, so outputs stay byte-identical. + // --------------------------------------------------------------------------- + EXPORT void extend_leaf_seed_cat1_aes128_ref(void* extended_seed_out, const void* seed128) { +- aes128_key_schedule_x1_ref(extended_seed_out, seed128); ++ // When building for liboqs, this allows allows key schedule reuse (see `aes_ansi_ref.h`) ++ // Requires the buffer to have been passed to aes128_prepare_rk_buffer first. ++ aes128_set_key_reuse_ref(extended_seed_out, seed128); + } + EXPORT void extend_leaf_seed_cat3_rijndael256_ref(void* extended_seed_out, const void* seed192) { + uint8_t key256[32] = {}; // k || 0^64 +@@ -89,6 +100,16 @@ EXPORT void extend_leaf_seed_cat5_rijndael256_4x_ref(void* extended_seed_out, co + for (int i = 0; i < 4; i++) extend_leaf_seed_cat5_rijndael256_ref(out + i * RIJNDAEL256_RK_BYTES, s + i * 32); + } + ++EXPORT void prepare_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes) { ++ aes128_prepare_rk_buffer(buf, nslots, slot_bytes); ++} ++EXPORT void release_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes) { ++ uint8_t* p = (uint8_t*) buf; ++ for (uint64_t i = 0; i < nslots; ++i) aes128_release_key(p + i * slot_bytes); ++} ++EXPORT void extseed_buf_noop(void* buf, uint64_t nslots, uint64_t slot_bytes) { ++ (void) buf; (void) nslots; (void) slot_bytes; // rijndael256: schedule is in-place ++} + + EXPORT uint64_t extended_node_seed_bytes_cat1_aes128(void) { return 16 * 11; } + EXPORT uint64_t extended_node_seed_bytes_cat3_rijndael256(void) { return RIJNDAEL256_RK_BYTES; } +@@ -212,6 +233,21 @@ EXPORT void xof_finalize_and_output_shake256(xof_ctx* xof, void* out, uint64_t o + Keccak_HashSqueeze(inst, out, out_bytes << 3); + } + ++EXPORT void xof_ctx_release_shake128(xof_ctx* xof) { ++ #ifndef SDITH3_FOR_LIBOQS ++ (void)xof; // no-op ++ #else ++ OQS_SHA3_shake128_inc_ctx_release(&xof->shake128_state); ++ #endif ++} ++EXPORT void xof_ctx_release_shake256(xof_ctx* xof) { ++ #ifndef SDITH3_FOR_LIBOQS ++ (void)xof; // no-op ++ #else ++ OQS_SHA3_shake256_inc_ctx_release(&xof->shake256_state); ++ #endif ++} ++ + // vector shake function + + static const uint64_t SINGLE_XOF_STRIDE = (sizeof(KeccakWidth1600_SpongeInstance) + 31) & UINT64_C(-32); +@@ -316,6 +352,43 @@ EXPORT void xof_vector_finalize_and_output_shake256(xof_vector_ctx* xof, uint64_ + xof_vector_finalize_and_output_shake128(xof, num_xofs, out_hashes, hash_bytes); // same + } + ++EXPORT void xof_vector_ctx_release_shake128(xof_vector_ctx* xof, uint64_t num_xofs) { ++ #ifndef SDITH3_FOR_LIBOQS ++ (void)xof; // no-op ++ (void)num_xofs; // no-op ++ #else ++ const uint64_t num_batches = num_xofs >> UINT64_C(2); ++ const uint64_t num_remainder = num_xofs & UINT64_C(3); ++ void* sbase = BATCH_XOF(xof, num_batches); ++ for (uint64_t b = 0; b < num_batches; ++b) { ++ KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); ++ OQS_SHA3_shake128_x4_inc_ctx_release(&inst->shake128_state); ++ } ++ for (uint64_t r = 0; r < num_remainder; ++r) { ++ KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); ++ OQS_SHA3_shake128_inc_ctx_release(&inst->shake128_state); ++ } ++ #endif ++} ++EXPORT void xof_vector_ctx_release_shake256(xof_vector_ctx* xof, uint64_t num_xofs) { ++ #ifndef SDITH3_FOR_LIBOQS ++ (void)xof; // no-op ++ (void)num_xofs; // no-op ++ #else ++ const uint64_t num_batches = num_xofs >> UINT64_C(2); ++ const uint64_t num_remainder = num_xofs & UINT64_C(3); ++ void* sbase = BATCH_XOF(xof, num_batches); ++ for (uint64_t b = 0; b < num_batches; ++b) { ++ KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); ++ OQS_SHA3_shake256_x4_inc_ctx_release(&inst->shake256_state); ++ } ++ for (uint64_t r = 0; r < num_remainder; ++r) { ++ KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); ++ OQS_SHA3_shake256_inc_ctx_release(&inst->shake256_state); ++ } ++ #endif ++} ++ + // cipher-based proof of work + + EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat1() { return sizeof(struct proofow_state128_t); } +@@ -339,6 +412,7 @@ EXPORT void proofow_init_cipher_cat1_ref( // + xof_seed_shake128(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake128(&xof); + xof_output_shake128(&xof, s->p, 64); // covers p0,p1,k0,k1 ++ xof_ctx_release_shake128(&xof); + s->p[0].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 +@@ -364,6 +438,7 @@ EXPORT int proofow_grind_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_ + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake128(&xof); + *ctr_in_out = ctr; + return 1; + } +@@ -390,9 +465,21 @@ EXPORT int proofow_verify_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake128(&xof); + return 1; + } + ++EXPORT void proofow_release_cipher_cat1_ref(proofow_ctx_t* proofow_state) { ++ struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; ++ aes128_release_key(s->rk[0]); ++ aes128_release_key(s->rk[1]); ++} ++ ++// Shared by every proof-of-work variant that holds no schedule of its own: the ++// cat3/cat5 cipher ones expand rijndael256 in place, the avx cat1 one expands ++// aes128 in place, and the shake ones run no cipher at all. ++EXPORT void proofow_release_noop(proofow_ctx_t* proofow_state) { (void)proofow_state; } ++ + // cipher-based proof of work (cat5: rijndael256 block cipher + shake256 xof) + + EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat5() { return sizeof(struct proofow_state256_t); } +@@ -416,6 +503,7 @@ EXPORT void proofow_init_cipher_cat5_ref( // + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) ++ xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 +@@ -441,6 +529,7 @@ EXPORT int proofow_grind_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_ + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } +@@ -467,6 +556,7 @@ EXPORT int proofow_verify_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + return 1; + } + +@@ -495,6 +585,7 @@ EXPORT void proofow_init_cipher_cat3_ref( // + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) ++ xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 +@@ -520,6 +611,7 @@ EXPORT int proofow_grind_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_ + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } +@@ -546,6 +638,7 @@ EXPORT int proofow_verify_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + return 1; + } + +@@ -581,6 +674,7 @@ EXPORT int proofow_grind_w_shake_cat1( // + xof_init_and_seed_shake128(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&ctx, &ctr, 4); + xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ xof_ctx_release_shake128(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); +@@ -604,6 +698,7 @@ EXPORT int proofow_verify_w_shake_cat1( // + xof_init_and_seed_shake128(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&ctx, &ctr, 4); + xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ xof_ctx_release_shake128(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; +@@ -639,6 +734,7 @@ EXPORT int proofow_grind_w_shake_cat3( // + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); +@@ -662,6 +758,7 @@ EXPORT int proofow_verify_w_shake_cat3( // + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; +@@ -696,7 +793,8 @@ EXPORT int proofow_grind_w_shake_cat5( // + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); +- xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); +@@ -719,9 +817,13 @@ EXPORT int proofow_verify_w_shake_cat5( // + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); +- xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); +- if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; ++ xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); ++ if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) { ++ xof_ctx_release_shake256(&ctx); ++ return 0; ++ } + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&ctx); + return 1; + } + +@@ -752,8 +854,10 @@ EXPORT int proofow_verify_w_shake_cat5( // + if (extract_kappabit_uint(s->w, s->kappa_tau, buf[j]) == 0) { \ + *ctr_in_out = ctr + j; \ + memcpy(delta0_out, buf[j], s->delta0_out_bytes); \ ++ xof_vector_ctx_release_##SHAKE(xv, 4); \ + return 1; \ + } \ ++ xof_vector_ctx_release_##SHAKE(xv, 4); \ + } \ + for (; ctr < CTR_MAX; ctr++) { /* <4 tail, byte-identical scalar path */ \ + xof_ctx c __attribute((aligned(16))); \ +@@ -763,8 +867,10 @@ EXPORT int proofow_verify_w_shake_cat5( // + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { \ + *ctr_in_out = ctr; \ + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); \ ++ xof_ctx_release_##SHAKE(&c); \ + return 1; \ + } \ ++ xof_ctx_release_##SHAKE(&c); \ + } \ + return 0; \ + } +@@ -809,6 +915,14 @@ EXPORT void matrix_rng_init_rijndael256_cat5_ref(matrix_rng_t* rng, const seed_t + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); + } + ++EXPORT void matrix_rng_release_aes128_cat1_ref(matrix_rng_t* rng) { ++ struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; ++ aes128_release_key(r->rk); ++} ++ ++// cat3/cat5 (and the avx cat1 path) expand their schedule inside the context. ++EXPORT void matrix_rng_release_noop(matrix_rng_t* rng) { (void)rng; } ++ + EXPORT void matrix_rng_get_row_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); +@@ -1024,6 +1138,14 @@ EXPORT void keygen_rng_init_rijndael256_cat5_ref(keygen_rng_ctx* rng, const seed + KEYGEN_RNG_INIT_EMPTY(s); + } + ++EXPORT void keygen_rng_release_aes128_cat1_ref(keygen_rng_ctx* rng) { ++ struct keygen_rng_aes128_cat1_t* s = (struct keygen_rng_aes128_cat1_t*) rng; ++ aes128_release_key(s->rk); ++} ++ ++// cat3/cat5 (and the avx cat1 path) expand their schedule inside the context. ++EXPORT void keygen_rng_release_noop(keygen_rng_ctx* rng) { (void)rng; } ++ + DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_aes128_cat1_ref, keygen_rng_aes128_cat1_t, ctr128_t, + aes128_ctrle_nocarry_nblocks_ref) + DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_rijndael256_ref, keygen_rng_rijndael256_t, ctr256_t, +diff --git a/src/sdith_prng.h b/src/sdith_prng.h +index 18aa7c4..88cb8ec 100644 +--- a/src/sdith_prng.h ++++ b/src/sdith_prng.h +@@ -3,6 +3,10 @@ + + #include "commons.h" + ++#ifdef SDITH3_FOR_LIBOQS ++#include ++#endif ++ + /** + * Domain separation of the GGM tree and vole PRNGs. + * +@@ -38,6 +42,15 @@ typedef int PROOFOW_VERIFY_W_F( // + bitvec_t* delta0_out, // + const uint64_t ctr_value // + ); ++/** proof of work: release whatever the init took hold of */ ++typedef void PROOFOW_RELEASE_F(proofow_ctx_t* proofow_state); ++// Only the cat1 cipher variant owns anything: its two aes128 schedules are heap ++// contexts on the liboqs backend (see aes_ansi_ref.h). The cat3/cat5 cipher ++// variants expand rijndael256 in place, the avx cat1 one expands aes128 in ++// place, and the shake variants hold no cipher state at all, so all of those ++// take proofow_release_noop. ++EXPORT void proofow_release_cipher_cat1_ref(proofow_ctx_t* proofow_state); ++EXPORT void proofow_release_noop(proofow_ctx_t* proofow_state); + EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat1(); + EXPORT void proofow_init_cipher_cat1_ref( // + proofow_ctx_t* proofow_state, // +@@ -195,6 +208,14 @@ typedef uint64_t EXTENDED_NODE_SEED_BYTES_F(void); + typedef void EXTEND_LEAF_SEED_4X_F(void* extended_seed_out, const void* node_seed); + + EXPORT void extend_leaf_seed_cat1_aes128_ref(void* extended_seed_out, const void* seed128); ++ ++/** When building for liboqs, cat1 aes128 uses the liboqs backend, which requires ++ * the extended-seed buffer to be prepared/released. See aes_ansi_ref.h for details. */ ++typedef void EXTSEED_BUF_F(void* buf, uint64_t nslots, uint64_t slot_bytes); ++ ++EXPORT void prepare_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes); ++EXPORT void release_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes); ++EXPORT void extseed_buf_noop(void* buf, uint64_t nslots, uint64_t slot_bytes); + EXPORT void extend_leaf_seed_cat1_aes128_avx2(void* extended_seed_out, const void* seed128); + EXPORT void extend_leaf_seed_cat3_rijndael256_ref(void* extended_seed_out, const void* seed192); + EXPORT void extend_leaf_seed_cat3_rijndael256_avx2(void* extended_seed_out, const void* seed192); +@@ -259,9 +280,20 @@ EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_ref(void* out, uint64_t out_byte + EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx); + ++ ++#ifndef SDITH3_FOR_LIBOQS + typedef struct xof_ctx_t { + uint64_t DUMMY[224 / 8]; + } xof_ctx; ++#else ++typedef struct xof_ctx_t { ++ uint32_t shake; // 128 or 256, set by Keccak_HashInitialize_SHAKE* ++ union { ++ OQS_SHA3_shake128_inc_ctx shake128_state; ++ OQS_SHA3_shake256_inc_ctx shake256_state; ++ }; ++} xof_ctx; ++#endif + + typedef void XOF_INIT_F(xof_ctx* xof); + EXPORT void xof_init_shake128(xof_ctx* xof); +@@ -288,6 +320,11 @@ typedef void XOF_FINALIZE_AND_OUTPUT_F(xof_ctx* xof, void* out, uint64_t out_byt + EXPORT void xof_finalize_and_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes); + EXPORT void xof_finalize_and_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes); + ++// liboqs requires context be released. When not using liboqs, context is on the stack and this is a no-op. ++typedef void XOF_CTX_RELEASE_F(xof_ctx* xof); ++EXPORT void xof_ctx_release_shake128(xof_ctx* xof); ++EXPORT void xof_ctx_release_shake256(xof_ctx* xof); ++ + typedef struct xof_functions_t { + XOF_INIT_F* xof_init; + XOF_SEED_F* xof_seed; +@@ -295,6 +332,7 @@ typedef struct xof_functions_t { + XOF_OUTPUT_F* xof_output; + XOF_INIT_AND_SEED_F* xof_init_and_seed; + XOF_FINALIZE_AND_OUTPUT_F* xof_finalize_and_output; ++ XOF_CTX_RELEASE_F* xof_ctx_release; + } xof_functions; + + static const xof_functions xof_shake128 = { +@@ -303,7 +341,8 @@ static const xof_functions xof_shake128 = { + xof_finalize_shake128, // + xof_output_shake128, // + xof_init_and_seed_shake128, // +- xof_finalize_and_output_shake128 // ++ xof_finalize_and_output_shake128, // ++ xof_ctx_release_shake128 // + }; + static const xof_functions xof_shake256 = { + xof_init_shake256, // +@@ -311,7 +350,8 @@ static const xof_functions xof_shake256 = { + xof_finalize_shake256, // + xof_output_shake256, // + xof_init_and_seed_shake256, // +- xof_finalize_and_output_shake256 // ++ xof_finalize_and_output_shake256, // ++ xof_ctx_release_shake256 // + }; + + typedef struct xof_vector_ctx_t xof_vector_ctx; +@@ -332,25 +372,33 @@ typedef void XOF_VECTOR_FINALIZE_AND_OUTPUT_F(xof_vector_ctx* xof, uint64_t num_ + EXPORT void xof_vector_finalize_and_output_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); + EXPORT void xof_vector_finalize_and_output_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); + ++// liboqs requires context be released. When not using liboqs, context is on the stack and this is a no-op. ++typedef void XOF_VECTOR_CTX_RELEASE_F(xof_vector_ctx* xof, uint64_t num_xofs); ++EXPORT void xof_vector_ctx_release_shake128(xof_vector_ctx* xof, uint64_t num_xofs); ++EXPORT void xof_vector_ctx_release_shake256(xof_vector_ctx* xof, uint64_t num_xofs); ++ + typedef struct xof_vector_functions_t { + XOF_VECTOR_CTX_BYTES_F* ctx_bytes; + XOF_VECTOR_INIT_AND_SEED_F* init_and_seed; + XOF_VECTOR_SEED_F* seed; + XOF_VECTOR_FINALIZE_AND_OUTPUT_F* finalize_and_output; ++ XOF_VECTOR_CTX_RELEASE_F* ctx_release; + } xof_vector_functions; + + static const xof_vector_functions xof_vector_shake128 = { + xof_vector_ctx_bytes_shake128, // + xof_vector_init_and_seed_shake128, // + xof_vector_seed_shake128, // +- xof_vector_finalize_and_output_shake128 // ++ xof_vector_finalize_and_output_shake128, // ++ xof_vector_ctx_release_shake128 // + }; + + static const xof_vector_functions xof_vector_shake256 = { + xof_vector_ctx_bytes_shake256, // + xof_vector_init_and_seed_shake256, // + xof_vector_seed_shake256, // +- xof_vector_finalize_and_output_shake256 // ++ xof_vector_finalize_and_output_shake256, // ++ xof_vector_ctx_release_shake256 // + }; + + +@@ -366,6 +414,14 @@ EXPORT void matrix_rng_init_rijndael256_cat3_avx(matrix_rng_t* rng, const seed_t + EXPORT void matrix_rng_init_rijndael256_cat5_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); + EXPORT void matrix_rng_init_rijndael256_cat5_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); + ++// Releases whatever matrix_rng_init took hold of. ++// Only active in the cat1 aes128 ref path when building for liboqs, where key schedules ++// are heap-allocated (see aes_ansi_ref.h for details). ++// The avx and rijndael256 paths expand in place, so they take matrix_rng_release_noop. ++typedef void MATRIX_RNG_RELEASE(matrix_rng_t* rng); ++EXPORT void matrix_rng_release_aes128_cat1_ref(matrix_rng_t* rng); ++EXPORT void matrix_rng_release_noop(matrix_rng_t* rng); ++ + typedef void MATRIX_RNG_GET_ROW(const matrix_rng_t* rng, void* out, const uint64_t row_index); + EXPORT void matrix_rng_get_row_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); + EXPORT void matrix_rng_get_row_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); +@@ -469,6 +525,7 @@ EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_avx(const matrix_rng_t* + // rather than falling back to the get_rows + flambda_dot_product pair. + typedef struct matrix_rng_functions_t { + MATRIX_RNG_INIT* matrix_rng_init; ++ MATRIX_RNG_RELEASE* matrix_rng_release; + MATRIX_RNG_GET_ROW* matrix_rng_get_row; + MATRIX_RNG_GET_ROWS* matrix_rng_get_rows; + MATRIX_RNG_PREPROCESS_CHALL* matrix_rng_preprocess_chall; +@@ -477,6 +534,7 @@ typedef struct matrix_rng_functions_t { + + static const matrix_rng_functions matrix_rng_cat1_aes128_ref = { + matrix_rng_init_aes128_cat1_ref, // ++ matrix_rng_release_aes128_cat1_ref, // + matrix_rng_get_row_aes128_cat1_ref, // + matrix_rng_get_rows_aes128_cat1_ref, // + matrix_rng_preprocess_chall_aes128_cat1_ref, // +@@ -484,6 +542,7 @@ static const matrix_rng_functions matrix_rng_cat1_aes128_ref = { + }; + static const matrix_rng_functions matrix_rng_cat3_rijndael256_ref = { + matrix_rng_init_rijndael256_cat3_ref, // ++ matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat3_ref, // + matrix_rng_get_rows_rijndael256_cat3_ref, // + matrix_rng_preprocess_chall_rijndael256_cat3_ref, // +@@ -491,6 +550,7 @@ static const matrix_rng_functions matrix_rng_cat3_rijndael256_ref = { + }; + static const matrix_rng_functions matrix_rng_cat5_rijndael256_ref = { + matrix_rng_init_rijndael256_cat5_ref, // ++ matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat5_ref, // + matrix_rng_get_rows_rijndael256_cat5_ref, // + matrix_rng_preprocess_chall_rijndael256_cat5_ref, // +@@ -501,6 +561,7 @@ static const matrix_rng_functions matrix_rng_cat5_rijndael256_ref = { + #if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) + static const matrix_rng_functions matrix_rng_cat1_aes128_avx = { + matrix_rng_init_aes128_cat1_avx, // ++ matrix_rng_release_noop, // + matrix_rng_get_row_aes128_cat1_avx, // + matrix_rng_get_rows_aes128_cat1_avx, // + matrix_rng_preprocess_chall_aes128_cat1_avx, // +@@ -508,6 +569,7 @@ static const matrix_rng_functions matrix_rng_cat1_aes128_avx = { + }; + static const matrix_rng_functions matrix_rng_cat3_rijndael256_avx = { + matrix_rng_init_rijndael256_cat3_avx, // ++ matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat3_avx, // + matrix_rng_get_rows_rijndael256_cat3_avx, // + matrix_rng_preprocess_chall_rijndael256_cat3_avx, // +@@ -515,6 +577,7 @@ static const matrix_rng_functions matrix_rng_cat3_rijndael256_avx = { + }; + static const matrix_rng_functions matrix_rng_cat5_rijndael256_avx = { + matrix_rng_init_rijndael256_cat5_avx, // ++ matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat5_avx, // + matrix_rng_get_rows_rijndael256_cat5_avx, // + matrix_rng_preprocess_chall_rijndael256_cat5_avx, // +@@ -552,34 +615,47 @@ EXPORT uint32_t keygen_rng_next_u32_aes128_cat1_avx(keygen_rng_ctx* rng); + EXPORT uint32_t keygen_rng_next_u32_rijndael256_ref(keygen_rng_ctx* rng); + EXPORT uint32_t keygen_rng_next_u32_rijndael256_avx(keygen_rng_ctx* rng); + ++// Releases whatever keygen_rng_init took hold of: as for matrix_rng, only the ++// cat1 aes128 ref path owns a schedule. ++typedef void KEYGEN_RNG_RELEASE(keygen_rng_ctx* rng); ++EXPORT void keygen_rng_release_aes128_cat1_ref(keygen_rng_ctx* rng); ++EXPORT void keygen_rng_release_noop(keygen_rng_ctx* rng); ++ + typedef struct keygen_rng_functions_t { + KEYGEN_RNG_INIT* init; ++ KEYGEN_RNG_RELEASE* release; + KEYGEN_RNG_NEXT_U32* next_u32; + } keygen_rng_functions; + + static const keygen_rng_functions keygen_rng_cat1_aes128_ref = { + keygen_rng_init_aes128_cat1_ref, // ++ keygen_rng_release_aes128_cat1_ref, // + keygen_rng_next_u32_aes128_cat1_ref, // + }; + static const keygen_rng_functions keygen_rng_cat3_rijndael256_ref = { + keygen_rng_init_rijndael256_cat3_ref, // ++ keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_ref, // + }; + static const keygen_rng_functions keygen_rng_cat5_rijndael256_ref = { + keygen_rng_init_rijndael256_cat5_ref, // ++ keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_ref, // + }; + #if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) + static const keygen_rng_functions keygen_rng_cat1_aes128_avx = { + keygen_rng_init_aes128_cat1_avx, // ++ keygen_rng_release_noop, // + keygen_rng_next_u32_aes128_cat1_avx, // + }; + static const keygen_rng_functions keygen_rng_cat3_rijndael256_avx = { + keygen_rng_init_rijndael256_cat3_avx, // ++ keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_avx, // + }; + static const keygen_rng_functions keygen_rng_cat5_rijndael256_avx = { + keygen_rng_init_rijndael256_cat5_avx, // ++ keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_avx, // + }; + #endif +diff --git a/src/sdith_prng_avx2.c b/src/sdith_prng_avx2.c +index 0ee0dac..552a369 100644 +--- a/src/sdith_prng_avx2.c ++++ b/src/sdith_prng_avx2.c +@@ -3,11 +3,11 @@ + #include + #include + +-#include "aes_ansi_ref.h" + #include "sdith_prng_private.h" + #include "vole_private.h" + + ++ + // ggm seed rng, extended-seed variants (avx2): encrypt with the precomputed round + // keys (encrypt_nblocks) instead of scheduling in oneshot. Same domain sep as the + // raw variant (node_idx, not node_idx<<1), so byte-identical to the raw output. +@@ -165,6 +165,7 @@ EXPORT void proofow_init_cipher_cat1_avx( // + xof_seed_shake128(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake128(&xof); + xof_output_shake128(&xof, s->p, 64); // covers p0,p1,k0,k1 ++ xof_ctx_release_shake128(&xof); + s->p[0].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 +@@ -187,6 +188,7 @@ EXPORT int proofow_grind_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_ + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake128(&xof); + *ctr_in_out = ctr; + return 1; + } +@@ -207,6 +209,7 @@ EXPORT int proofow_verify_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake128(&xof); + return 1; + } + +@@ -233,6 +236,7 @@ EXPORT void proofow_init_cipher_cat5_avx( // + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) ++ xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 +@@ -255,6 +259,7 @@ EXPORT int proofow_grind_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_ + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } +@@ -275,6 +280,7 @@ EXPORT int proofow_verify_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + return 1; + } + +@@ -301,6 +307,7 @@ EXPORT void proofow_init_cipher_cat3_avx( // + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) ++ xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 +@@ -323,6 +330,7 @@ EXPORT int proofow_grind_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_ + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } +@@ -343,6 +351,7 @@ EXPORT int proofow_verify_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); ++ xof_ctx_release_shake256(&xof); + return 1; + } + // --- matrix_rng (avx2) --------------------------------------------------------- +diff --git a/src/sdith_signature.c b/src/sdith_signature.c +index 7cd2a3f..a7f3900 100644 +--- a/src/sdith_signature.c ++++ b/src/sdith_signature.c +@@ -188,7 +188,7 @@ EXPORT uint64_t sdith_keygen_entropy_bytes(const signature_parameters* sig_param + } + + #define MAP_FIELD(POOL_NAME, FIELD_NAME, VAR_BYTES) \ +- FIELD_NAME = (typeof(FIELD_NAME))POOL_NAME; \ ++ FIELD_NAME = (__typeof__(FIELD_NAME))POOL_NAME; \ + POOL_NAME += (VAR_BYTES) + + /** secret key mapping */ +@@ -372,6 +372,7 @@ EXPORT void sdith_sign(const signature_parameters* sig_params, // + par.vole_params.xof.xof_seed(&hash_aux_ctx, hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_aux_ctx, sign.corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&hash_aux_ctx, hash_aux, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&hash_aux_ctx); + + uint8_t* const rvp_u_cchk = u; + uint8_t* const rvp_v_cchk = v2; +@@ -415,6 +416,7 @@ EXPORT void sdith_sign(const signature_parameters* sig_params, // + par.vole_params.xof.xof_seed(&hash_lines_ctx, cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_lines_ctx, sign.circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&hash_lines_ctx, hash_lines, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&hash_lines_ctx); + + // -------------------------------------- + // Phase 3: PIOP protocol (prover side) +@@ -425,6 +427,7 @@ EXPORT void sdith_sign(const signature_parameters* sig_params, // + par.vole_params.xof.xof_init_and_seed(&chall_rng, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_finalize_and_output(&chall_rng, chall_a, par.lambda_bytes * par.rsd_codim_limbs); + par.vole_params.xof.xof_output(&chall_rng, chall_unitary, par.lambda_bytes * par.rsd_w); ++ par.vole_params.xof.xof_ctx_release(&chall_rng); + + rsd_public_key_times_challenge_ref( // + &par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // +@@ -475,6 +478,7 @@ EXPORT void sdith_sign(const signature_parameters* sig_params, // + par.vole_params.xof.xof_seed(&hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&hash_piop_ctx, sign.hash_piop, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&hash_piop_ctx); + + // -------------------------------------- + // Phase 3: Open one random evaluation +@@ -495,6 +499,7 @@ EXPORT void sdith_sign(const signature_parameters* sig_params, // + if (topen <= par.target_topen) break; // success! + ++pow_ctr; + } ++ par.vole_params.proofow_release(pow_ctx); + memcpy(sign.proofow_ctr_reveal, &pow_ctr, PROOFOW_CTR_REVEALED_BYTES); + + // generate delta1 +@@ -631,6 +636,7 @@ EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + memcpy(&proof_of_work_counter, sign.proofow_ctr_reveal, PROOFOW_CTR_REVEALED_BYTES); // load the golden counter + par.vole_params.proofow_init(pow_ctx, par.lambda, par.kappa, par.tau, par.proofow_w, sign.hash_piop); + int r = par.vole_params.proofow_verify_w(pow_ctx, verif_delta0, proof_of_work_counter); ++ par.vole_params.proofow_release(pow_ctx); + VERIFY_OR_FAIL(r, "invalid proof of work: vgrind"); + VERIFY_OR_FAIL(!bitvec_is_zero_nonct(verif_delta0, par.tau * par.kappa), "invalid proof of work: zero"); + hidden_leaves_indexes2(par.kappa, par.tau, verif_hidden_leaves_idx, verif_delta0); +@@ -690,6 +696,7 @@ EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, verif_hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, sign.corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_aux_ctx, verif_hash_aux, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&verif_hash_aux_ctx); + + // vole consistency check + both_vole_consistency_check_matrix(&par.vole_params, par.L, verif_cchk_matrix, verif_hash_aux, 2 * par.lambda_bytes); +@@ -703,6 +710,7 @@ EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, verif_cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, sign.circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_lines_ctx, verif_hash_lines, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&verif_hash_lines_ctx); + + // -------------------------------------- + // PIOP Protocol (verifier's side) +@@ -736,6 +744,7 @@ EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + par.vole_params.xof.xof_finalize_and_output(&verif_chall_rng, verif_chall_a, par.lambda_bytes * par.rsd_codim_limbs); + // note: the chall unitary are only needed if the mux tree contains one non-binary arity + par.vole_params.xof.xof_output(&verif_chall_rng, verif_chall_unitary, par.lambda_bytes * par.rsd_w); ++ par.vole_params.xof.xof_ctx_release(&verif_chall_rng); + + rsd_public_key_times_challenge_ref(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // + verif_chall_a_H, verif_chall_a_y, // +@@ -789,6 +798,7 @@ EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_piop_ctx, verif_hash_piop, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&verif_hash_piop_ctx); + VERIFY_OR_FAIL(memcmp(verif_hash_piop, sign.hash_piop, 2 * par.lambda_bytes) == 0, "invalid hash_piop"); + } + +diff --git a/src/vole_expansion.c b/src/vole_expansion.c +index 13727c0..eb49506 100644 +--- a/src/vole_expansion.c ++++ b/src/vole_expansion.c +@@ -4,7 +4,10 @@ + #include "ggm.h" + #include "sdith_prng.h" + #include "vole_private.h" ++ ++#ifndef SDITH3_FOR_LIBOQS + #include "KeccakSpongetimes4.h" ++#endif + + #ifndef NDEBUG + #define MSTACK_DEF(bytelen) \ +@@ -26,8 +29,11 @@ + stack_cur += bytelen + #endif + ++#ifndef SDITH3_FOR_LIBOQS ++// these don't appear to be used here at all, so no corresponding liboqs implimentaion is added + #define BATCH_XOF_STRIDE (((sizeof(KeccakWidth1600times4_SpongeInstance) + 31) / 32) * 32) + #define BATCH_XOF(base, idx) ((KeccakWidth1600times4_SpongeInstance*)((uint8_t*)(base) + (idx) * BATCH_XOF_STRIDE)) ++#endif + + /** @brief converts delta0 to delta1 + * delta0 has kappa*tau bits, encoding tau grey code encodings +@@ -128,6 +134,8 @@ EXPORT void prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + TMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + TMP_SPACE_MAP_ALIGNED(bitvec_t**, uu, 8, TAU * sizeof(bitvec_t*)); + TMP_SPACE_MAP_ALIGNED(bitmat_t**, vv, 8, TAU * sizeof(bitmat_t*)); ++ // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) ++ vole_params->prepare_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + // the two domain-separated salts: one for the GGM tree, one for the vole rng + uint64_t* const ggm_masked_salt = masked_salts; + uint64_t* const vole_masked_salt = masked_salts + (SEED_BYTES >> 3); +@@ -232,11 +240,17 @@ EXPORT void prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + // bound first (it commits all lambda bits, whereas the tweaked salts drop the + // low GGM_TWEAK_BITS and the top prefix bits), then the per-rep subhashes. + vole_params->xof_vector.finalize_and_output(commit_xofs, TAU, subhashes_ptrs, 2 * LAMBDA_BYTES); ++ vole_params->xof_vector.ctx_release(commit_xofs, TAU); + xof_ctx commits_xof; + vole_params->xof.xof_init_and_seed(&commits_xof, &HASH_BAVC_PREFIX, 1); + vole_params->xof.xof_seed(&commits_xof, global_salt, LAMBDA_BYTES); + vole_params->xof.xof_seed(&commits_xof, subhashes, 2 * TAU * LAMBDA_BYTES); + vole_params->xof.xof_finalize_and_output(&commits_xof, commits_hash, 2 * LAMBDA_BYTES); ++ vole_params->xof.xof_ctx_release(&commits_xof); ++ ++ // release any per-slot state the ext_seed backend cached (no-op unless the ++ // liboqs aes128 backend is in use) ++ vole_params->release_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + } + + /** +@@ -324,6 +338,8 @@ EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + TMP_SPACE_MAP_ALIGNED(bitmat_t**, qq, 8, TAU * sizeof(bitmat_t*)); + TMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_nodes_idx, 8, (2 * TAU + topen + 1) * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint32_t*, sibling_nodes_idx, 8, (topen + 1) * sizeof(uint32_t)); ++ // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) ++ vole_params->prepare_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + // the two domain-separated salts: one for the GGM tree, one for the vole rng + uint64_t* const ggm_masked_salt = masked_salts; + uint64_t* const vole_masked_salt = masked_salts + (SEED_BYTES >> 3); +@@ -506,11 +522,13 @@ EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + // now, hash the per-rep subhashes into the final commits hash (same layout as + // the prover's): commits_hash = H(HASH_BAVC_PREFIX, global_salt, subhashes). + vole_params->xof_vector.finalize_and_output(commit_xofs, TAU, subhashes_ptrs, 2 * LAMBDA_BYTES); ++ vole_params->xof_vector.ctx_release(commit_xofs, TAU); + xof_ctx commits_xof; + vole_params->xof.xof_init_and_seed(&commits_xof, &HASH_BAVC_PREFIX, 1); + vole_params->xof.xof_seed(&commits_xof, global_salt, LAMBDA_BYTES); + vole_params->xof.xof_seed(&commits_xof, subhashes, 2 * TAU * LAMBDA_BYTES); + vole_params->xof.xof_finalize_and_output(&commits_xof, commits_hash, 2 * LAMBDA_BYTES); ++ vole_params->xof.xof_ctx_release(&commits_xof); + + // postprocess q using delta + const uint64_t* deltap64 = delta1; +@@ -522,6 +540,10 @@ EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + } + } + } ++ ++ // release any per-slot state the ext_seed backend cached (no-op unless the ++ // liboqs aes128 backend is in use) ++ vole_params->release_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + } + + +@@ -614,6 +636,8 @@ EXPORT void full_ggm_tree_open_sibling_path_from_root( // + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, 2 * BUF_SIZE_MAX * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint32_t*, node_indexes, 8, BUF_SIZE_MAX * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, node_actions, 8, BUF_SIZE_MAX * sizeof(uint8_t)); ++ // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) ++ vole_params->prepare_extseed_buf(ext_seed, 1, EXT_BYTES); + // only the GGM salt is needed here: this path does not draw any vole randomness + compute_tweaked_salts(vole_params, ggm_masked_salt, NULL, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); +@@ -727,6 +751,10 @@ EXPORT void full_ggm_tree_open_sibling_path_from_root( // + vole_params->ggm_extseed_rng_commit(hidden_leaves_commits + i * COMMIT_BYTES, ggm_masked_salt, ext_seed, + node_indexes[TAU - i - 1]); + } ++ ++ // release any per-slot state the ext_seed backend cached (no-op unless the ++ // liboqs aes128 backend is in use) ++ vole_params->release_extseed_buf(ext_seed, 1, EXT_BYTES); + } + + EXPORT void prover_midsize_to_fullsize_std_vole_ct_ref(const vole_parameters* vole_params, uint64_t L, bitvec_t* out_u, +@@ -786,6 +814,7 @@ EXPORT void both_vole_consistency_check_matrix( // + xof_ctx cchk_matrix_rng; + vole_params->xof.xof_init_and_seed(&cchk_matrix_rng, chk_seed1, chk_seed1_bytes); + vole_params->xof.xof_finalize_and_output(&cchk_matrix_rng, chk_matrix, cchk_nrows * cchk_col_bytes); ++ vole_params->xof.xof_ctx_release(&cchk_matrix_rng); + // mask last columns with zeroes if needed + uint8_t cchk_last_mask = 0xFF >> ((-cchk_ncols) & 7); + uint8_t* const cm = (uint8_t*)chk_matrix; +diff --git a/src/vole_parameters.c b/src/vole_parameters.c +index 34e4b45..f1c6fb5 100644 +--- a/src/vole_parameters.c ++++ b/src/vole_parameters.c +@@ -26,18 +26,22 @@ EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, + vole_params->proofow_init = proofow_init_shake_cat1; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat1; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat1; ++ vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat1; + vole_params->proofow_init = proofow_init_cipher_cat1_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat1_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat1_ref; ++ vole_params->proofow_release = proofow_release_cipher_cat1_ref; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat1_aes128_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat1_aes128_4x_ref; ++ vole_params->prepare_extseed_buf = prepare_extseed_buf_cat1_aes128_ref; ++ vole_params->release_extseed_buf = release_extseed_buf_cat1_aes128_ref; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat1_aes128; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat1_aes128_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat1_aes128_x4_ref; // I8: naive four calls +@@ -68,18 +72,22 @@ EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, + vole_params->proofow_init = proofow_init_shake_cat3; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat3; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat3; ++ vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat3; + vole_params->proofow_init = proofow_init_cipher_cat3_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat3_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat3_ref; ++ vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat3_rijndael256_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat3_rijndael256_4x_ref; ++ vole_params->prepare_extseed_buf = extseed_buf_noop; ++ vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat3_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat3_rijndael256_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref; // I8: naive four calls +@@ -110,18 +118,22 @@ EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, + vole_params->proofow_init = proofow_init_shake_cat5; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat5; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat5; ++ vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat5; + vole_params->proofow_init = proofow_init_cipher_cat5_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat5_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat5_ref; ++ vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat5_rijndael256_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat5_rijndael256_4x_ref; ++ vole_params->prepare_extseed_buf = extseed_buf_noop; ++ vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat5_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat5_rijndael256_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref; // I8: naive four calls +diff --git a/src/vole_parameters.h b/src/vole_parameters.h +index e93f99d..6fa831b 100644 +--- a/src/vole_parameters.h ++++ b/src/vole_parameters.h +@@ -62,8 +62,11 @@ struct vole_parameters_t { + PROOFOW_INIT_F* proofow_init; + PROOFOW_GRIND_W_F* proofow_grind_w; + PROOFOW_VERIFY_W_F* proofow_verify_w; ++ PROOFOW_RELEASE_F* proofow_release; + EXTEND_LEAF_SEED_F* extend_leaf_seed; + EXTEND_LEAF_SEED_4X_F* extend_leaf_seed_4x; ++ EXTSEED_BUF_F* prepare_extseed_buf; ++ EXTSEED_BUF_F* release_extseed_buf; + EXTENDED_NODE_SEED_BYTES_F* extended_node_seed_bytes; + GGM_EXTSEED_RNG_LR_F* ggm_extseed_rng_lr; + GGM_EXTSEED_RNG_LR_X4_F* ggm_extseed_rng_lr_x4; // I8: batched 4-node variant; NULL => four ggm_extseed_rng_lr calls +diff --git a/src/vole_parameters_avx2.c b/src/vole_parameters_avx2.c +index cbc30f2..dcdbeee 100644 +--- a/src/vole_parameters_avx2.c ++++ b/src/vole_parameters_avx2.c +@@ -26,18 +26,22 @@ EXPORT void vole_parameters_init_with_variant_avx(vole_parameters* vole_params, + vole_params->proofow_init = proofow_init_shake_cat1; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat1_4way; // AVX2 4-way KeccakP-1600-times4 + vole_params->proofow_verify_w = proofow_verify_w_shake_cat1; ++ vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat1; + vole_params->proofow_init = proofow_init_cipher_cat1_avx; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat1_avx; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat1_avx; ++ vole_params->proofow_release = proofow_release_noop; + break; + default: + abort(); // unknown variant + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat1_aes128_avx2; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat1_aes128_4x_avx2; ++ vole_params->prepare_extseed_buf = extseed_buf_noop; ++ vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat1_aes128; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat1_aes128_avx2; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2; // I8 +@@ -68,18 +72,22 @@ EXPORT void vole_parameters_init_with_variant_avx(vole_parameters* vole_params, + vole_params->proofow_init = proofow_init_shake_cat3; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat3_4way; // AVX2 4-way KeccakP-1600-times4 + vole_params->proofow_verify_w = proofow_verify_w_shake_cat3; ++ vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat3; + vole_params->proofow_init = proofow_init_cipher_cat3_avx; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat3_avx; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat3_avx; ++ vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat3_rijndael256_avx2; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat3_rijndael256_4x_avx2; ++ vole_params->prepare_extseed_buf = extseed_buf_noop; ++ vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat3_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat3_rijndael256_avx2; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2; // I8: naive four calls +@@ -110,18 +118,22 @@ EXPORT void vole_parameters_init_with_variant_avx(vole_parameters* vole_params, + vole_params->proofow_init = proofow_init_shake_cat5; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat5_4way; // AVX2 4-way KeccakP-1600-times4 + vole_params->proofow_verify_w = proofow_verify_w_shake_cat5; ++ vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat5; + vole_params->proofow_init = proofow_init_cipher_cat5_avx; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat5_avx; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat5_avx; ++ vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat5_rijndael256_avx2; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat5_rijndael256_4x_avx2; ++ vole_params->prepare_extseed_buf = extseed_buf_noop; ++ vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat5_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat5_rijndael256_avx2; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2; // I8: naive four calls +diff --git a/src/vole_private.h b/src/vole_private.h +index 30d3711..e095785 100644 +--- a/src/vole_private.h ++++ b/src/vole_private.h +@@ -5,6 +5,7 @@ + #include + + #include "commons.h" ++#include "sdith_inline.h" + #include "ggm.h" + #include "sdith_algebra.h" + #include "sdith_arithmetic.h" +@@ -35,13 +36,7 @@ + #define CASSERT_ALIGNMENT CREQUIRE_ALIGNMENT + #endif + +- +- +-#if defined(_WIN32) || defined(__APPLE__) +-#define __always_inline inline __attribute((always_inline)) +-#endif +- +-__always_inline uint64_t alignment_of(uint64_t x) { return (x ^ (x - 1)) >> 1; } ++SDITH_ALWAYS_INLINE uint64_t alignment_of(uint64_t x) { return (x ^ (x - 1)) >> 1; } + + // irreducible polynomial constant for GF128 + #define GF128_PV 0b10000111 +@@ -80,7 +75,7 @@ union gf256_t { + // integer multiplier is constant-time on the targets we care about, incl. + // Cortex-M4 UMULL). gf_clmul64 combines three gf_bmul32 (Karatsuba) into a + // full 64x64->128 carryless product. +-static __always_inline uint64_t gf_bmul32(uint32_t x, uint32_t y) { ++SDITH_ALWAYS_INLINE uint64_t gf_bmul32(uint32_t x, uint32_t y) { + uint32_t x0 = x & 0x11111111u, x1 = x & 0x22222222u, x2 = x & 0x44444444u, x3 = x & 0x88888888u; + uint32_t y0 = y & 0x11111111u, y1 = y & 0x22222222u, y2 = y & 0x44444444u, y3 = y & 0x88888888u; + uint64_t z0 = (uint64_t)x0 * y0 ^ (uint64_t)x1 * y3 ^ (uint64_t)x2 * y2 ^ (uint64_t)x3 * y1; +@@ -91,7 +86,7 @@ static __always_inline uint64_t gf_bmul32(uint32_t x, uint32_t y) { + z2 &= 0x4444444444444444ull; z3 &= 0x8888888888888888ull; + return z0 | z1 | z2 | z3; + } +-static __always_inline void gf_clmul64(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) { ++SDITH_ALWAYS_INLINE void gf_clmul64(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) { + uint32_t a0 = (uint32_t)a, a1 = (uint32_t)(a >> 32), b0 = (uint32_t)b, b1 = (uint32_t)(b >> 32); + uint64_t z0 = gf_bmul32(a0, b0); + uint64_t z2 = gf_bmul32(a1, b1); +diff --git a/test/bench_signature.cpp b/test/bench_signature.cpp +index 867e83c..1f8c690 100644 +--- a/test/bench_signature.cpp ++++ b/test/bench_signature.cpp +@@ -264,6 +264,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_seed(&hash_aux_ctx, hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_aux_ctx, corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&hash_aux_ctx, hash_aux, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&hash_aux_ctx); + + double t4 = get_time(); + uint8_t* const rvp_u_cchk = u; +@@ -307,6 +308,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_seed(&hash_lines_ctx, cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_lines_ctx, circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&hash_lines_ctx, hash_lines, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&hash_lines_ctx); + + const double t101 = get_time(); + // generate the challenge points +@@ -314,6 +316,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_init_and_seed(&chall_rng, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_finalize_and_output(&chall_rng, chall_a, par.lambda_bytes * par.rsd_codim_limbs); + par.vole_params.xof.xof_output(&chall_rng, chall_unitary, par.lambda_bytes * par.rsd_w); ++ par.vole_params.xof.xof_ctx_release(&chall_rng); + const double t102 = get_time(); + rsd_public_key_times_challenge_ref( // + &par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // +@@ -369,6 +372,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_seed(&hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&hash_piop_ctx, hash_piop, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&hash_piop_ctx); + + const double t200 = get_time(); + +@@ -484,6 +488,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_aux_ctx, verif_hash_aux, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&verif_hash_aux_ctx); + REQUIRE_DRAMATICALLY(memcmp(verif_hash_aux, hash_aux, 2 * par.lambda_bytes) == 0, "bug!!"); + + double verif_paranoia_checks_time = 0.; +@@ -577,6 +582,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, verif_cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_lines_ctx, verif_hash_lines, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&verif_hash_lines_ctx); + REQUIRE_DRAMATICALLY(memcmp(verif_hash_lines, hash_lines, 2 * par.lambda_bytes) == 0, "bug!!"); + + const double vt5 = get_time(); +@@ -649,6 +655,7 @@ int main(int argc, char** argv) { + par.lambda_bytes * par.rsd_codim_limbs); + // note: the chall unitary are only needed if the mux tree contains one non-binary arity + par.vole_params.xof.xof_output(&verif_chall_rng, verif_chall_unitary, par.lambda_bytes * par.rsd_w); ++ par.vole_params.xof.xof_ctx_release(&verif_chall_rng); + const double vt102 = get_time(); + + std::vector vtmpsp( +@@ -732,6 +739,7 @@ int main(int argc, char** argv) { + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_piop_ctx, verif_hash_piop, 2 * par.lambda_bytes); ++ par.vole_params.xof.xof_ctx_release(&verif_hash_piop_ctx); + REQUIRE_DRAMATICALLY(memcmp(verif_hash_piop, hash_piop, 2 * par.lambda_bytes) == 0, "bug!!"); + + const double vt200 = get_time(); diff --git a/scripts/copy_from_upstream/update_upstream_alg_docs.py b/scripts/copy_from_upstream/update_upstream_alg_docs.py index d630746af0..63be67fa5d 100755 --- a/scripts/copy_from_upstream/update_upstream_alg_docs.py +++ b/scripts/copy_from_upstream/update_upstream_alg_docs.py @@ -436,7 +436,7 @@ def update_upstream_sig_alg_docs(liboqs_root, sigs, upstream_info, write_changes upstream_impl['supported_platforms'][i]['architecture'] = 'ARM64_V8' if 'asimd' in upstream_impl['supported_platforms'][i]['required_flags']: upstream_impl['supported_platforms'][i]['required_flags'].remove('asimd') - if not upstream_impl['supported_platforms'][i]['required_flags']: + if 'required_flags' in upstream_impl['supported_platforms'][i] and not upstream_impl['supported_platforms'][i]['required_flags']: del upstream_impl['supported_platforms'][i]['required_flags'] impl['supported-platforms'] = rhs_if_not_equal(impl['supported-platforms'], upstream_impl['supported_platforms'], "supported-platforms") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1878e3fa20..b771ecc820 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,8 +75,21 @@ if(OQS_ENABLE_SIG_MQOM) add_subdirectory(sig/mqom) set(SIG_OBJS ${SIG_OBJS} ${MQOM_OBJS}) endif() +if(OQS_ENABLE_SIG_SDITH) + add_subdirectory(sig/sdith) + set(SIG_OBJS ${SIG_OBJS} ${SDITH_OBJS}) +endif() ##### OQS_COPY_FROM_UPSTREAM_FRAGMENT_ADD_ALG_OBJECTS_END +# SDitH is imported upstream code that is not yet free of compiler warnings +# This prevents those warnings from being treated as errors and blocking CI +# In the future, we hope to remove this once the upstream code is cleaned up +# Tracked by https://github.com/open-quantum-safe/liboqs/issues/2588 +if(OQS_ENABLE_SIG_SDITH) + get_property(_sdith_targets DIRECTORY sig/sdith PROPERTY BUILDSYSTEM_TARGETS) + set_target_properties(${_sdith_targets} PROPERTIES COMPILE_WARNING_AS_ERROR OFF) +endif() + if(OQS_ENABLE_SIG_SLH_DSA) add_subdirectory(sig/slh_dsa) set(SIG_OBJS ${SIG_OBJS} ${SLH_DSA_OBJS}) diff --git a/src/oqsconfig.h.cmake b/src/oqsconfig.h.cmake index aad797187d..48db834704 100644 --- a/src/oqsconfig.h.cmake +++ b/src/oqsconfig.h.cmake @@ -529,6 +529,32 @@ #cmakedefine OQS_ENABLE_SIG_mqom_mqom3_cat5_gf2_shorter_ot_memopt 1 #cmakedefine OQS_ENABLE_SIG_mqom_mqom3_cat5_gf2_shorter_ot_avx2 1 #cmakedefine OQS_ENABLE_SIG_mqom_mqom3_cat5_gf2_shorter_ot_neon 1 + +#cmakedefine OQS_ENABLE_SIG_SDITH 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_short 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_fast 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_short 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_fast 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_short 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_fast 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow 1 +#cmakedefine OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2 1 ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ADD_ALG_ENABLE_DEFINES_END ///// OQS_COPY_FROM_SLH_DSA_FRAGMENT_ADD_ALG_ENABLE_DEFINES_START #cmakedefine OQS_ENABLE_SIG_SLH_DSA 1 diff --git a/src/sig/sdith/CMakeLists.txt b/src/sig/sdith/CMakeLists.txt new file mode 100644 index 0000000000..cd2b994e13 --- /dev/null +++ b/src/sig/sdith/CMakeLists.txt @@ -0,0 +1,227 @@ +# SPDX-License-Identifier: MIT + +# This file was generated by +# scripts/copy_from_upstream/copy_from_upstream.py + +set(_SDITH_OBJS "") + +if(OQS_ENABLE_SIG_sdith_l1_gf2_short OR OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow OR OQS_ENABLE_SIG_sdith_l1_gf2_fast OR OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow OR OQS_ENABLE_SIG_sdith_l3_gf2_short OR OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow OR OQS_ENABLE_SIG_sdith_l3_gf2_fast OR OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow OR OQS_ENABLE_SIG_sdith_l5_gf2_short OR OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow OR OQS_ENABLE_SIG_sdith_l5_gf2_fast OR OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow) + add_library(sdith_sdith_common OBJECT sdith_sdith_common/aes128_ctrle_special_ref.c sdith_sdith_common/aes_glue.c sdith_sdith_common/commons.c sdith_sdith_common/ct_utils.c sdith_sdith_common/gf128.c sdith_sdith_common/gf192.c sdith_sdith_common/gf256.c sdith_sdith_common/ggm.c sdith_sdith_common/matrix_transpose_f2.c sdith_sdith_common/matrix_vector_products_f2.c sdith_sdith_common/piop_circuit.c sdith_sdith_common/rijndael256.c sdith_sdith_common/rijndael256_ctrle_special_ref.c sdith_sdith_common/rsd.c sdith_sdith_common/sdith_prng.c sdith_sdith_common/sdith_signature.c sdith_sdith_common/sdith_signature_parameters.c sdith_sdith_common/vole_expansion.c sdith_sdith_common/vole_parameters.c sdith_sdith_common/vole_to_piop.c) + target_include_directories(sdith_sdith_common PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common) + target_compile_options(sdith_sdith_common PUBLIC -DSDITH3_FOR_LIBOQS -DNDEBUG -DONLY_REF_IMPLEMENTATION -DAPPLY_NAMESPACE=oqs_sig_private_sdith_ref_) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2 OR OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2 OR OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2 OR OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2 OR OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2 OR OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2 OR OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2 OR OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2 OR OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2 OR OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2 OR OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2 OR OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2) + add_library(sdith_sdith_common_avx2 OBJECT sdith_sdith_common_avx2/aes128_ctrle_special_avx2.c sdith_sdith_common_avx2/aes128_ctrle_special_ref.c sdith_sdith_common_avx2/aes_glue.c sdith_sdith_common_avx2/commons.c sdith_sdith_common_avx2/ct_utils.c sdith_sdith_common_avx2/ct_utils_avx2.c sdith_sdith_common_avx2/gf128.c sdith_sdith_common_avx2/gf128_avx2.c sdith_sdith_common_avx2/gf192.c sdith_sdith_common_avx2/gf192_avx2.c sdith_sdith_common_avx2/gf256.c sdith_sdith_common_avx2/gf256_avx2.c sdith_sdith_common_avx2/ggm.c sdith_sdith_common_avx2/matrix_transpose_f2.c sdith_sdith_common_avx2/matrix_vector_products_f2.c sdith_sdith_common_avx2/matrix_vector_products_f2_avx2.c sdith_sdith_common_avx2/piop_circuit.c sdith_sdith_common_avx2/rijndael256.c sdith_sdith_common_avx2/rijndael256_avx.c sdith_sdith_common_avx2/rijndael256_ctrle_special_avx2.c sdith_sdith_common_avx2/rijndael256_ctrle_special_ref.c sdith_sdith_common_avx2/rsd.c sdith_sdith_common_avx2/sdith_prng.c sdith_sdith_common_avx2/sdith_prng_avx2.c sdith_sdith_common_avx2/sdith_signature.c sdith_sdith_common_avx2/sdith_signature_parameters.c sdith_sdith_common_avx2/vole_expansion.c sdith_sdith_common_avx2/vole_parameters.c sdith_sdith_common_avx2/vole_parameters_avx2.c sdith_sdith_common_avx2/vole_to_piop.c) + target_include_directories(sdith_sdith_common_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_avx2) + target_compile_options(sdith_sdith_common_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + target_compile_options(sdith_sdith_common_avx2 PUBLIC -DSDITH3_FOR_LIBOQS -DNDEBUG -DAPPLY_NAMESPACE=oqs_sig_private_sdith_avx2_) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_short) + add_library(sdith_l1_gf2_short_ref OBJECT sig_sdith_l1_gf2_short.c sdith_l1_gf2_short_ref/api.c ) + target_include_directories(sdith_l1_gf2_short_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_short_ref) + target_include_directories(sdith_l1_gf2_short_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_short_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2) + add_library(sdith_l1_gf2_short_avx2 OBJECT sdith_l1_gf2_short_avx2/api.c ) + target_include_directories(sdith_l1_gf2_short_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_short_avx2) + target_include_directories(sdith_l1_gf2_short_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_short_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l1_gf2_short_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow) + add_library(sdith_l1_gf2_short_cipherpow_ref OBJECT sig_sdith_l1_gf2_short_cipherpow.c sdith_l1_gf2_short_cipherpow_ref/api.c ) + target_include_directories(sdith_l1_gf2_short_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_short_cipherpow_ref) + target_include_directories(sdith_l1_gf2_short_cipherpow_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_short_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2) + add_library(sdith_l1_gf2_short_cipherpow_avx2 OBJECT sdith_l1_gf2_short_cipherpow_avx2/api.c ) + target_include_directories(sdith_l1_gf2_short_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_short_cipherpow_avx2) + target_include_directories(sdith_l1_gf2_short_cipherpow_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_short_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l1_gf2_short_cipherpow_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_fast) + add_library(sdith_l1_gf2_fast_ref OBJECT sig_sdith_l1_gf2_fast.c sdith_l1_gf2_fast_ref/api.c ) + target_include_directories(sdith_l1_gf2_fast_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_fast_ref) + target_include_directories(sdith_l1_gf2_fast_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_fast_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2) + add_library(sdith_l1_gf2_fast_avx2 OBJECT sdith_l1_gf2_fast_avx2/api.c ) + target_include_directories(sdith_l1_gf2_fast_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_fast_avx2) + target_include_directories(sdith_l1_gf2_fast_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_fast_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l1_gf2_fast_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow) + add_library(sdith_l1_gf2_fast_cipherpow_ref OBJECT sig_sdith_l1_gf2_fast_cipherpow.c sdith_l1_gf2_fast_cipherpow_ref/api.c ) + target_include_directories(sdith_l1_gf2_fast_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_fast_cipherpow_ref) + target_include_directories(sdith_l1_gf2_fast_cipherpow_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_fast_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2) + add_library(sdith_l1_gf2_fast_cipherpow_avx2 OBJECT sdith_l1_gf2_fast_cipherpow_avx2/api.c ) + target_include_directories(sdith_l1_gf2_fast_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l1_gf2_fast_cipherpow_avx2) + target_include_directories(sdith_l1_gf2_fast_cipherpow_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l1_gf2_fast_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l1_gf2_fast_cipherpow_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_short) + add_library(sdith_l3_gf2_short_ref OBJECT sig_sdith_l3_gf2_short.c sdith_l3_gf2_short_ref/api.c ) + target_include_directories(sdith_l3_gf2_short_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_short_ref) + target_include_directories(sdith_l3_gf2_short_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_short_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2) + add_library(sdith_l3_gf2_short_avx2 OBJECT sdith_l3_gf2_short_avx2/api.c ) + target_include_directories(sdith_l3_gf2_short_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_short_avx2) + target_include_directories(sdith_l3_gf2_short_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_short_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l3_gf2_short_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow) + add_library(sdith_l3_gf2_short_cipherpow_ref OBJECT sig_sdith_l3_gf2_short_cipherpow.c sdith_l3_gf2_short_cipherpow_ref/api.c ) + target_include_directories(sdith_l3_gf2_short_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_short_cipherpow_ref) + target_include_directories(sdith_l3_gf2_short_cipherpow_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_short_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2) + add_library(sdith_l3_gf2_short_cipherpow_avx2 OBJECT sdith_l3_gf2_short_cipherpow_avx2/api.c ) + target_include_directories(sdith_l3_gf2_short_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_short_cipherpow_avx2) + target_include_directories(sdith_l3_gf2_short_cipherpow_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_short_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l3_gf2_short_cipherpow_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_fast) + add_library(sdith_l3_gf2_fast_ref OBJECT sig_sdith_l3_gf2_fast.c sdith_l3_gf2_fast_ref/api.c ) + target_include_directories(sdith_l3_gf2_fast_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_fast_ref) + target_include_directories(sdith_l3_gf2_fast_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_fast_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2) + add_library(sdith_l3_gf2_fast_avx2 OBJECT sdith_l3_gf2_fast_avx2/api.c ) + target_include_directories(sdith_l3_gf2_fast_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_fast_avx2) + target_include_directories(sdith_l3_gf2_fast_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_fast_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l3_gf2_fast_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow) + add_library(sdith_l3_gf2_fast_cipherpow_ref OBJECT sig_sdith_l3_gf2_fast_cipherpow.c sdith_l3_gf2_fast_cipherpow_ref/api.c ) + target_include_directories(sdith_l3_gf2_fast_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_fast_cipherpow_ref) + target_include_directories(sdith_l3_gf2_fast_cipherpow_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_fast_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2) + add_library(sdith_l3_gf2_fast_cipherpow_avx2 OBJECT sdith_l3_gf2_fast_cipherpow_avx2/api.c ) + target_include_directories(sdith_l3_gf2_fast_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l3_gf2_fast_cipherpow_avx2) + target_include_directories(sdith_l3_gf2_fast_cipherpow_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l3_gf2_fast_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l3_gf2_fast_cipherpow_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_short) + add_library(sdith_l5_gf2_short_ref OBJECT sig_sdith_l5_gf2_short.c sdith_l5_gf2_short_ref/api.c ) + target_include_directories(sdith_l5_gf2_short_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_short_ref) + target_include_directories(sdith_l5_gf2_short_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_short_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2) + add_library(sdith_l5_gf2_short_avx2 OBJECT sdith_l5_gf2_short_avx2/api.c ) + target_include_directories(sdith_l5_gf2_short_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_short_avx2) + target_include_directories(sdith_l5_gf2_short_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_short_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l5_gf2_short_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow) + add_library(sdith_l5_gf2_short_cipherpow_ref OBJECT sig_sdith_l5_gf2_short_cipherpow.c sdith_l5_gf2_short_cipherpow_ref/api.c ) + target_include_directories(sdith_l5_gf2_short_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_short_cipherpow_ref) + target_include_directories(sdith_l5_gf2_short_cipherpow_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_short_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2) + add_library(sdith_l5_gf2_short_cipherpow_avx2 OBJECT sdith_l5_gf2_short_cipherpow_avx2/api.c ) + target_include_directories(sdith_l5_gf2_short_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_short_cipherpow_avx2) + target_include_directories(sdith_l5_gf2_short_cipherpow_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_short_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l5_gf2_short_cipherpow_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_fast) + add_library(sdith_l5_gf2_fast_ref OBJECT sig_sdith_l5_gf2_fast.c sdith_l5_gf2_fast_ref/api.c ) + target_include_directories(sdith_l5_gf2_fast_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_fast_ref) + target_include_directories(sdith_l5_gf2_fast_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_fast_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2) + add_library(sdith_l5_gf2_fast_avx2 OBJECT sdith_l5_gf2_fast_avx2/api.c ) + target_include_directories(sdith_l5_gf2_fast_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_fast_avx2) + target_include_directories(sdith_l5_gf2_fast_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_fast_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l5_gf2_fast_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow) + add_library(sdith_l5_gf2_fast_cipherpow_ref OBJECT sig_sdith_l5_gf2_fast_cipherpow.c sdith_l5_gf2_fast_cipherpow_ref/api.c ) + target_include_directories(sdith_l5_gf2_fast_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_fast_cipherpow_ref) + target_include_directories(sdith_l5_gf2_fast_cipherpow_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_fast_cipherpow_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +if(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2) + add_library(sdith_l5_gf2_fast_cipherpow_avx2 OBJECT sdith_l5_gf2_fast_cipherpow_avx2/api.c ) + target_include_directories(sdith_l5_gf2_fast_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_l5_gf2_fast_cipherpow_avx2) + target_include_directories(sdith_l5_gf2_fast_cipherpow_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) + target_include_directories(sdith_l5_gf2_fast_cipherpow_avx2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sdith_sdith_common_headers) + target_compile_options(sdith_l5_gf2_fast_cipherpow_avx2 PRIVATE -mavx2 -mavx -maes -mpclmul) + set(_SDITH_OBJS ${_SDITH_OBJS} $) +endif() + +set(SDITH_OBJS ${_SDITH_OBJS} PARENT_SCOPE) diff --git a/src/sig/sdith/sdith_l1_gf2_fast_avx2/api.c b/src/sig/sdith/sdith_l1_gf2_fast_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_fast_avx2/api.h b/src/sig/sdith/sdith_l1_gf2_fast_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_avx2/params.h b/src/sig/sdith/sdith_l1_gf2_fast_avx2/params.h new file mode 100644 index 0000000000..60088c01f7 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-fast, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 4914 +#define SIGNATURE_PARAMS CAT1_FAST_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/api.c b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/api.h b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/params.h b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/params.h new file mode 100644 index 0000000000..9202e22f90 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-fast-cipherpow, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 4643 +#define SIGNATURE_PARAMS CAT1_FAST_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/api.c b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/api.h b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/params.h b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/params.h new file mode 100644 index 0000000000..e8fd8ede22 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_cipherpow_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-fast-cipherpow, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 4643 +#define SIGNATURE_PARAMS CAT1_FAST_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_ref/api.c b/src/sig/sdith/sdith_l1_gf2_fast_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_fast_ref/api.h b/src/sig/sdith/sdith_l1_gf2_fast_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_fast_ref/params.h b/src/sig/sdith/sdith_l1_gf2_fast_ref/params.h new file mode 100644 index 0000000000..9a6b658e37 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_fast_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-fast, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_fast_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 4914 +#define SIGNATURE_PARAMS CAT1_FAST_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_avx2/api.c b/src/sig/sdith/sdith_l1_gf2_short_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_short_avx2/api.h b/src/sig/sdith/sdith_l1_gf2_short_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_avx2/params.h b/src/sig/sdith/sdith_l1_gf2_short_avx2/params.h new file mode 100644 index 0000000000..16c5d533e7 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-short, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_avx2_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 3721 +#define SIGNATURE_PARAMS CAT1_SHORT_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/api.c b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/api.h b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/params.h b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/params.h new file mode 100644 index 0000000000..c3030cc60c --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-short-cipherpow, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 3721 +#define SIGNATURE_PARAMS CAT1_SHORT_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/api.c b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/api.h b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/params.h b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/params.h new file mode 100644 index 0000000000..67598ae8dc --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_cipherpow_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-short-cipherpow, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 3721 +#define SIGNATURE_PARAMS CAT1_SHORT_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_ref/api.c b/src/sig/sdith/sdith_l1_gf2_short_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l1_gf2_short_ref/api.h b/src/sig/sdith/sdith_l1_gf2_short_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l1_gf2_short_ref/params.h b/src/sig/sdith/sdith_l1_gf2_short_ref/params.h new file mode 100644 index 0000000000..4c39055024 --- /dev/null +++ b/src/sig/sdith/sdith_l1_gf2_short_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L1-gf2-short, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l1_gf2_short_ +#define CRYPTO_SECRETKEYBYTES 147 +#define CRYPTO_PUBLICKEYBYTES 70 +#define CRYPTO_BYTES 3721 +#define SIGNATURE_PARAMS CAT1_SHORT_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_avx2/api.c b/src/sig/sdith/sdith_l3_gf2_fast_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_fast_avx2/api.h b/src/sig/sdith/sdith_l3_gf2_fast_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_avx2/params.h b/src/sig/sdith/sdith_l3_gf2_fast_avx2/params.h new file mode 100644 index 0000000000..1011e24cd2 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-fast, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 10852 +#define SIGNATURE_PARAMS CAT3_FAST_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/api.c b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/api.h b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/params.h b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/params.h new file mode 100644 index 0000000000..2f647fa0b4 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-fast-cipherpow, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 10452 +#define SIGNATURE_PARAMS CAT3_FAST_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/api.c b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/api.h b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/params.h b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/params.h new file mode 100644 index 0000000000..592c5ef9c7 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_cipherpow_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-fast-cipherpow, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 10452 +#define SIGNATURE_PARAMS CAT3_FAST_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_ref/api.c b/src/sig/sdith/sdith_l3_gf2_fast_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_fast_ref/api.h b/src/sig/sdith/sdith_l3_gf2_fast_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_fast_ref/params.h b/src/sig/sdith/sdith_l3_gf2_fast_ref/params.h new file mode 100644 index 0000000000..00ea3cd74f --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_fast_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-fast, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_fast_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 10852 +#define SIGNATURE_PARAMS CAT3_FAST_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_avx2/api.c b/src/sig/sdith/sdith_l3_gf2_short_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_short_avx2/api.h b/src/sig/sdith/sdith_l3_gf2_short_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_avx2/params.h b/src/sig/sdith/sdith_l3_gf2_short_avx2/params.h new file mode 100644 index 0000000000..d22a93226e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-short, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_avx2_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 8484 +#define SIGNATURE_PARAMS CAT3_SHORT_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/api.c b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/api.h b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/params.h b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/params.h new file mode 100644 index 0000000000..4a9617066c --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-short-cipherpow, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 8484 +#define SIGNATURE_PARAMS CAT3_SHORT_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/api.c b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/api.h b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/params.h b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/params.h new file mode 100644 index 0000000000..6027ddf90c --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_cipherpow_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-short-cipherpow, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 8484 +#define SIGNATURE_PARAMS CAT3_SHORT_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_ref/api.c b/src/sig/sdith/sdith_l3_gf2_short_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l3_gf2_short_ref/api.h b/src/sig/sdith/sdith_l3_gf2_short_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l3_gf2_short_ref/params.h b/src/sig/sdith/sdith_l3_gf2_short_ref/params.h new file mode 100644 index 0000000000..cd23de8d89 --- /dev/null +++ b/src/sig/sdith/sdith_l3_gf2_short_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L3-gf2-short, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l3_gf2_short_ +#define CRYPTO_SECRETKEYBYTES 208 +#define CRYPTO_PUBLICKEYBYTES 98 +#define CRYPTO_BYTES 8484 +#define SIGNATURE_PARAMS CAT3_SHORT_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_avx2/api.c b/src/sig/sdith/sdith_l5_gf2_fast_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_fast_avx2/api.h b/src/sig/sdith/sdith_l5_gf2_fast_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_avx2/params.h b/src/sig/sdith/sdith_l5_gf2_fast_avx2/params.h new file mode 100644 index 0000000000..3fd541d028 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-fast, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 19144 +#define SIGNATURE_PARAMS CAT5_FAST_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/api.c b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/api.h b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/params.h b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/params.h new file mode 100644 index 0000000000..3979ada462 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-fast-cipherpow, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 19144 +#define SIGNATURE_PARAMS CAT5_FAST_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/api.c b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/api.h b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/params.h b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/params.h new file mode 100644 index 0000000000..adbcb34a8b --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_cipherpow_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-fast-cipherpow, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 19144 +#define SIGNATURE_PARAMS CAT5_FAST_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_ref/api.c b/src/sig/sdith/sdith_l5_gf2_fast_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_fast_ref/api.h b/src/sig/sdith/sdith_l5_gf2_fast_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_fast_ref/params.h b/src/sig/sdith/sdith_l5_gf2_fast_ref/params.h new file mode 100644 index 0000000000..09374c3f29 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_fast_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-fast, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_fast_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 19144 +#define SIGNATURE_PARAMS CAT5_FAST_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_avx2/api.c b/src/sig/sdith/sdith_l5_gf2_short_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_short_avx2/api.h b/src/sig/sdith/sdith_l5_gf2_short_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_avx2/params.h b/src/sig/sdith/sdith_l5_gf2_short_avx2/params.h new file mode 100644 index 0000000000..0b5f024169 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-short, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_avx2_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 15147 +#define SIGNATURE_PARAMS CAT5_SHORT_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/api.c b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/api.h b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/params.h b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/params.h new file mode 100644 index 0000000000..dc0d4e5d58 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_avx2/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-short-cipherpow, avx2 implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_avx2_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 15147 +#define SIGNATURE_PARAMS CAT5_SHORT_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/api.c b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/api.h b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/params.h b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/params.h new file mode 100644 index 0000000000..2634d8b640 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_cipherpow_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-short-cipherpow, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 15147 +#define SIGNATURE_PARAMS CAT5_SHORT_CIPHERPOW_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_ref/api.c b/src/sig/sdith/sdith_l5_gf2_short_ref/api.c new file mode 100644 index 0000000000..64c3088b9e --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_ref/api.c @@ -0,0 +1,92 @@ +// The scheme's sizes, parameter set and symbol prefixes. liboqs copies +// this file next to the params.h of each scheme and implementation. +#include "params.h" + +#include +#include + +#include +#include + +#include "sdith_signature.h" +#include "api.h" + + +OQS_STATUS crypto_sign_keypair(uint8_t* public_key, uint8_t* secret_key) { + if (CRYPTO_BYTES != sdith_signature_bytes(&SIGNATURE_PARAMS) || + CRYPTO_PUBLICKEYBYTES != sdith_public_key_bytes(&SIGNATURE_PARAMS) || + CRYPTO_SECRETKEYBYTES != sdith_secret_key_bytes(&SIGNATURE_PARAMS)) + return OQS_ERROR; + uint64_t entropy_bytes = sdith_keygen_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_keygen_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_keygen(&SIGNATURE_PARAMS, secret_key, public_key, entropy, tmp_space); + + // tmp_space holds the raw solution, entropy holds the sk_seed: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_sign( + uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key) +{ + // TODO: there is an opportunity to optimize this by reusing the allocated tmp/entropy space + // when repeatedly signing/verifying. Tracked in liboqs as: + // https://github.com/open-quantum-safe/liboqs/issues/2619 + uint64_t entropy_bytes = sdith_signature_entropy_bytes(&SIGNATURE_PARAMS); + uint64_t tmp_bytes = sdith_signature_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* entropy = OQS_MEM_malloc(entropy_bytes); + if (entropy == NULL) return OQS_ERROR; + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) { + OQS_MEM_insecure_free(entropy); + return OQS_ERROR; + } + + OQS_randombytes(entropy, entropy_bytes); + sdith_sign(&SIGNATURE_PARAMS, signature, message, message_len, secret_key, entropy, tmp_space); + *signature_len = CRYPTO_BYTES; + + // tmp_space and entropy hold secret signing state: wipe both. + OQS_MEM_secure_free(tmp_space, tmp_bytes); + OQS_MEM_secure_free(entropy, entropy_bytes); + return OQS_SUCCESS; +} + +OQS_STATUS crypto_sign_verify( + const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key +) { + if (signature_len != CRYPTO_BYTES) return OQS_ERROR; + uint64_t tmp_bytes = sdith_verify_tmp_bytes(&SIGNATURE_PARAMS); + uint8_t* tmp_space = OQS_MEM_malloc(tmp_bytes); + if (tmp_space == NULL) return OQS_ERROR; + + uint8_t res = sdith_verify( + &SIGNATURE_PARAMS, + signature, + message, + message_len, + public_key, + tmp_space + ); + + OQS_MEM_secure_free(tmp_space, tmp_bytes); // Touches only public data + return res ? OQS_SUCCESS : OQS_ERROR; +} diff --git a/src/sig/sdith/sdith_l5_gf2_short_ref/api.h b/src/sig/sdith/sdith_l5_gf2_short_ref/api.h new file mode 100644 index 0000000000..fe7891b6f9 --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_ref/api.h @@ -0,0 +1,68 @@ +#ifndef API_H +#define API_H + +#include + +// This header wraps the SDiTH signature API for use in liboqs + +#include "sdith_signature.h" +#include "commons.h" + +#include + +/* Public API */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +#define crypto_sign_keypair SDITH_PUBLIC_API_NAMESPACE(crypto_sign_keypair) +#define crypto_sign_sign SDITH_PUBLIC_API_NAMESPACE(crypto_sign_sign) +#define crypto_sign_verify SDITH_PUBLIC_API_NAMESPACE(crypto_sign_verify) + +/** + * Generates the public and private key + * @param public_key [out] public key + * @param secret_key [out] secret key + * @return OQS_SUCCESS on success, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_keypair(uint8_t* public_key, + uint8_t* secret_key); + +/** + * Signs a message with the private key + * @param signature [out] signature + * @param signature_len [out] length of the signature + * @param message [in] message to sign + * @param message_len [in] length of the message + * @param secret_key [in] secret key + */ +EXPORT OQS_STATUS crypto_sign_sign(uint8_t *signature, + size_t *signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *secret_key); + +/** + * Verifies a signature with the public key + * @param message [in] message to verify + * @param message_len [in] length of the message + * @param signature [in] signature to verify + * @param signature_len [in] length of the signature + * @param public_key [in] public key + * @return OQS_SUCCESS on successful verification, OQS_FAILURE on failure + */ +EXPORT OQS_STATUS crypto_sign_verify(const uint8_t *signature, + size_t signature_len, + const uint8_t *message, + size_t message_len, + const uint8_t *public_key); + +#endif // API_H diff --git a/src/sig/sdith/sdith_l5_gf2_short_ref/params.h b/src/sig/sdith/sdith_l5_gf2_short_ref/params.h new file mode 100644 index 0000000000..18564aa32b --- /dev/null +++ b/src/sig/sdith/sdith_l5_gf2_short_ref/params.h @@ -0,0 +1,20 @@ +#ifndef SDITH_LIBOQS_PARAMS_H +#define SDITH_LIBOQS_PARAMS_H + +/* SDitH3-L5-gf2-short, ref implementation: the settings api.c is built with. */ + +#ifndef SDITH3_FOR_LIBOQS +#define SDITH3_FOR_LIBOQS +#endif +#ifndef NDEBUG +#define NDEBUG +#endif + +#define APPLY_NAMESPACE oqs_sig_private_sdith_ref_ +#define APPLY_PUBLIC_API_NAMESPACE oqs_sig_pubapi_sdith_l5_gf2_short_ +#define CRYPTO_SECRETKEYBYTES 275 +#define CRYPTO_PUBLICKEYBYTES 132 +#define CRYPTO_BYTES 15147 +#define SIGNATURE_PARAMS CAT5_SHORT_PARAMETERS + +#endif // SDITH_LIBOQS_PARAMS_H diff --git a/src/sig/sdith/sdith_sdith_common/LICENSE.txt b/src/sig/sdith/sdith_sdith_common/LICENSE.txt new file mode 100644 index 0000000000..599479c32a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/LICENSE.txt @@ -0,0 +1,235 @@ +======================================================================== +Apache 2.0 License +======================================================================== + 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. + +======================================================================== +Third-Party Components & Subcomponent Licenses +======================================================================== +This software includes the following third-party components under distinct licenses: + +lib/sha3: + copied from The eXtended Keccak Code Package (XKCP) (multiple licenses) + https://github.com/XKCP/XKCP + only build files have been edited (CMakeLists.txt) + +lib/aes/aes_ansi_ref.c/.h: + ANSI C Rijndael code by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto -- public domain + A little-endian version of the algorithm is provided in aes_ansi_littleendian_ref.c + the avx implementation via the aes-ni instructions are new, and covered by the main repository license. + +lib/aes/rijndael256_avx.c/.h: + The following part is adapted from a work by Nir Drucker and Shay Gueron: + Software optimization of Rijndael for Modern x86_64 platforms, + in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) + Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. + (SPDX-License-Identifier: Apache-2.0) + +kat/*/PQCgenKAT_sign.c, rng.c, rng.h: + NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the + software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative + works of the software or any portion of the software, and you may copy and distribute such modifications or works. + Modified works should carry a notice stating that you changed the software and should note the date and nature of any + such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the + software. + diff --git a/src/sig/sdith/sdith_sdith_common/NOTICE b/src/sig/sdith/sdith_sdith_common/NOTICE new file mode 100644 index 0000000000..f372dc9e28 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/NOTICE @@ -0,0 +1,28 @@ +Copyright 2026 The SDitH Consortium + +This product includes software developed by: + +lib/sha3: + copied from The eXtended Keccak Code Package (XKCP) (multiple licenses) + https://github.com/XKCP/XKCP + only build files have been edited (CMakeLists.txt) + +lib/aes/aes_ansi_ref.c/.h: + ANSI C Rijndael code by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto -- public domain + A little-endian version of the algorithm is provided in aes_ansi_littleendian_ref.c + the avx implementation via the aes-ni instructions are new, and covered by the main repository license. + +lib/aes/rijndael256_avx.c/.h: + The following part is adapted from a work by Nir Drucker and Shay Gueron: + Software optimization of Rijndael for Modern x86_64 platforms, + in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) + Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. + (SPDX-License-Identifier: Apache-2.0) + +kat/*/PQCgenKAT_sign.c, rng.c, rng.h: + NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the + software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative + works of the software or any portion of the software, and you may copy and distribute such modifications or works. + Modified works should carry a notice stating that you changed the software and should note the date and nature of any + such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the + software. diff --git a/src/sig/sdith/sdith_sdith_common/aes128_ctrle.h b/src/sig/sdith/sdith_sdith_common/aes128_ctrle.h new file mode 100644 index 0000000000..49c95440e1 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/aes128_ctrle.h @@ -0,0 +1,79 @@ +#ifndef AES128_CTRLE_H +#define AES128_CTRLE_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif +#include "rijndael256_ctrle.h" + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +/** (special API) batched key schedule: expand 1..4 independent aes128 keys into + * 1..4 round-key buffers (each 16*11 bytes). Output is bit-identical to + * aes128_ctrle_set_key, so these are KAT-preserving. The x2/x3/x4 avx2 variants + * interleave the expansions to hide latency; the ref variants just loop. */ +EXPORT void aes128_key_schedule_x1_ref(void* rk0, const void* k0); +EXPORT void aes128_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void aes128_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, const void* k2); +EXPORT void aes128_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); +EXPORT void aes128_key_schedule_x1_avx2(void* rk0, const void* k0); +EXPORT void aes128_key_schedule_x2_avx2(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void aes128_key_schedule_x3_avx2(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, const void* k2); +EXPORT void aes128_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); + +/** (special API) no-carry CTR encryption. Encrypts N consecutive blocks: + * out[i] = AES(round_keys, ctr_block with its low 64 bits += i), for i in 0..N-1. + * Only the low 64 bits of the counter are incremented (no carry into the upper + * 64 bits). Stateless: ctr_block (16 bytes) is not modified. The fixed-size + * building blocks chain into aes128_ctrle_nocarry_nblocks (advance the low-64 + * counter by the group size between calls). */ +EXPORT void aes128_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_3blocks_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_4blocks_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, uint64_t nblocks); +EXPORT void aes128_ctrle_nocarry_1block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_2block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_3blocks_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_4blocks_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_nblocks_avx2(void* out, const void* round_keys, const void* ctr_block, uint64_t nblocks); +// 4 keys x 2 counter blocks (8 blocks) interleaved: for key i (round keys at round_keys4 + i*176, +// base counter at ctr4blk + i*16) writes enc(ctr_i) || enc(ctr_i+1) to out + i*32. Byte-identical +// to four aes128_ctrle_nocarry_2block_avx2 calls (KAT-preserving); keeps 8 aesenc in flight. +EXPORT void aes128_ctrle_nocarry_2blk_x4keys_avx2(void* out, const void* round_keys4, const void* ctr4blk); + +/** + * (special API) AES proof-of-work grind over two independent keys. + * Encrypts the two plaintext blocks in_pt256 (p0 || p1, 32 bytes) under the two round-key sets + * rk128 (rk[2][11], 352 bytes), + * If the ciphertexts satisfy the grinding condition: ((c0.lo64 ^ c1.lo64) & mask_w) == 0, success: + * return store the counter and the ciphertexts and return 1. + * Otherwise, increment the counter and the plaintexts by 1 (no carry into the high 64 bits) and restart. + * If the counter reaches 2^32 with no hit, stores 2^32 in *in_out_counter and returns 0. + * The winning counter is the smallest one in [initial, 2^32). + */ +EXPORT int aes128_proofow_grind_avx2( // + void* out_ct256, // [out] c0 || c1 (32 bytes) satisfying low64(c0 ^ c1) & mask_w == 0 + uint64_t* in_out_counter, // [in/out] starting counter (< 2^32) + const void* in_pt256, // [in] p0 || p1 (32 bytes) the initial plaintexts + const void* rk128, // [in] matrix of round keys v128[2][11] + uint64_t mask_w // [in] the grinding condition +); + +typedef union { + __uint128_t u128; + uint64_t v64[2]; + uint8_t v8[16]; +} ctr128_t; + +#endif // AES128_CTRLE_H diff --git a/src/sig/sdith/sdith_sdith_common/aes128_ctrle_special_ref.c b/src/sig/sdith/sdith_sdith_common/aes128_ctrle_special_ref.c new file mode 100644 index 0000000000..6c3dddd899 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/aes128_ctrle_special_ref.c @@ -0,0 +1,71 @@ +#include + +#include "aes128_ctrle.h" +#include "aes_ansi_ref.h" + +#ifdef SDITH3_FOR_LIBOQS +#include +#endif + +/* -------- batched key schedule (ref: just loop the scalar x1) -------- */ +EXPORT void aes128_key_schedule_x1_ref(void* rk0, const void* k0) { aes128_set_key_ref(rk0, k0); } +EXPORT void aes128_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1) { + aes128_set_key_ref(rk0, k0); + aes128_set_key_ref(rk1, k1); +} +EXPORT void aes128_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, + const void* k2) { + aes128_set_key_ref(rk0, k0); + aes128_set_key_ref(rk1, k1); + aes128_set_key_ref(rk2, k2); +} +EXPORT void aes128_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + aes128_set_key_ref(rk0, k0); + aes128_set_key_ref(rk1, k1); + aes128_set_key_ref(rk2, k2); + aes128_set_key_ref(rk3, k3); +} + +/* -------- no-carry CTR encryption (ref) -------- + * block i uses the counter with only its low 64 bits incremented by i; there is + * no carry into the upper 64 bits (that is the caller's guarantee). */ +static inline void aes128_nocarry_ref_impl(void* out, const void* round_keys, const void* ctr_block, uint64_t nblocks) { + ctr128_t ctr; + uint8_t* oo = (uint8_t*)out; + memcpy(ctr.v8, ctr_block, 16); +#ifndef SDITH3_FOR_LIBOQS + /* reference implementation */ + for (uint64_t i = 0; i < nblocks; ++i) { + aes128_encrypt_1block_ref(oo + 16 * i, ctr.v8, round_keys); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } +#else + /* LIBOQS implementation: round_keys caches a schedule pointer (see aes_glue.c), + * it is not a raw key. ECB over nblocks*16 bytes is nblocks independent block + * encryptions, so the whole counter run goes out in a single call. */ + void* schedule = NULL; + memcpy(&schedule, round_keys, sizeof(void*)); + for (uint64_t i = 0; i < nblocks; ++i) { + memcpy(oo + 16 * i, ctr.v8, 16); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } + OQS_AES128_ECB_enc_sch(oo, 16 * nblocks, schedule, oo); +#endif +} +EXPORT void aes128_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 1); +} +EXPORT void aes128_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 2); +} +EXPORT void aes128_ctrle_nocarry_3blocks_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 3); +} +EXPORT void aes128_ctrle_nocarry_4blocks_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 4); +} +EXPORT void aes128_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, nblocks); +} diff --git a/src/sig/sdith/sdith_sdith_common/aes_ansi_ref.h b/src/sig/sdith/sdith_sdith_common/aes_ansi_ref.h new file mode 100644 index 0000000000..5032734aed --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/aes_ansi_ref.h @@ -0,0 +1,56 @@ +#ifndef AES_ANSI_REF_H +#define AES_ANSI_REF_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +/* References implimentations */ + +/* aes128 reference implementation of the key scheduling (warning:big endian round keys) */ +EXPORT void aes128_set_key_ref(void* rk, const void* key128); +/* aes128 reference implementation of the encryption (1 single block) */ +EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk); + + +/* LIBOQS integration glue */ + +/* The below functions are either no-ops or just call the above functions when + * not building for liboqs. When building for liboqs,`integration/liboqs/aes_glue.c` + * impliments these to dispatch to liboqs' AES. + * + * LIBOQS uses a heap-allocated schedule for each key, so a single schedule + * pointer is written into each round-key buffer instead of the round keys + * themselves, and that schedule is replaced when the buffer is reused. The + * following functions help to prepare, reuse, and release the round-key + * buffers. + */ + +/* Prepare an nslots x slot_bytes array of round-key buffers. + * + * Marks every slot empty, so that the first aes128_set_key_reuse_ref call on a + * slot loads a schedule and every later one replaces it. + */ +EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes); + +/* Replace the key of the schedule held by a prepared buffer. + * + * @warning The buffer MUST have been prepared with aes128_prepare_rk_buffer first. + */ +EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128); + +/* Release a key schedule created by aes128_set_key_ref or aes128_set_key_reuse_ref. + * A no-op on a prepared buffer whose slot was never keyed. */ +EXPORT void aes128_release_key(void *rk); + +#endif // AES_ANSI_REF_H diff --git a/src/sig/sdith/sdith_sdith_common/aes_glue.c b/src/sig/sdith/sdith_sdith_common/aes_glue.c new file mode 100644 index 0000000000..6b80b56ee7 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/aes_glue.c @@ -0,0 +1,48 @@ +#include + +#include "aes_ansi_ref.h" + +#include +#include + + +EXPORT void aes128_set_key_ref(void* rk, const void* key128) { + // Allocates a schedule via liboqs and writes the pointer to the schedule into the rk buffer + void* schedule = NULL; + OQS_AES128_ECB_load_schedule(key128, &schedule); + memcpy(rk, &schedule, sizeof(void*)); +} + +EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk) { + // Interprets first sizeof(void *) bytes of rk as a schedule pointer for liboqs ctx + void* schedule = NULL; + memcpy(&schedule, rk, sizeof(void*)); + OQS_AES128_ECB_enc_sch(in_pt128, 16, schedule, out_ct128); +} + +EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes) { + // Marks every slot empty by zeroing its schedule pointer. + // No schedule is allocated here: `aes128_set_key_reuse_ref` does this in a later call + uint8_t* p = (uint8_t*) rk; + for (uint64_t i = 0; i < nslots; ++i) { + memset(p + i * slot_bytes, 0, sizeof(void*)); + } +} + +EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128) { + // The slot holds a schedule rather than round keys, so replacing the key means + // freeing any schedule already there and loading a new one in its place. + aes128_release_key(rk); + aes128_set_key_ref(rk, key128); +} + + +EXPORT void aes128_release_key(void* rk) { + // Interprets first sizeof(void *) bytes of rk as a schedule pointer for liboqs ctx + void* schedule = NULL; + memcpy(&schedule, rk, sizeof(void*)); + // An empty slot has nothing to free. + if (schedule == NULL) return; + OQS_AES128_free_schedule(schedule); + OQS_MEM_cleanse(rk, sizeof(void*)); +} diff --git a/src/sig/sdith/sdith_sdith_common/commons.c b/src/sig/sdith/sdith_sdith_common/commons.c new file mode 100644 index 0000000000..bcc761f001 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/commons.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include + +#include "sdith_prng.h" +#include "vole_private.h" + +/** binary valuation of i (also known as hamming weight of i ^ (i - 1) - 1) */ +uint16_t binval_of(uint16_t i) { + CASSERT(i != 0, "binval_of(0) is undefined"); + return __builtin_ctz(i); +} + +// compat function, to use in case of the builtin above does not exist +uint16_t binval_of_compat(uint16_t i) { + uint16_t u = i ^ (i - 1) ^ 1; + // return _mm_popcnt_u32(u); + u = (u & 0x5555) + ((u >> 1) & 0x5555); + u = (u & 0x3333) + ((u >> 2) & 0x3333); + u = (u & 0x0f0f) + ((u >> 4) & 0x0f0f); + u = (u & 0x00ff) + ((u >> 8) & 0x00ff); + return u; +} + +/** grey encoding of x */ +uint16_t grey_of(uint16_t x) { return x ^ (x >> 1); } + +/** inverse o grey encoding of x */ +uint16_t inv_grey_of(uint16_t x) { + uint16_t u = x; + for (uint16_t i = 1; i < 16; ++i) { + u ^= (x >> i); + } + return u; +} + +/** value of the pos-th bit of x (little endian index) */ +uint8_t bit_of(uint16_t x, uint16_t pos) { return (x >> pos) & 1; } + + +/** raise to the power p */ +EXPORT void flambda_power(const vole_parameters* vole_params, flambda_t* res, const flambda_t* x, uint64_t p) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + flambda_max_t tx; + memcpy(tx, x, lambda_bytes); + memset(res, 0, lambda_bytes); + *((uint8_t*)res) = 1; + // invariant: res * tx^p = cst + while (p > 0) { + if (p & 1) { + vole_params->flambda_product(res, res, tx); + --p; + } + if (p == 0) break; + vole_params->flambda_product(tx, tx, tx); + p >>= 1; + } +} + +/** test if a field element is zero (non-ct version) */ +EXPORT uint8_t flambda_is_zero_nonct(const vole_parameters* vole_params, const flambda_t* x) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint8_t* const xx = (const uint8_t*)x; + for (uint64_t i = 0; i < lambda_bytes; ++i) { + if (xx[i]) return 0; + } + return 1; +} + +/** test if a bit vector is zero (non-ct version) */ +EXPORT uint8_t bitvec_is_zero_nonct(const uint8_t* x, uint64_t num_bits) { + while (num_bits >= 8) { + if (*x) return 0; + ++x; + num_bits -= 8; + } + if (num_bits > 0) { + uint8_t mask = ((uint8_t)(1) << num_bits) - 1; + if ((*x) & mask) return 0; + } + return 1; +} diff --git a/src/sig/sdith/sdith_sdith_common/commons.h b/src/sig/sdith/sdith_sdith_common/commons.h new file mode 100644 index 0000000000..d30521b080 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/commons.h @@ -0,0 +1,55 @@ +#ifndef COMMONS_H +#define COMMONS_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#define EXPORT_DECL extern "C" +#include +#else +#define EXPORT +#define EXPORT_DECL extern +#include "stdint.h" +#endif + +#ifdef __x86_64__ +#define CPU_SUPPORTS(feature) __builtin_cpu_supports(feature) +#endif + +/* Namespacing with the appropriate prefix */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +typedef void bitvec_t; // vector of bits row major (dimensions provided at runtime) +typedef void bitmat_t; // matrix of bits row major (dimensions provided at runtime) +typedef void flambda_t; // at runtime, the size of a big fielf elem is lam (i.e. lambda/8) +typedef void fpoly_t; // at runtime, the size of a degree d is (d+1).lam +typedef void seed_t; // at runtime, the size of a commit is 1.lam +typedef void salt_t; // at runtime, the size of a commit is 1.lam +typedef void hash_t; // at runtime, the size of a hash is 2.lam +typedef void commit_t; // at runtime, the size of a commit is 2.lam +typedef void hash_ctx_t; + +// type large enough to hold one field element +typedef uint64_t flambda_max_t[4] __attribute((aligned(32))); // usable as data type for temporary variables + +typedef enum proofow_variant_t { + PROOFOW_VARIANT_SHAKE = 0, + PROOFOW_VARIANT_CIPHER = 1 +} proofow_variant_t; + +#endif // COMMONS_H diff --git a/src/sig/sdith/sdith_sdith_common/ct_utils.c b/src/sig/sdith/sdith_sdith_common/ct_utils.c new file mode 100644 index 0000000000..950f4a6164 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/ct_utils.c @@ -0,0 +1,89 @@ +#include "sdith_ct_utils.h" + +#include + +#include "vole_private.h" + +// Reference constant-time helpers. +// +// As stated in sdith_ct_utils.h, these are the readable definitions, not the +// hardened implementations: they say what each function computes, and the _avx +// ones in ct_utils_avx2.c say how to compute it without giving the compiler +// room to reintroduce a branch. A C compiler may legally turn any of the masks +// below back into a conditional jump, so a build that must actually be +// constant-time has to use the _avx table. + +EXPORT uint64_t mask_lt_ct_ref(uint64_t secret_a, uint64_t secret_b) { + return -(uint64_t)(secret_a < secret_b); +} + +EXPORT uint64_t mask_eq_ct_ref(uint64_t secret_a, uint64_t secret_b) { + return -(uint64_t)(secret_a == secret_b); +} + +// Schoolbook restoring division, most significant bit first: bring one bit of n +// down into the remainder, and subtract d whenever the remainder has grown past +// it. rem stays below 2*d < 2^33, hence the 64-bit accumulator. +EXPORT void div_rem_u32_ct_ref(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d) { + CREQUIRE(public_d != 0, "division by zero"); + uint64_t rem = 0; + uint32_t quo = 0; + for (int64_t i = 31; i >= 0; --i) { + rem = (rem << 1) | ((secret_n >> i) & 1); + if (rem >= public_d) { + rem -= public_d; + quo |= (uint32_t)1 << i; + } + } + *q = quo; + *r = (uint32_t)rem; +} + +// res ^= b, or res unchanged, depending on the mask: a whole-vector select +// written as an AND so that both outcomes run the same instructions. +EXPORT void bitvec_xor_to_masked_ct_ref(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask) { + uint8_t* const r = (uint8_t*)res; + const uint8_t* const b = (const uint8_t*)secret_b; + const uint8_t m8 = (uint8_t)secret_mask; + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] ^= b[i] & m8; + } +} + +// The field lands at a position known to the attacker, so the bytes it touches +// can be addressed directly: only the bits being written are secret. Both the +// offset and the width are public, so the byte range is exact -- the caller's +// vector never needs slack past the last field. +EXPORT void bitvec_xoru32_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value) { + uint8_t* const r = (uint8_t*)res; + CREQUIRE(public_nbits <= 32, "field too wide (%" PRId64 " bits)", public_nbits); + const uint64_t first_byte = public_bitpos >> 3; + const uint64_t shift = public_bitpos & 7; + const uint64_t nbytes = (shift + public_nbits + 7) >> 3; + CREQUIRE(first_byte + nbytes <= bytelen, // + "field [%" PRId64 ",+%" PRId64 ") out of range (bytelen %" PRId64 ")", public_bitpos, public_nbits, bytelen); + // keep only the low public_nbits bits: the width is public, so is the mask + const uint32_t field_mask = public_nbits >= 32 ? UINT32_C(-1) : (UINT32_C(1) << public_nbits) - 1; + const uint64_t shifted = (uint64_t)(secret_value & field_mask) << shift; + for (uint64_t k = 0; k < nbytes; ++k) { + r[first_byte + k] ^= (uint8_t)(shifted >> (8 * k)); + } +} + +// Here the position itself is secret, so it cannot be used to address memory: +// every word of the vector is read and written, and a mask picks the one that +// actually changes. Cost is the whole vector per call instead of one byte. +EXPORT void bitvec_xorbit_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask) { + uint8_t* const r = (uint8_t*)res; + // debug-only: a range check on a secret would itself be a branch on a secret. + // Out of range is harmless anyway -- no byte matches, so the call is a no-op. + CASSERT((secret_bitpos >> 3) < bytelen, // + "bitpos %" PRId64 " out of range (bytelen %" PRId64 ")", secret_bitpos, bytelen); + const uint64_t target_byte = secret_bitpos >> 3; + const uint8_t bit = (uint8_t)1 << (secret_bitpos & 7); + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] ^= bit & (uint8_t)mask_eq_ct_ref(i, target_byte) & (uint8_t)secret_mask; + } +} diff --git a/src/sig/sdith/sdith_sdith_common/fips202_glue.h b/src/sig/sdith/sdith_sdith_common/fips202_glue.h new file mode 100644 index 0000000000..70e1cf1676 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/fips202_glue.h @@ -0,0 +1,44 @@ +#ifndef FIPS202_GLUE_H +#define FIPS202_GLUE_H + +#include + +typedef xof_ctx Keccak_HashInstance; // defined in sdith_prng.h + +static inline void Keccak_HashInitialize_SHAKE128(Keccak_HashInstance* inst) { + inst->shake = 128; + OQS_SHA3_shake128_inc_init(&inst->shake128_state); +} + +static inline void Keccak_HashInitialize_SHAKE256(Keccak_HashInstance* inst) { + inst->shake = 256; + OQS_SHA3_shake256_inc_init(&inst->shake256_state); +} + +// XKCP lengths are in bits, liboqs lengths are in bytes +static inline void Keccak_HashUpdate(Keccak_HashInstance* inst, const void* data, uint64_t databitlen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_absorb(&inst->shake128_state, data, databitlen >> 3); + } else { + OQS_SHA3_shake256_inc_absorb(&inst->shake256_state, data, databitlen >> 3); + } +} + +static inline void Keccak_HashFinal(Keccak_HashInstance* inst, void* hashval) { + (void)hashval; // XKCP ignores it for SHAKE + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_finalize(&inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_finalize(&inst->shake256_state); + } +} + +static inline void Keccak_HashSqueeze(Keccak_HashInstance* inst, void* data, uint64_t databitlen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_squeeze(data, databitlen >> 3, &inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_squeeze(data, databitlen >> 3, &inst->shake256_state); + } +} + +#endif diff --git a/src/sig/sdith/sdith_sdith_common/fips202x4_glue.h b/src/sig/sdith/sdith_sdith_common/fips202x4_glue.h new file mode 100644 index 0000000000..a9dc109bc1 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/fips202x4_glue.h @@ -0,0 +1,109 @@ +#ifndef FIPS202X4_GLUE_H +#define FIPS202X4_GLUE_H + +#include + +#include +#include + +typedef struct { + uint32_t shake; // 128 or 256, set by SpongeInitialize + union { + OQS_SHA3_shake128_inc_ctx shake128_state; + OQS_SHA3_shake256_inc_ctx shake256_state; + }; +} KeccakWidth1600_SpongeInstance; + +typedef struct { + uint32_t shake; // 128 or 256, set by SpongeInitialize + union { + OQS_SHA3_shake128_x4_inc_ctx shake128_state; + OQS_SHA3_shake256_x4_inc_ctx shake256_state; + }; +} KeccakWidth1600times4_SpongeInstance; + + +static inline void KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance* inst, unsigned int rate, + unsigned int capacity) { + (void)rate; // only read by the asserts, which NDEBUG removes + inst->shake = capacity / 2; // SHAKE128 has capacity 256 and SHAKE256 has capacity 512 + if (inst->shake == 128) { + assert(rate == (OQS_SHA3_SHAKE128_RATE << 3)); // XKCP rates are in bits, liboqs rates in bytes + OQS_SHA3_shake128_inc_init(&inst->shake128_state); + } else { + assert(rate == (OQS_SHA3_SHAKE256_RATE << 3)); + OQS_SHA3_shake256_inc_init(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600_SpongeAbsorb(KeccakWidth1600_SpongeInstance* inst, const unsigned char* data, + size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_absorb(&inst->shake128_state, data, dataByteLen); + } else { + OQS_SHA3_shake256_inc_absorb(&inst->shake256_state, data, dataByteLen); + } +} + +// sdith always passes 0x1F (the SHAKE padding), which liboqs's finalize applies +static inline void KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance* inst, + unsigned char delimitedData) { + (void)delimitedData; // liboqs finalize applies the delimiter already + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_finalize(&inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_finalize(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance* inst, unsigned char* data, + size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_squeeze(data, dataByteLen, &inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_squeeze(data, dataByteLen, &inst->shake256_state); + } +} + +static inline void KeccakWidth1600times4_SpongeInitialize(KeccakWidth1600times4_SpongeInstance* inst, + unsigned int rate, unsigned int capacity) { + (void)rate; // implied by capacity + inst->shake = capacity / 2; // SHAKE128 has capacity 256 and SHAKE256 has capacity 512 + if (inst->shake == 128) { + assert(rate == (OQS_SHA3_SHAKE128_RATE << 3)); // XKCP in bits, liboqs in bytes + OQS_SHA3_shake128_x4_inc_init(&inst->shake128_state); + } else { + assert(rate == (OQS_SHA3_SHAKE256_RATE << 3)); + OQS_SHA3_shake256_x4_inc_init(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600times4_SpongeAbsorb(KeccakWidth1600times4_SpongeInstance* inst, + const unsigned char** data, size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_x4_inc_absorb(&inst->shake128_state, data[0], data[1], data[2], data[3], dataByteLen); + } else { + OQS_SHA3_shake256_x4_inc_absorb(&inst->shake256_state, data[0], data[1], data[2], data[3], dataByteLen); + } +} + +static inline void KeccakWidth1600times4_SpongeAbsorbLastFewBits(KeccakWidth1600times4_SpongeInstance* inst, + unsigned char delimitedData) { + (void)delimitedData; // liboqs finalize applies the delimiter already + if (inst->shake == 128) { + OQS_SHA3_shake128_x4_inc_finalize(&inst->shake128_state); + } else { + OQS_SHA3_shake256_x4_inc_finalize(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600times4_SpongeSqueeze(KeccakWidth1600times4_SpongeInstance* inst, + unsigned char** data, size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_x4_inc_squeeze(data[0], data[1], data[2], data[3], dataByteLen, &inst->shake128_state); + } else { + OQS_SHA3_shake256_x4_inc_squeeze(data[0], data[1], data[2], data[3], dataByteLen, &inst->shake256_state); + } +} + +#endif diff --git a/src/sig/sdith/sdith_sdith_common/gf128.c b/src/sig/sdith/sdith_sdith_common/gf128.c new file mode 100644 index 0000000000..9bc5a9a2bf --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/gf128.c @@ -0,0 +1,247 @@ +#include "inttypes.h" +#include "vole_private.h" + +const gf128 GF128_ZERO = {.v128 = 0}; +const gf128 GF128_ONE = {.v128 = 1}; + +SDITH_ALWAYS_INLINE uint8_t gf128p_equals(const gf128* const a, const gf128* const b) { return a->v128 == b->v128; } + +void gf128p_sum(gf128* const res, const gf128* const a, const gf128* const b) { gf128_sum_ref(res, a, b); } + +SDITH_ALWAYS_INLINE uint8_t gf128p_bitof(const gf128* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 128, "bad bit position %" PRIu64, position); + return (a->v128 >> position) & 1; +} + +void gf128p_lsh(gf128* const res, const gf128* const a, const uint64_t amount) { + CREQUIRE(amount < 128, "bad left shift amount %" PRIu64, amount); + res->v128 = a->v128 << amount; +} + +void gf128p_rsh(gf128* const res, const gf128* const a, const uint64_t amount) { + CREQUIRE(amount < 128, "bad right shift amount %" PRIu64, amount); + res->v128 = a->v128 >> amount; +} + +void gf128p_mul(gf128* const res, const gf128* const a, const gf128* const b) { gf128_product_ref(res, a, b); } + +uint8_t gf128v_equals(const gf128 a, const gf128 b) { return gf128p_equals(&a, &b); } + +gf128 gf128v_sum(const gf128 a, const gf128 b) { + gf128 res; + gf128p_sum(&res, &a, &b); + return res; +} + +uint8_t gf128v_bitof(const gf128 a, const uint64_t position) { return gf128p_bitof(&a, position); } + +gf128 gf128v_lsh(const gf128 a, const uint64_t amount) { + gf128 res; + gf128p_lsh(&res, &a, amount); + return res; +} + +gf128 gf128v_rsh(const gf128 a, const uint64_t amount) { + gf128 res; + gf128p_rsh(&res, &a, amount); + return res; +} + +gf128 gf128v_mul(const gf128 a, const gf128 b) { + gf128 res; + gf128p_mul(&res, &a, &b); + return res; +} + +EXPORT void gf128_set_ref(gf128* res, const gf128* a) { *res = *a; } +EXPORT void gf128_flambda_set_ref(flambda_t* res, const flambda_t* a) { + gf128_set_ref((gf128*) res, (const gf128*) a); +}; + + +void gf128_sum_ref(gf128* res, const gf128* a, const gf128* b) { res->v128 = a->v128 ^ b->v128; } +EXPORT void gf128_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_sum_ref((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +__uint128_t gfprod128(__uint128_t a, __uint128_t b) { + __uint128_t tt = a; + __uint128_t rr = 0; + for (uint64_t i = 0; i < 128; ++i) { + rr ^= (-((b >> i) & (__uint128_t)1)) & tt; + tt = ((-(tt >> 127)) & GF128_P) ^ (tt << 1); + } + return rr; +} + +void gf128_product_ref(gf128* res, const gf128* a, const gf128* b) { res->v128 = gfprod128(a->v128, b->v128); } +EXPORT void gf128_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_product_ref((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +__uint128_t gfprod128_f2(__uint128_t a, __uint128_t b) { return (-b) & a; } + +void gf128_product_f2_ref(gf128* res, const gf128* a, const gf128* b) { res->v128 = gfprod128_f2(a->v128, b->v128); } +EXPORT void gf128_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2) { + gf128_product_f2_ref((gf128*) res, (const gf128*) a, (const gf128*) b_f2); +} + + +EXPORT void gf128_dot_product_ref(gf128* res, const gf128* x, const gf128* y, const uint64_t size) { + __uint128_t acc = 0; + for (uint64_t i = 0; i < size; ++i) { + acc ^= gfprod128(x[i].v128, y[i].v128); + } + res->v128 = acc; +} +EXPORT void gf128_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf128_dot_product_ref((gf128*) res, (const gf128*) x, (const gf128*) y, size); +} + + +EXPORT void gf128_dot_product_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf128); + __uint128_t acc = res->v128; + for (uint64_t i = 0; i < size; ++i) { + acc ^= gfprod128(x[i * xbs].v128, y[i].v128); + } + res->v128 = acc; +} +EXPORT void gf128_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf128_dot_product_acc_ref((gf128*) res, (const gf128*) x, x_byte_slice, (const gf128*) y, size); +} + + +EXPORT void gf128_dot_product_f2_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf128); + __uint128_t acc = res->v128; + for (uint64_t i = 0; i < size; ++i) { + acc ^= gfprod128_f2(x[i * xbs].v128, y_f2[i].v128); + } + res->v128 = acc; +} +EXPORT void gf128_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf128_dot_product_f2_acc_ref((gf128*) res, (const gf128*) x, x_byte_slice, (const gf128*) y_f2, size); +} + + +EXPORT void gf128_inverse_ref(gf128* res, const gf128* a) { + // this is the euclidian algorithm to compute the extended gcd + __uint128_t aa = a->v128; + CREQUIRE(aa != 0, "inverse of 0"); + __uint128_t uu = 1; + uint64_t log2a = 127; + while (((aa >> log2a) & 1) == 0) --log2a; + if (log2a == 0) { // a == 1: inverse is 1. Early-out also avoids the aa << 128 UB below. + res->v128 = 1; + return; + } + __uint128_t bb = GF128_P ^ (aa << (128 - log2a)); + __uint128_t vv = uu << (128 - log2a); + uint64_t log2b = 127; + while (log2a != 0) { + CASSERT(gfprod128(a->v128, uu) == aa, "bug1"); + CASSERT(gfprod128(a->v128, vv) == bb, "bug2"); + while (log2b >= log2a) { + if ((bb >> log2b) & 1) { + bb ^= (aa << (log2b - log2a)); + vv ^= (uu << (log2b - log2a)); + } + --log2b; + } + // swap aa <-> bb, uu <-> vv + __uint128_t tmp = aa; + aa = bb; + bb = tmp; + tmp = uu; + uu = vv; + vv = tmp; + uint64_t tmp2 = log2a; + log2a = log2b; + log2b = tmp2; + // update log2a + CASSERT(aa != 0, "bug3"); + while (((aa >> log2a) & 1) == 0) --log2a; + } + CASSERT(aa == 1, "bug4"); + res->v128 = uu; +} +EXPORT void gf128_flambda_inverse_ref(flambda_t* res, const flambda_t* a) { + gf128_inverse_ref((gf128*) res, (const gf128*) a); +} + + +EXPORT void gf128_sum_pow2_naive(gf128* res, const gf128* x) { + static const __uint128_t ONE = 1; + __uint128_t r = 0; + for (uint64_t i = 0; i < 128; ++i) { + r ^= gfprod128(ONE << i, x[i].v128); + } + res->v128 = r; +} + +EXPORT void gf128_sum_pow2_ref(gf128* res, const gf128* x) { + __uint128_t left = x[0].v128; + __uint128_t right = 0; + for (uint64_t i = 1; i < 128; ++i) { + __uint128_t xi = x[i].v128; + left ^= xi << i; + right ^= xi >> (128 - i); + } + res->v128 = left ^ gfprod128(GF128_P, right); +} +EXPORT void gf128_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x) { + gf128_sum_pow2_ref((gf128*) res, (const gf128*) x); +} + + +void gf128_echelon_pow2_naive(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + CREQUIRE(k > 0, "k not supported"); + CREQUIRE(k * x_size <= 128, "echelon width not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf128); + gf128 ONE = GF128_ONE; + gf128 r = GF128_ZERO; + gf128 tmp; + for (uint64_t i = 0; i < x_size; ++i) { + gf128p_lsh(&tmp, &ONE, k * i); + gf128p_mul(&tmp, &tmp, x + i * xbs); + gf128p_sum(&r, &r, &tmp); + } + *res = r; +} + +void gf128_echelon_pow2_ref(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 128, "echelon width not supported"); + if (x_size == 0) { + *res = GF128_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf128); + static const gf128 PP = {.v128 = GF128_PV}; + gf128 left = x[0]; + gf128 right = GF128_ZERO; + gf128 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf128p_lsh(&tmp, x + i * xbs, k * i); + gf128p_sum(&left, &left, &tmp); + gf128p_rsh(&tmp, x + i * xbs, 128 - k * i); + gf128p_sum(&right, &right, &tmp); + } + gf128p_mul(&tmp, &right, &PP); + gf128p_sum(res, &left, &tmp); +} +EXPORT void gf128_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf128_echelon_pow2_ref(k, (gf128*) res, (const gf128*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common/gf192.c b/src/sig/sdith/sdith_sdith_common/gf192.c new file mode 100644 index 0000000000..f42ab6c58a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/gf192.c @@ -0,0 +1,343 @@ +#include +#include +#include +#include +#include + +#include "vole_private.h" + +const gf192 GF192_ZERO = {.v64 = {0, 0, 0}}; +const gf192 GF192_ONE = {.v64 = {1, 0, 0}}; + +SDITH_ALWAYS_INLINE uint8_t gf192p_equals(const gf192* const a, const gf192* const b) { + return memcmp(a->v, b->v, 24) == 0; +} + +SDITH_ALWAYS_INLINE void gf192p_sum(gf192* const res, const gf192* const a, const gf192* const b) { + gf192_sum_ref(res, a, b); +} + +SDITH_ALWAYS_INLINE uint8_t gf192p_bitof(const gf192* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 192, "bad bit position %" PRIu64, position); + const uint64_t q8 = position >> 3; + const uint64_t r8 = position & 7; + return (a->v[q8] >> r8) & 1; +} + +// 64-bit limb shifts (little-endian v64[3]). +// This function does not need to be CT: amount is always public in the hot callers (sum_pow2/echelon loop index); +// It is also used on delta by the ref_inverse +// which is also public since delta is part of the signature. +void gf192p_lsh(gf192* const res, const gf192* const a, const uint64_t amount) { + CREQUIRE(amount < 192, "bad left shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[3] = {0, 0, 0}; + if (rb == 0) { + for (uint64_t i = ql; i < 3; i++) o[i] = a->v64[i - ql]; + } else { + for (uint64_t i = 3; i-- > ql;) { + const uint64_t hi = a->v64[i - ql] << rb; + const uint64_t lo = (i - ql >= 1) ? (a->v64[i - ql - 1] >> (64 - rb)) : 0; + o[i] = hi | lo; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; +} + +void gf192p_rsh(gf192* const res, const gf192* const a, const uint64_t amount) { + CREQUIRE(amount < 192, "bad right shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[3] = {0, 0, 0}; + if (rb == 0) { + for (uint64_t i = 0; i + ql < 3; i++) o[i] = a->v64[i + ql]; + } else { + for (uint64_t i = 0; i + ql < 3; i++) { + const uint64_t lo = a->v64[i + ql] >> rb; + const uint64_t hi = (i + ql + 1 < 3) ? (a->v64[i + ql + 1] << (64 - rb)) : 0; + o[i] = lo | hi; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; +} + +SDITH_ALWAYS_INLINE void gf192p_mul(gf192* const res, const gf192* const a, const gf192* const b) { + gf192_product_ref(res, a, b); +} + +uint8_t gf192v_equals(const gf192 a, const gf192 b) { return gf192p_equals(&a, &b); } + +gf192 gf192v_sum(const gf192 a, const gf192 b) { + gf192 res; + gf192p_sum(&res, &a, &b); + return res; +} + +uint8_t gf192v_bitof(const gf192 a, const uint64_t position) { return gf192p_bitof(&a, position); } + +gf192 gf192v_lsh(const gf192 a, const uint64_t amount) { + gf192 res; + gf192p_lsh(&res, &a, amount); + return res; +} + +gf192 gf192v_rsh(const gf192 a, const uint64_t amount) { + gf192 res; + gf192p_rsh(&res, &a, amount); + return res; +} + +gf192 gf192v_mul(const gf192 a, const gf192 b) { + gf192 res; + gf192p_mul(&res, &a, &b); + return res; +} + +EXPORT void gf192_set_ref(gf192* res, const gf192* a) { *res = *a; } +EXPORT void gf192_flambda_set_ref(flambda_t* res, const flambda_t* a) { + gf192_set_ref((gf192*) res, (const gf192*) a); +} + +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b) { + for (uint64_t i = 0; i < 3; ++i) res->v64[i] = a->v64[i] ^ b->v64[i]; +} +EXPORT void gf192_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf192_sum_ref((gf192*) res, (const gf192*) a, (const gf192*) b); +} + + +EXPORT void gf192_product_ref(gf192* res, const gf192* a, const gf192* b) { + // deal with the in-place issue + if (res == b) { + gf192 tmp; + gf192p_mul(&tmp, a, b); + memcpy(res->v, tmp.v, 24); + return; + } + // Out of place product, constant-time and word-level. The 3x3 carryless limb + // products (Karatsuba gf_clmul64) are accumulated into a 384-bit result, then + // reduced modulo the field polynomial x^192 + x^7 + x^2 + x + 1 (0x87) with + // sparse shift-xors. There is no data-dependent branch or memory access, so + // the running time is independent of the secret bits of a and b (this runs on + // prover witness values, where a data-dependent branch would be a timing + // leak). The result is bit-identical to the schoolbook version, so all KATs + // are unchanged. Operand limbs are read before res is written, so res may + // alias a (res == b is handled by the guard above). + const uint64_t* const av = a->v64; + const uint64_t* const bv = b->v64; + uint64_t t[6] = {0}, hi, lo; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) { + gf_clmul64(av[i], bv[j], &hi, &lo); + t[i + j] ^= lo; + t[i + j + 1] ^= hi; + } + // fold the high 192 bits (t[3..5]) down: x^(192+n) = x^n * (x^7 + x^2 + x + 1) + uint64_t r0 = t[0], r1 = t[1], r2 = t[2], c; +#define GF192_FOLD(v, L, H) \ + do { \ + (L) = (v) ^ ((v) << 1) ^ ((v) << 2) ^ ((v) << 7); \ + (H) = ((v) >> 63) ^ ((v) >> 62) ^ ((v) >> 57); \ + } while (0) + GF192_FOLD(t[3], lo, hi); r0 ^= lo; r1 ^= hi; + GF192_FOLD(t[4], lo, hi); r1 ^= lo; r2 ^= hi; + GF192_FOLD(t[5], lo, hi); r2 ^= lo; c = hi; // c holds coefficients of bits 192..198 + r0 ^= c ^ (c << 1) ^ (c << 2) ^ (c << 7); // second fold; c <= 7 bits, no further overflow +#undef GF192_FOLD + res->v64[0] = r0; + res->v64[1] = r1; + res->v64[2] = r2; +} +EXPORT void gf192_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf192_product_ref((gf192*) res, (const gf192*) a, (const gf192*) b); +} + + +EXPORT void gf192_dot_product_ref(gf192* res, const gf192* x, const gf192* y, const uint64_t size) { + gf192 acc = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf192_product_ref(&tmp, &x[i], &y[i]); + gf192_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf192_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf192_dot_product_ref((gf192*) res, (const gf192*) x, (const gf192*) y, size); +} + + +EXPORT void gf192_dot_product_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf192); + gf192 acc = *res; + gf192 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf192_product_ref(&tmp, &x[i * xbs], &y[i]); + gf192_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf192_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf192_dot_product_acc_ref((gf192*) res, (const gf192*) x, x_byte_slice, (const gf192*) y, size); +} + + +EXPORT void gf192_dot_product_f2_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf192); + uint64_t acc0 = res->v64[0], acc1 = res->v64[1], acc2 = res->v64[2]; + for (uint64_t i = 0; i < size; ++i) { + const uint64_t mask = -y_f2[i].v64[0]; + acc0 ^= x[i * xbs].v64[0] & mask; + acc1 ^= x[i * xbs].v64[1] & mask; + acc2 ^= x[i * xbs].v64[2] & mask; + } + res->v64[0] = acc0; + res->v64[1] = acc1; + res->v64[2] = acc2; +} +EXPORT void gf192_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf192_dot_product_f2_acc_ref((gf192*) res, (const gf192*) x, x_byte_slice, (const gf192*) y_f2, size); +} + + +EXPORT void gf192_product_f2_ref(gf192* res, const gf192* a, const gf192* b_f2) { + const uint64_t mask = -b_f2->v64[0]; + for (uint64_t i = 0; i < 3; ++i) res->v64[i] = a->v64[i] & mask; +} +EXPORT void gf192_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2) { + gf192_product_f2_ref((gf192*) res, (const gf192*) a, (const gf192*) b_f2); +} + + +EXPORT void gf192_inverse_ref(gf192* res, const gf192* a) { + // this is the euclidian algorithm to compute the extended gcd + gf192 aa = *a; + CREQUIRE(!gf192p_equals(&aa, &GF192_ZERO), "inverse of 0"); + gf192 uu = GF192_ONE; + uint64_t log2a = 191; + while (gf192p_bitof(&aa, log2a) == 0) --log2a; + gf192 bb; + gf192p_lsh(&bb, &aa, 192 - log2a); + bb.v64[0] ^= GF192_P; + gf192 vv; + gf192p_lsh(&vv, &uu, 192 - log2a); + uint64_t log2b = 191; + while (log2a != 0) { + CASSERT(gf192v_equals(gf192v_mul(*a, uu), aa), "bug1"); + CASSERT(gf192v_equals(gf192v_mul(*a, vv), bb), "bug2"); + while (log2b >= log2a) { + if (gf192p_bitof(&bb, log2b)) { + gf192 tmp; + gf192p_lsh(&tmp, &aa, log2b - log2a); + gf192p_sum(&bb, &bb, &tmp); + gf192p_lsh(&tmp, &uu, log2b - log2a); + gf192p_sum(&vv, &vv, &tmp); + } + --log2b; + } + // swap aa <-> bb, uu <-> vv + gf192 tmp = aa; + aa = bb; + bb = tmp; + tmp = uu; + uu = vv; + vv = tmp; + uint64_t tmp2 = log2a; + log2a = log2b; + log2b = tmp2; + // update log2a + CASSERT(!gf192p_equals(&aa, &GF192_ZERO), "bug3"); + while (gf192p_bitof(&aa, log2a) == 0) --log2a; + } + CASSERT(gf192p_equals(&aa, &GF192_ONE), "bug4"); + *res = uu; +} +EXPORT void gf192_flambda_inverse_ref(flambda_t* res, const flambda_t* a) { + gf192_inverse_ref((gf192*) res, (const gf192*) a); +} + + +EXPORT void gf192_sum_pow2_naive(gf192* res, const gf192* x) { + gf192 ONE = GF192_ONE; + gf192 r = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 0; i < 192; ++i) { + gf192p_lsh(&tmp, &ONE, i); + gf192p_mul(&tmp, &tmp, x + i); + gf192p_sum(&r, &r, &tmp); + } + *res = r; +} + +EXPORT void gf192_sum_pow2_ref(gf192* res, const gf192* x) { + static const gf192 PP = {.v64 = {GF192_PV, 0, 0}}; + gf192 left = x[0]; + gf192 right = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 1; i < 192; ++i) { + gf192p_lsh(&tmp, x + i, i); + gf192p_sum(&left, &left, &tmp); + gf192p_rsh(&tmp, x + i, 192 - i); + gf192p_sum(&right, &right, &tmp); + } + gf192p_mul(&tmp, &right, &PP); + gf192p_sum(res, &left, &tmp); +} +EXPORT void gf192_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x) { + gf192_sum_pow2_ref((gf192*) res, (const gf192*) x); +} + + +void gf192_echelon_pow2_naive(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + CREQUIRE(k > 0, "k not supported"); + CREQUIRE(k * x_size <= 192, "echelon width not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf192); + gf192 ONE = GF192_ONE; + gf192 r = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 0; i < x_size; ++i) { + gf192p_lsh(&tmp, &ONE, k * i); + gf192p_mul(&tmp, &tmp, x + i * xbs); + gf192p_sum(&r, &r, &tmp); + } + *res = r; +} + +void gf192_echelon_pow2_ref(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 192, "echelon width not supported"); + if (x_size == 0) { + *res = GF192_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf192); + static const gf192 PP = {.v64 = {GF192_PV, 0, 0}}; + gf192 left = x[0]; + gf192 right = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf192p_lsh(&tmp, x + i * xbs, k * i); + gf192p_sum(&left, &left, &tmp); + gf192p_rsh(&tmp, x + i * xbs, 192 - k * i); + gf192p_sum(&right, &right, &tmp); + } + gf192p_mul(&tmp, &right, &PP); + gf192p_sum(res, &left, &tmp); +} +EXPORT void gf192_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf192_echelon_pow2_ref(k, (gf192*) res, (const gf192*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common/gf256.c b/src/sig/sdith/sdith_sdith_common/gf256.c new file mode 100644 index 0000000000..086401349d --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/gf256.c @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include + +#include "vole_private.h" + +const gf256 GF256_ZERO = {.v64 = {0, 0, 0, 0}}; +const gf256 GF256_ONE = {.v64 = {1, 0, 0, 0}}; + +SDITH_ALWAYS_INLINE uint8_t gf256p_equals(const gf256* const a, const gf256* const b) { + return memcmp(a->v, b->v, 32) == 0; +} + +SDITH_ALWAYS_INLINE void gf256p_sum(gf256* const res, const gf256* const a, const gf256* const b) { + gf256_sum_ref(res, a, b); +} + +SDITH_ALWAYS_INLINE uint8_t gf256p_bitof(const gf256* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 256, "bad bit position %" PRIu64, position); + const uint64_t q8 = position >> 3; + const uint64_t r8 = position & 7; + return (a->v[q8] >> r8) & 1; +} + +// 64-bit limb shifts (little-endian v64[4]). +// This function does not need to be CT (same as lsh). +void gf256p_lsh(gf256* const res, const gf256* const a, const uint64_t amount) { + CREQUIRE(amount < 256, "bad left shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[4] = {0, 0, 0, 0}; + if (rb == 0) { + for (uint64_t i = ql; i < 4; i++) o[i] = a->v64[i - ql]; + } else { + for (uint64_t i = 4; i-- > ql;) { + const uint64_t hi = a->v64[i - ql] << rb; + const uint64_t lo = (i - ql >= 1) ? (a->v64[i - ql - 1] >> (64 - rb)) : 0; + o[i] = hi | lo; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; + res->v64[3] = o[3]; +} + +void gf256p_rsh(gf256* const res, const gf256* const a, const uint64_t amount) { + CREQUIRE(amount < 256, "bad right shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[4] = {0, 0, 0, 0}; + if (rb == 0) { + for (uint64_t i = 0; i + ql < 4; i++) o[i] = a->v64[i + ql]; + } else { + for (uint64_t i = 0; i + ql < 4; i++) { + const uint64_t lo = a->v64[i + ql] >> rb; + const uint64_t hi = (i + ql + 1 < 4) ? (a->v64[i + ql + 1] << (64 - rb)) : 0; + o[i] = lo | hi; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; + res->v64[3] = o[3]; +} + +SDITH_ALWAYS_INLINE void gf256p_mul(gf256* const res, const gf256* const a, const gf256* const b) { + gf256_product_ref(res, a, b); +} + +uint8_t gf256v_equals(const gf256 a, const gf256 b) { return gf256p_equals(&a, &b); } + +gf256 gf256v_sum(const gf256 a, const gf256 b) { + gf256 res; + gf256p_sum(&res, &a, &b); + return res; +} + +uint8_t gf256v_bitof(const gf256 a, const uint64_t position) { return gf256p_bitof(&a, position); } + +gf256 gf256v_lsh(const gf256 a, const uint64_t amount) { + gf256 res; + gf256p_lsh(&res, &a, amount); + return res; +} + +gf256 gf256v_rsh(const gf256 a, const uint64_t amount) { + gf256 res; + gf256p_rsh(&res, &a, amount); + return res; +} + +gf256 gf256v_mul(const gf256 a, const gf256 b) { + gf256 res; + gf256p_mul(&res, &a, &b); + return res; +} + +EXPORT void gf256_set_ref(gf256* res, const gf256* a) { *res = *a; } +EXPORT void gf256_flambda_set_ref(flambda_t* res, const flambda_t* a) { + gf256_set_ref((gf256*) res, (const gf256*) a); +} + + +EXPORT void gf256_sum_ref(gf256* res, const gf256* a, const gf256* b) { + for (uint64_t i = 0; i < 32; ++i) res->v[i] = a->v[i] ^ b->v[i]; +} +EXPORT void gf256_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_sum_ref((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +EXPORT void gf256_product_ref(gf256* res, const gf256* a, const gf256* b) { + // deal with the in-place issue + if (res == b) { + gf256 tmp; + gf256p_mul(&tmp, a, b); + memcpy(res->v, tmp.v, 32); + return; + } + // Out of place product, constant-time and word-level. The 4x4 carryless limb + // products (Karatsuba gf_clmul64) are accumulated into a 512-bit result, then + // reduced modulo the field polynomial x^256 + x^10 + x^5 + x^2 + 1 (0x425) + // with sparse shift-xors. There is no data-dependent branch or memory access, + // so the running time is independent of the secret bits of a and b (this runs + // on prover witness values, where a data-dependent branch would be a timing + // leak). The result is bit-identical to the schoolbook version, so all KATs + // are unchanged. Operand limbs are read before res is written, so res may + // alias a (res == b is handled by the guard above). + const uint64_t* const av = a->v64; + const uint64_t* const bv = b->v64; + uint64_t t[8] = {0}, hi, lo; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) { + gf_clmul64(av[i], bv[j], &hi, &lo); + t[i + j] ^= lo; + t[i + j + 1] ^= hi; + } + // fold the high 256 bits (t[4..7]) down: x^(256+n) = x^n * (x^10 + x^5 + x^2 + 1) + uint64_t r0 = t[0], r1 = t[1], r2 = t[2], r3 = t[3], c; +#define GF256_FOLD(v, L, H) \ + do { \ + (L) = (v) ^ ((v) << 2) ^ ((v) << 5) ^ ((v) << 10); \ + (H) = ((v) >> 62) ^ ((v) >> 59) ^ ((v) >> 54); \ + } while (0) + GF256_FOLD(t[4], lo, hi); r0 ^= lo; r1 ^= hi; + GF256_FOLD(t[5], lo, hi); r1 ^= lo; r2 ^= hi; + GF256_FOLD(t[6], lo, hi); r2 ^= lo; r3 ^= hi; + GF256_FOLD(t[7], lo, hi); r3 ^= lo; c = hi; // c holds coefficients of bits 256..265 + r0 ^= c ^ (c << 2) ^ (c << 5) ^ (c << 10); // second fold; c <= 10 bits, no further overflow +#undef GF256_FOLD + res->v64[0] = r0; + res->v64[1] = r1; + res->v64[2] = r2; + res->v64[3] = r3; +} +EXPORT void gf256_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_product_ref((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +EXPORT void gf256_dot_product_ref(gf256* res, const gf256* x, const gf256* y, const uint64_t size) { + gf256 acc = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf256_product_ref(&tmp, &x[i], &y[i]); + gf256_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf256_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf256_dot_product_ref((gf256*) res, (const gf256*) x, (const gf256*) y, size); +} + + +EXPORT void gf256_dot_product_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + gf256 acc = *res; + gf256 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf256_product_ref(&tmp, &x[i * xbs], &y[i]); + gf256_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf256_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf256_dot_product_acc_ref((gf256*) res, (const gf256*) x, x_byte_slice, (const gf256*) y, size); +} + + +EXPORT void gf256_dot_product_f2_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + gf256 acc = *res; + for (uint64_t i = 0; i < size; ++i) { + const uint64_t mask = -y_f2[i].v64[0]; + for (uint64_t k = 0; k < 4; ++k) acc.v64[k] ^= x[i * xbs].v64[k] & mask; + } + *res = acc; +} +EXPORT void gf256_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf256_dot_product_f2_acc_ref((gf256*) res, (const gf256*) x, x_byte_slice, (const gf256*) y_f2, size); +} + + +EXPORT void gf256_product_f2_ref(gf256* res, const gf256* a, const gf256* b_f2) { + const uint64_t mask = -b_f2->v64[0]; + for (uint64_t i = 0; i < 4; ++i) res->v64[i] = a->v64[i] & mask; +} +EXPORT void gf256_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2) { + gf256_product_f2_ref((gf256*) res, (const gf256*) a, (const gf256*) b_f2); +} + + +EXPORT void gf256_inverse_ref(gf256* res, const gf256* a) { + // this is the euclidian algorithm to compute the extended gcd + gf256 aa = *a; + CREQUIRE(!gf256p_equals(&aa, &GF256_ZERO), "inverse of 0"); + gf256 uu = GF256_ONE; + uint64_t log2a = 255; + while (gf256p_bitof(&aa, log2a) == 0) --log2a; + gf256 bb; + gf256p_lsh(&bb, &aa, 256 - log2a); + bb.v64[0] ^= GF256_P; + gf256 vv; + gf256p_lsh(&vv, &uu, 256 - log2a); + uint64_t log2b = 255; + while (log2a != 0) { + CASSERT(gf256v_equals(gf256v_mul(*a, uu), aa), "bug1"); + CASSERT(gf256v_equals(gf256v_mul(*a, vv), bb), "bug2"); + while (log2b >= log2a) { + if (gf256p_bitof(&bb, log2b)) { + gf256 tmp; + gf256p_lsh(&tmp, &aa, log2b - log2a); + gf256p_sum(&bb, &bb, &tmp); + gf256p_lsh(&tmp, &uu, log2b - log2a); + gf256p_sum(&vv, &vv, &tmp); + } + --log2b; + } + // swap aa <-> bb, uu <-> vv + gf256 tmp = aa; + aa = bb; + bb = tmp; + tmp = uu; + uu = vv; + vv = tmp; + uint64_t tmp2 = log2a; + log2a = log2b; + log2b = tmp2; + // update log2a + CASSERT(!gf256p_equals(&aa, &GF256_ZERO), "bug3"); + while (gf256p_bitof(&aa, log2a) == 0) --log2a; + } + CASSERT(gf256p_equals(&aa, &GF256_ONE), "bug4"); + *res = uu; +} +EXPORT void gf256_flambda_inverse_ref(flambda_t* res, const flambda_t* a) { + gf256_inverse_ref((gf256*) res, (const gf256*) a); +} + + +EXPORT void gf256_sum_pow2_naive(gf256* res, const gf256* x) { + gf256 ONE = GF256_ONE; + gf256 r = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 0; i < 256; ++i) { + gf256p_lsh(&tmp, &ONE, i); + gf256p_mul(&tmp, &tmp, x + i); + gf256p_sum(&r, &r, &tmp); + } + *res = r; +} + +EXPORT void gf256_sum_pow2_ref(gf256* res, const gf256* x) { + static const gf256 PP = {.v64 = {GF256_PV, 0, 0, 0}}; + gf256 left = x[0]; + gf256 right = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 1; i < 256; ++i) { + gf256p_lsh(&tmp, x + i, i); + gf256p_sum(&left, &left, &tmp); + gf256p_rsh(&tmp, x + i, 256 - i); + gf256p_sum(&right, &right, &tmp); + } + gf256p_mul(&tmp, &right, &PP); + gf256p_sum(res, &left, &tmp); +} +EXPORT void gf256_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x) { + gf256_sum_pow2_ref((gf256*) res, (const gf256*) x); +} + + +void gf256_echelon_pow2_naive(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + CREQUIRE(k > 0, "k not supported"); + CREQUIRE(k * x_size <= 256, "echelon width not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + gf256 ONE = GF256_ONE; + gf256 r = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 0; i < x_size; ++i) { + gf256p_lsh(&tmp, &ONE, k * i); + gf256p_mul(&tmp, &tmp, x + i * xbs); + gf256p_sum(&r, &r, &tmp); + } + *res = r; +} + +void gf256_echelon_pow2_ref(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 256, "echelon width not supported"); + if (x_size == 0) { + *res = GF256_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf256); + static const gf256 PP = {.v64 = {GF256_PV, 0, 0, 0}}; + gf256 left = x[0]; + gf256 right = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf256p_lsh(&tmp, x + i * xbs, k * i); + gf256p_sum(&left, &left, &tmp); + gf256p_rsh(&tmp, x + i * xbs, 256 - k * i); + gf256p_sum(&right, &right, &tmp); + } + gf256p_mul(&tmp, &right, &PP); + gf256p_sum(res, &left, &tmp); +} +EXPORT void gf256_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf256_echelon_pow2_ref(k, (gf256*) res, (const gf256*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common/ggm.c b/src/sig/sdith/sdith_sdith_common/ggm.c new file mode 100644 index 0000000000..3d8b3051ef --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/ggm.c @@ -0,0 +1,222 @@ +#include "ggm.h" + +#include +#include + +#include "sdith_prng.h" +#include "vole_private.h" + +// private layout (move to a ggm-private.h if needed) +struct full_ggm_tree_t { + uint32_t lambda; + uint32_t tau; + uint32_t kappa; + uint32_t lambda_bytes; + uint32_t depth; + uint32_t theta; // domain-separation truncation width = depth + 2 + uint32_t num_leaves; + uint64_t rng_data[4]; // here: global salt (lambda bits used) + GGM_SEED_RNG_LR_F* seed_rng_lr; // left and right in one call + GGM_COMMIT_RNG_F* commit_rng; // takes the extended leaf seed + EXTEND_LEAF_SEED_F* extend_leaf_seed; // raw leaf seed -> extended leaf seed + uint32_t extended_bytes; // byte size of an extended leaf seed + const seed_t* root_seed; // shared with seeds_cache + seed_t* seeds_cache; // 2*lambda_bytes*depth bytes + uint32_t cached_index; // + uint32_t* open_buf; // 4*tau*depth bytes + // space for the root seed copy + cache + open buffer +}; + +/** @brief if x==0, return 0, else floor(log2(x)) */ +uint32_t floor_log2i(uint32_t x) { + if (x == 0) return 0; + return 31 - __builtin_clz(x); +} + +// alternative function to use if the builtin above does not exist +uint32_t floor_log2i_compat(uint32_t x) { + uint32_t res = 0; + uint32_t t = x; + if (t >> 16) { + res += 16; + t >>= 16; + } + if (t >> 8) { + res += 8; + t >>= 8; + } + if (t >> 4) { + res += 4; + t >>= 4; + } + if (t >> 2) { + res += 2; + t >>= 2; + } + if (t >> 1) { + res += 1; + } + return res; +} + +/** @brief if x==0, return 0, else ceil(log2(x)) */ +uint32_t ceil_log2i(uint32_t x) { + uint32_t res = floor_log2i(x); + if (x == (UINT32_C(1) << res)) + return res; + else + return res + 1; +} + +EXPORT uint32_t estimate_topen_tmp_bytes(uint32_t tau, uint32_t kappa) { + uint32_t depth = ceil_log2i(tau) + kappa; // depth = ceil(log2(tau)) + kappa. + return 4 * tau * depth; +} + + +/** decode "delta" into the indexes of the hidden leaves */ +// hidden_nodes = [delta[i.kappa, (i+1).kappa) * tau + i for i in range(tau)] +// qsort hidden_leaves +// uint64_t hidden_leaves_indexes(uint64_t kappa, uint64_t tau, // dims +// uint32_t* hidden_leaves, // output: node indexes +// const bitvec_t* delta); // input: bits of delta + +// swap two elements - used in partition +void swap(uint32_t* a, uint32_t* b) { + uint32_t t = *a; + *a = *b; + *b = t; +} + +// partioning - used in quick sort +int partition(uint32_t arr[], int low, int high) { + uint32_t pivot = arr[high]; + int hi = high - 1; + int lo = low; + while (1) { + while (lo <= hi && arr[lo] <= pivot) ++lo; + while (lo <= hi && arr[hi] >= pivot) --hi; + if (lo > hi) break; + swap(arr + lo, arr + hi); + ++lo; + --hi; + } + swap(arr + lo, arr + high); + return lo; +} + +// QuickSort - used in hidden_leaves_indexes +void quickSort(uint32_t arr[], int low, int high) { + if (low < high) { + int pi = partition(arr, low, high); + + quickSort(arr, low, pi - 1); + quickSort(arr, pi + 1, high); + } +} + +SDITH_ALWAYS_INLINE uint32_t extract_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, const uint64_t* data) { + const uint64_t kappa_mask = (UINT64_C(1) << kappa) - 1; + uint64_t limb_pos = bitpos >> 6; + uint64_t limb_rem = bitpos & UINT64_C(63); + if (limb_rem + kappa <= 64) { + return (data[limb_pos] >> limb_rem) & kappa_mask; + } else { + return ((data[limb_pos] >> limb_rem) | (data[limb_pos + 1] << (64 - limb_rem))) & kappa_mask; + } +} +SDITH_ALWAYS_INLINE void xorto_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, uint64_t* data, uint64_t value) { + const uint64_t kappa_mask = (UINT64_C(1) << kappa) - 1; + uint64_t limb_pos = bitpos >> 6; + uint64_t limb_rem = bitpos & UINT64_C(63); + value &= kappa_mask; + if (limb_rem + kappa <= 64) { + data[limb_pos] ^= value << limb_rem; + } else { + data[limb_pos] ^= value << limb_rem; + data[limb_pos + 1] ^= value >> (64 - limb_rem); + } +} + +EXPORT uint32_t extract_kappabit_uint(uint64_t kappa, uint64_t bitpos, const void* data) { + return extract_kappabit_uint_inline(kappa, bitpos, (uint64_t*)data); +} +EXPORT void xorto_kappabit_uint(uint64_t kappa, uint64_t bitpos, void* data, uint64_t value) { + xorto_kappabit_uint_inline(kappa, bitpos, (uint64_t*)data, value); +} + +EXPORT void hidden_leaves_indexes(uint64_t kappa, uint64_t tau, uint32_t* hidden_leaves, const bitvec_t* delta) { + for (uint64_t k = 0; k < tau; ++k) { + hidden_leaves[k] = extract_kappabit_uint_inline(kappa, k * kappa, delta) * tau + k; + } + quickSort(hidden_leaves, 0, tau - 1); +} +EXPORT void hidden_leaves_indexes2(uint64_t kappa, uint64_t tau, uint32_t* hidden_leaves, const bitvec_t* delta) { + const uint64_t start_index = tau * (UINT64_C(1) << kappa); + for (uint64_t k = 0; k < tau; ++k) { + hidden_leaves[k] = extract_kappabit_uint_inline(kappa, k * kappa, delta) * tau + k + start_index; + } + quickSort(hidden_leaves, 0, tau - 1); +} + +/** estimate the number of nodes to open for this choice of delta: */ +// algorithm: +// sibling_path_indexes = [] +// new nodes_list = [] +// for (depth = tau*kappa-1 down to 0) +// while hidden_leave is not empty { +// if (hidden_leaves have >= 2 elements and hidden_leave[0] ^ hidden_leave[1] == 1) { +// append hidden_leave[0] >> 1 to new nodes_list +// pop the two first nodes of hidden_nodes +// } else { +// append hidden_leave[0] ^ 1 to sibling_path_indexes +// append hidden_leave[0] >> 1 to new nodes_list +// pop the first nodes of hidden_nodes +// } +// } +// } +uint64_t estimate_topen(const uint32_t tau, const uint32_t kappa, uint64_t max_topen, const uint32_t* hidden_leaves_idx, + uint8_t* tmp_space) { + // CASSERT(max_topen < tree->tau * tree->kappa, "topen bug"); + uint32_t sibling_path_size = 0; + uint32_t* bstart = (uint32_t*)tmp_space; + uint32_t* bend = bstart + tau; +#ifndef NDEBUG + uint32_t num_leaves = tau * UINT64_C(1) << kappa; + uint32_t last_leave_index = num_leaves - 1; + for (uint32_t i = 0; i < tau; ++i) { + CREQUIRE(hidden_leaves_idx[i] > last_leave_index, "incorrect leave node index"); + last_leave_index = hidden_leaves_idx[i]; + } +#endif + // copy the leaf indexes in reversed order + for (uint32_t i = 0; i < tau; ++i) { + bstart[tau - i - 1] = hidden_leaves_idx[i]; + } + while (bend - bstart >= 2) { + uint32_t first_idx = *(bstart++); + uint32_t second_idx = *(bstart); + uint32_t next_idx = first_idx >> 1; + CASSERT(first_idx > 1, "bug1"); + CASSERT(*(bend - 1) > next_idx, "bug2"); + if ((first_idx ^ second_idx) == 1) { + // two hidden nodes with the same parent + ++bstart; + } else { + // single child out of at least 2 + ++sibling_path_size; + } + *(bend++) = next_idx; + } + while (*bstart != 1) { + ++sibling_path_size; + *bstart >>= 1; + } + return sibling_path_size; +} + + +struct ggm_multi_item_t { + uint16_t type : 2; + uint16_t addr : 14; +}; diff --git a/src/sig/sdith/sdith_sdith_common/ggm.h b/src/sig/sdith/sdith_sdith_common/ggm.h new file mode 100644 index 0000000000..93035a3619 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/ggm.h @@ -0,0 +1,53 @@ +#ifndef AQ_VOLE_IMPL_GGM_H +#define AQ_VOLE_IMPL_GGM_H + +// This file contains the declaration of all algebra functions over vectors and matrices over F2 + +#include "commons.h" + +typedef void GGM_SEED_RNG_LR_F(void* lr_out, const void* salt, const void* key, uint64_t node_idx, uint32_t theta); +typedef void GGM_COMMIT_RNG_F(void* out, const void* salt, const void* key, uint64_t node_idx); + +/** decode "delta" into the indexes of the hidden leaves */ +// hidden_nodes = [delta[i.kappa, (i+1).kappa) * tau + i for i in range(tau)] +// qsort hidden_leaves +EXPORT void hidden_leaves_indexes(uint64_t kappa, uint64_t tau, // dims + uint32_t* hidden_leaves, // output: node indexes + const bitvec_t* delta); // input: bits of delta +/** decode "delta" into the indexes of the hidden leaves: + * the v2 version returns node indexes instead of leave indexes */ +EXPORT void hidden_leaves_indexes2(uint64_t kappa, uint64_t tau, // dims + uint32_t* hidden_leaves, // output: node indexes + const bitvec_t* delta); // input: bits of delta + +/** estimate the number of nodes to open for this choice of delta: */ +// algorithm: +// sibling_path_indexes = [] +// new nodes_list = [] +// for (depth = tau*kappa-1 down to 0) +// while hidden_leave is not empty { +// if (hidden_leaves have >= 2 elements and hidden_leave[0] ^ hidden_leave[1] == 1) { +// append hidden_leave[0] >> 1 to new nodes_list +// pop the two first nodes of hidden_nodes +// } else { +// append hidden_leave[0] ^ 1 to sibling_path_indexes +// append hidden_leave[0] >> 1 to new nodes_list +// pop the first nodes of hidden_nodes +// } +// } +// } +EXPORT uint32_t estimate_topen_tmp_bytes( + uint32_t tau, + uint32_t kappa + ); + +EXPORT uint64_t estimate_topen( // + const uint32_t tau, + const uint32_t kappa, + uint64_t max_topen, // TODO ignored for now + const uint32_t* hidden_leaves_idx, + uint8_t* tmp_space + ); // + + +#endif // AQ_VOLE_IMPL_GGM_H diff --git a/src/sig/sdith/sdith_sdith_common/matrix_transpose_f2.c b/src/sig/sdith/sdith_sdith_common/matrix_transpose_f2.c new file mode 100644 index 0000000000..d593d8cf96 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/matrix_transpose_f2.c @@ -0,0 +1,525 @@ +#include +#include +#include +#include + +#include "vole_private.h" + +EXPORT void transpose_128_128_naive(void* out, const void* in) { + CASSERT(out != in); + typedef __uint128_t T; + const T* x = (T*)in; + T* r = (T*)out; + for (uint64_t i = 0; i < 128; ++i) { + __uint128_t oi = 0; + for (uint64_t j = 0; j < 128; ++j) { + oi |= ((x[j] >> i) & 1) << j; + } + r[i] = oi; + } +} + +EXPORT void transpose_192_192_naive(void* out, const void* in) { + CASSERT(out != in); + const uint64_t* x = (uint64_t*)in; + uint64_t *r = out; + for (uint64_t i = 0; i < 192; ++i) { + uint64_t tmp[3] = {0}; + for (uint64_t j = 0; j < 192; ++j) { + tmp[j/64] |= ((x[j*3 + i/64] >> (i%64)) & 1) << (j%64); + } + for (uint64_t j = 0; j < 3; ++j) + { + r[i*3 + j] = tmp[j]; + } + } +} + +EXPORT void transpose_256_256_naive(void* out, const void* in) { + CASSERT(out != in); + const uint64_t* x = (uint64_t*)in; + uint64_t *r = out; + for (uint64_t i = 0; i < 256; ++i) { + uint64_t tmp[4] = {0}; + for (uint64_t j = 0; j < 256; ++j) { + tmp[j/64] |= ((x[j*4 + i/64] >> (i%64)) & 1) << (j%64); + } + for (uint64_t j = 0; j < 4; ++j) + { + r[i*4 + j] = tmp[j]; + } + } +} + +SDITH_ALWAYS_INLINE void transpose8(uint8_t *a, uint64_t stride) { + int j, k; + uint64_t m, t; + m = 0x0F; + for (j = 4; j != 0; j = j >> 1, m = m ^ (m << j)) { + for (k = 0; k < 8; k = (k + j + 1) & ~j) { + t = (a[(k + j)*stride] ^ (a[k*stride] >> j)) & m; + a[(k + j)*stride] = a[(k + j)*stride] ^ t; + a[k*stride] = a[k*stride] ^ (t << j); + } + } +} + +SDITH_ALWAYS_INLINE void transpose64(uint64_t *a, uint64_t stride) { + int j, k; + uint64_t m, t; + m = 0x00000000FFFFFFFFULL; + for (j = 32; j != 0; j = j >> 1, m = m ^ (m << j)) { + for (k = 0; k < 64; k = (k + j + 1) & ~j) { + t = (a[(k + j)*stride] ^ (a[k*stride] >> j)) & m; + a[(k + j)*stride] = a[(k + j)*stride] ^ t; + a[k*stride] = a[k*stride] ^ (t << j); + } + } +} + +/* Not called anywhere in the current build; kept as a utility. */ +SDITH_MAYBE_UNUSED SDITH_ALWAYS_INLINE void transpose64_unaligned(uint8_t *a, uint64_t byte_stride) +{ + uint64_t tmp[64]; + for (size_t i = 0; i < 64; i++) + { + tmp[i] = *((uint64_t*)&a[i*byte_stride]); + } + transpose64(tmp, 1); + for (size_t i = 0; i < 64; i++) + { + *((uint64_t*)&a[i*byte_stride]) = tmp[i]; + } +} + +SDITH_ALWAYS_INLINE void transpose128(__uint128_t *a, uint64_t stride) { + int j, k; + __uint128_t m, t; + m = 1; + m <<= 64; + m -= 1; + for (j = 64; j != 0; j = j >> 1, m = m ^ (m << j)) { + for (k = 0; k < 128; k = (k + j + 1) & ~j) { + t = (a[(k + j)*stride] ^ (a[k*stride] >> j)) & m; + a[(k + j)*stride] = a[(k + j)*stride] ^ t; + a[k*stride] = a[k*stride] ^ (t << j); + } + } +} + +EXPORT void transpose_128_128_ref(void* x) { + transpose128((__uint128_t*)x, 1); + + // legacy code: + //uint64_t *x64 = x; + //// split into 4 submatrices: + //// A B + //// C D + //// A starts at x64[0] + //// B starts at x64[1] + //// C starts at x64[128] + //// D starts at x64[129] + //transpose64(&x64[0], 2); + //transpose64(&x64[1], 2); + //transpose64(&x64[128], 2); + //transpose64(&x64[129], 2); + // + //// swap submatrix B and C + //for (uint64_t i = 0; i < 64; i++) + //{ + // x64[2*i+ 1] ^= x64[2*i+128]; + // x64[2*i+128] ^= x64[2*i+ 1]; + // x64[2*i+ 1] ^= x64[2*i+128]; + //} +} + +EXPORT void transpose_192_192_ref(void* x) { + uint64_t *x64 = x; + // split into 9 submatrices: + // A B C + // D E F + // G H I + uint64_t *A = &x64[0]; + uint64_t *B = &x64[1]; + uint64_t *C = &x64[2]; + uint64_t *D = &x64[192]; + uint64_t *E = &x64[193]; + uint64_t *F = &x64[194]; + uint64_t *G = &x64[384]; + uint64_t *H = &x64[385]; + uint64_t *I = &x64[386]; + + transpose64(A, 3); + transpose64(B, 3); + transpose64(C, 3); + transpose64(D, 3); + transpose64(E, 3); + transpose64(F, 3); + transpose64(G, 3); + transpose64(H, 3); + transpose64(I, 3); + + // swap C and G + for (uint64_t i = 0; i < 64; i++) + { + C[3*i] ^= G[3*i]; + G[3*i] ^= C[3*i]; + C[3*i] ^= G[3*i]; + } + // swap B and D + for (uint64_t i = 0; i < 64; i++) + { + B[3*i] ^= D[3*i]; + D[3*i] ^= B[3*i]; + B[3*i] ^= D[3*i]; + } + // swap F and H + for (uint64_t i = 0; i < 64; i++) + { + F[3*i] ^= H[3*i]; + H[3*i] ^= F[3*i]; + F[3*i] ^= H[3*i]; + } +} + +EXPORT void transpose_256_256_ref(void* x) { + __uint128_t *x128 = x; + // split into 4 submatrices: + // A B + // C D + __uint128_t *A = &x128[0]; + __uint128_t *B = &x128[1]; + __uint128_t *C = &x128[256]; + __uint128_t *D = &x128[257]; + + transpose128(A, 2); + transpose128(B, 2); + transpose128(C, 2); + transpose128(D, 2); + + // swap submatrix B and C + for (uint64_t i = 0; i < 128; i++) + { + B[2*i] ^= C[2*i]; + C[2*i] ^= B[2*i]; + B[2*i] ^= C[2*i]; + } +} + +EXPORT void transpose_128_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: lambda elements of Lbyte bytes + * Output order: Lbyte*8 elements of lambda bits + */ + const uint64_t Lbyte = L/8; + CREQUIRE(Lslice >= Lbyte, "Lslice must be larger than L/8"); + const uint8_t* x = (uint8_t*)in; + // x[0..Lbyte-1] hold the first row + // x[Lbyte..2Lbyte-1] the second and so on, until + // x[127Lbyte..128Lbyte-1] hold the last row + uint8_t *r = out; + // r[0..15] hold the first output row + // r[16..31] hold the second output row and so on, until + // r[(L-1)*16..L*16-1] hold the last output row + for (uint64_t i = 0; i < 128*Lbyte; i++) + { + r[i] = 0; + } + for (uint64_t i = 0; i < L; ++i) + { + for (uint64_t j = 0; j < 128; ++j) + { + // get the i-th bit in the j-th input row + uint8_t tmp = (x[j*Lslice+i/8] >> (i%8)) & 1; + // store it to the j-th output bit of the i-th output row + r[i*16+j/8] |= tmp << (j%8); + } + } +} + +EXPORT void transpose_128_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 128 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 128 bits + */ + const uint64_t Lbyte = L/8; + CASSERT(Lslice >= Lbyte, "Lslice must be larger than L/8"); + uint64_t* o64 = (uint64_t*)out; + + if ((L%128) == 0) + { + uint64_t* x64 = (uint64_t*)in; + + // x64[0..Lbyte/8-1] hold the first row + // x64[Lbyte/8..2Lbyte/8-1] the second and so on, until + // x64[127Lbyte/8..128Lbyte/8-1] hold the last row + // x64[0..1] hold the first output row + // x64[2..3] hold the second output row and so on, until + // x64[(L-1)*2..L*2-1] hold the last output row + + // we split the whole matrix into Lbyte/16 sub-matrices (128x128 bit) + for (size_t i = 0; i < Lbyte/16; i++) + { + // first copy into out + for (size_t j = 0; j < 64*4; j++) + { + o64[j + i*64*4] = x64[(j%2) + (j/2)*Lslice/8 + i*2]; + } + transpose_128_128_ref(&o64[i*64*4]); + } + + } else { + + uint8_t* x8 = (uint8_t*)in; + uint8_t* o8 = (uint8_t*)out; + // x8[0..Lbyte-1] hold the first row + // x8[Lbyte..2Lbyte-1] the second and so on, until + // x8[127Lbyte..128Lbyte-1] hold the last row + // o8[0..15] hold the first output row + // o8[16..31] hold the second output row and so on, until + // o8[(L-1)*16..L*16-1] hold the last output row + + for (size_t i = 0; i < Lbyte/16; i++) + { + // copy 128x128 submatrix to output + for (size_t j = 0; j < 128*128/8; j++) + { + o8[j + i*128*16] = x8[(j%16) + (j/16)*Lslice + i*16]; + } + transpose_128_128_ref(&o64[i*64*4]); + } + + // now transpose the remainder bytes byte-wise + for (size_t i = (Lbyte/16)*16; i < Lbyte; i++) + { + for (size_t j = 0; j < 128/8; j++) + { + // copy this 8x8 matrix to its destination, then transpose + for (size_t k = 0; k < 8; k++) + { + o8[16*8*i + 16*k + j] = x8[i + Lslice*8*j + Lslice*k]; + } + transpose8(&o8[16*8*i + j], 16); + } + } + + } +} + +EXPORT void transpose_192_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 192 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 192 bits + */ + const uint64_t Lbyte = L/8; + CREQUIRE(Lslice >= Lbyte, "Lslice must be larger than L/8"); + const uint8_t* x = (uint8_t*)in; + // x[0..Lbyte-1] hold the first row + // x[Lbyte..2Lbyte-1] the second and so on, until + // x[191Lbyte..192Lbyte-1] hold the last row + uint8_t *r = out; + // r[0..23] hold the first output row + // r[24..47] hold the second output row and so on, until + // r[(L-1)*24..L*24-1] hold the last output row + for (uint64_t i = 0; i < 192*Lbyte; i++) + { + r[i] = 0; + } + for (uint64_t i = 0; i < L; ++i) + { + for (uint64_t j = 0; j < 192; ++j) + { + // get the i-th bit in the j-th input row + uint8_t tmp = (x[j*Lslice+i/8] >> (i%8)) & 1; + // store it to the j-th output bit of the i-th output row + r[i*24+j/8] |= tmp << (j%8); + } + } +} + +EXPORT void transpose_192_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 192 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 192 bits + */ + const uint64_t Lbyte = L/8; + CASSERT(Lslice >= Lbyte, "Lslice must be larger than L/8"); + uint64_t* o64 = (uint64_t*)out; + + if ((L%192) == 0) + { + uint64_t* x64 = (uint64_t*)in; + + // x64[0..Lbyte/8-1] hold the first row + // x64[Lbyte/8..2Lbyte/8-1] the second and so on, until + // x64[191Lbyte/8..192Lbyte/8-1] hold the last row + // x64[0..1] hold the first output row + // x64[2..3] hold the second output row and so on, until + // x64[(L-1)*2..L*2-1] hold the last output row + + // we split the whole matrix into Lbyte/24 sub-matrices (192x192 bit) + for (size_t i = 0; i < Lbyte/24; i++) + { + // first copy into out + for (size_t j = 0; j < 64*9; j++) + { + o64[j + i*64*9] = x64[(j%3) + (j/3)*Lslice/8 + i*3]; + } + transpose_192_192_ref(&o64[i*64*9]); + } + + } else { + + uint8_t* x8 = (uint8_t*)in; + uint8_t* o8 = (uint8_t*)out; + // x8[0..Lbyte-1] hold the first row + // x8[Lbyte..2Lbyte-1] the second and so on, until + // x8[191Lbyte..192Lbyte-1] hold the last row + // o8[0..15] hold the first output row + // o8[16..31] hold the second output row and so on, until + // o8[(L-1)*16..L*16-1] hold the last output row + + for (size_t i = 0; i < Lbyte/24; i++) + { + // copy 192x192 submatrix to output + for (size_t j = 0; j < 192*192/8; j++) + { + o8[j + i*192*24] = x8[(j%24) + (j/24)*Lslice + i*24]; + } + transpose_192_192_ref(&o64[i*64*9]); + } + + // now transpose the remainder bytes byte-wise + for (size_t i = (Lbyte/24)*24; i < Lbyte; i++) + { + for (size_t j = 0; j < 192/8; j++) + { + // copy this 8x8 matrix to its destination, then transpose + for (size_t k = 0; k < 8; k++) + { + o8[24*8*i + 24*k + j] = x8[i + Lslice*8*j + Lslice*k]; + } + transpose8(&o8[24*8*i + j], 24); + } + } + + } +} + +EXPORT void transpose_256_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: lambda elements of Lbyte bytes + * Output order: Lbyte*8 elements of lambda bits + */ + const uint64_t Lbyte = L/8; + CREQUIRE(Lslice >= Lbyte, "Lslice must be larger than L/8"); + const uint8_t* x = (uint8_t*)in; + // x[0..Lbyte-1] hold the first row + // x[Lbyte..2Lbyte-1] the second and so on, until + // x[255Lbyte..256Lbyte-1] hold the last row + uint8_t *r = out; + // r[0..31] hold the first output row + // r[32..64] hold the second output row and so on, until + // r[(L-1)*32..L*32-1] hold the last output row + for (uint64_t i = 0; i < 256*Lbyte; i++) + { + r[i] = 0; + } + for (uint64_t i = 0; i < L; ++i) + { + for (uint64_t j = 0; j < 256; ++j) + { + // get the i-th bit in the j-th input row + uint8_t tmp = (x[j*Lslice+i/8] >> (i%8)) & 1; + // store it to the j-th output bit of the i-th output row + r[i*32+j/8] |= tmp << (j%8); + } + } +} + +EXPORT void transpose_256_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 256 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 256 bits + */ + const uint64_t Lbyte = L/8; + CASSERT(Lslice >= Lbyte, "Lslice must be larger than L/8"); + uint64_t* o64 = (uint64_t*)out; + + if ((L%256) == 0) + { + uint64_t* x64 = (uint64_t*)in; + + // x64[0..Lbyte/8-1] hold the first row + // x64[Lbyte/8..2Lbyte/8-1] the second and so on, until + // x64[255Lbyte/8..256Lbyte/8-1] hold the last row + // x64[0..1] hold the first output row + // x64[2..3] hold the second output row and so on, until + // x64[(L-1)*2..L*2-1] hold the last output row + + // we split the whole matrix into Lbyte/32 sub-matrices (256x256 bit) + for (size_t i = 0; i < Lbyte/32; i++) + { + // first copy into out + for (size_t j = 0; j < 64*16; j++) + { + o64[j + i*64*16] = x64[(j%4) + (j/4)*Lslice/8 + i*4]; + } + transpose_256_256_ref(&o64[i*64*16]); + } + + } else { + + uint8_t* x8 = (uint8_t*)in; + uint8_t* o8 = (uint8_t*)out; + // x8[0..Lbyte-1] hold the first row + // x8[Lbyte..2Lbyte-1] the second and so on, until + // x8[255Lbyte..256Lbyte-1] hold the last row + // o8[0..15] hold the first output row + // o8[16..31] hold the second output row and so on, until + // o8[(L-1)*16..L*16-1] hold the last output row + + for (size_t i = 0; i < Lbyte/32; i++) + { + // copy 256x256 submatrix to output + for (size_t j = 0; j < 256*256/8; j++) + { + o8[j + i*256*32] = x8[(j%32) + (j/32)*Lslice + i*32]; + } + transpose_256_256_ref(&o64[i*64*16]); + } + + // now transpose the remainder bytes byte-wise + for (size_t i = (Lbyte/32)*32; i < Lbyte; i++) + { + for (size_t j = 0; j < 256/8; j++) + { + // copy this 8x8 matrix to its destination, then transpose + for (size_t k = 0; k < 8; k++) + { + o8[32*8*i + 32*k + j] = x8[i + Lslice*8*j + Lslice*k]; + } + transpose8(&o8[32*8*i + j], 32); + } + } + + } +} \ No newline at end of file diff --git a/src/sig/sdith/sdith_sdith_common/matrix_vector_products_f2.c b/src/sig/sdith/sdith_sdith_common/matrix_vector_products_f2.c new file mode 100755 index 0000000000..ee9f5d5a34 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/matrix_vector_products_f2.c @@ -0,0 +1,95 @@ +#include + +#include "vole_private.h" + +// A helper to set a single bit in a bit vector (XOR it with 'value'): +static inline void bitvec_value_xor_to(bitvec_t* v, uint64_t index, uint8_t value) { + const uint64_t byte_pos = index / 8; + const uint64_t bit_pos = index % 8; + ((uint8_t*)v)[byte_pos] ^= (uint8_t)(value << bit_pos); +} + +// Get a bit from a bit vector +static inline uint8_t bitvec_get_value(const bitvec_t* v, uint64_t idx) { + const uint8_t* vec = (uint8_t*)v; + return ( (vec[idx/8] >> (idx%8)) & 1 ); +} + +SDITH_ALWAYS_INLINE void bitvec_xor_inline_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, + const bitvec_t* b) { + uint8_t* r = (uint8_t*)res; + const uint8_t* aa = (uint8_t*)a; + const uint8_t* bb = (uint8_t*)b; + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] = aa[i] ^ bb[i]; + } +} + +EXPORT void bitvec_xor_to_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* b) { + bitvec_xor_inline_ref(bytelen, res, res, b); +} + +EXPORT void bitvec_xor_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b) { + bitvec_xor_inline_ref(bytelen, res, a, b); +} + +// b^=a then c^=b +EXPORT void bitvec_cascade_xor_to_ref(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a) { + bitvec_xor_inline_ref(bytelen, b, b, a); + bitvec_xor_inline_ref(bytelen, c, c, b); +} + + +uint8_t bitmat_get_value(const bitmat_t* v, uint64_t ncols, uint64_t row, uint64_t col) { + return bitvec_get_value(v, (row * ncols + col)); +} + +EXPORT void matrix_vector_product_f2_ref( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b) // bit vector of size ncols +{ + memset(res, 0, (nrows+7)/8); + for (uint64_t i=0; i> 3; + // Clear the result + memset(res, 0, nrows * lambda_bytes); + + // For each row i + for (uint64_t i = 0; i < nrows; i++) { + // Pointer to the result block for row i + uint8_t* r_i = res + i * lambda_bytes; + + for (uint64_t j = 0; j < ncols; j++) { + // Extract bit A[i,j] + uint64_t bit_index = i*ncols + j; + uint8_t a_ij = (amat[bit_index/8] >> (bit_index%8)) & 1; + + if (a_ij) { + // If a_ij is 1, XOR the block B[j] into r_i + const uint8_t* b_j = bvec + j * lambda_bytes; + for (int x = 0; x < lambda_bytes; x++) { + r_i[x] ^= b_j[x]; + } + } + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common/piop_circuit.c b/src/sig/sdith/sdith_sdith_common/piop_circuit.c new file mode 100644 index 0000000000..06e8cbdb20 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/piop_circuit.c @@ -0,0 +1,860 @@ +#include + +#include "vole_private.h" + +static const flambda_max_t FLAMBDA_ONE = {1, 0, 0, 0}; + +/** + * prover packed secret input gate (degree 1) + */ +EXPORT void prover_cst_vole_packed_secret_input_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + bitvec_t* out_pub, // [out] output publication (packed over f2) + fpoly_t* out_f, // [out] poly of degree 1 (cst term over f2) + const bitvec_t* in_value, // [in] secret bit values (packed over f2) + const bitvec_t* in_rvp_u, // [in] packed u terms + const flambda_t* in_rvp_v) // [in] packed v terms +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_v, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + uint8_t* const f = (uint8_t*)out_f; + const uint8_t* const rvp_v = (uint8_t*)in_rvp_v; + const uint8_t* const inval = (uint8_t*)in_value; + vole_params->bitvec_xor((num_inputs + 7) >> 3, out_pub, in_rvp_u, in_value); + + uint64_t leftover_bits = num_inputs & 7; + if (leftover_bits) { + uint8_t* out_pub_u8 = (uint8_t*)out_pub; + uint64_t idx = ((num_inputs + 7) >> 3) - 1; + uint64_t and_mask = (1 << leftover_bits) - 1; + out_pub_u8[idx] &= and_mask; + } + + memset(out_f, 0, 2 * num_inputs * lambda_bytes); + for (uint64_t i = 0; i < num_inputs; i++) { + uint8_t* const fi = f + i * 2 * lambda_bytes; + fi[0] = (inval[i >> 3] >> (i & 7)) & 1; + vole_params->flambda_set(fi + lambda_bytes, rvp_v + i * lambda_bytes); + } +} + +/** + * verifier packed secret input gate (degree 1) + */ +EXPORT void verifier_cst_vole_packed_secret_input_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + fpoly_t* out_q, // [out] vole evaluations + const bitvec_t* in_pub, // [in] publications (packed over f2) + const flambda_t* in_rvp_q, // [in] packed v terms + const flambda_t* delta2) // [in] verifier's point +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(delta2, alignment_of(lambda_bytes)); + + uint8_t* const q = (uint8_t*)out_q; + const uint8_t* const rvp_q = (uint8_t*)in_rvp_q; + const uint8_t* const inpub = (uint8_t*)in_pub; + uint8_t buf[32] = {0}; + +#ifndef NDEBUG + uint64_t leftover_bits = num_inputs & 7; + if (leftover_bits) { + uint64_t mask = ((1 << (8 - leftover_bits)) - 1) << leftover_bits; + uint64_t idx = ((num_inputs + 7) >> 3) - 1; + CASSERT((inpub[idx] & mask) == 0, "[in] publications does not have trailing zeros"); + } +#endif // NDEBUG + + for (uint64_t i = 0; i < num_inputs; i++) { + buf[0] = (inpub[i >> 3] >> (i & 7)) & 1; + vole_params->flambda_sum(q + i * lambda_bytes, rvp_q + i * lambda_bytes, buf); + } +} + +/** + * prover check-zero gate (degree d) + */ +EXPORT void prover_cst_vole_check_zero_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + fpoly_t* out_pub, // [out] output publication (degree d-1) -- not aligned + const fpoly_t* in_f, // [in] input (degree d) + const fpoly_t* in_rvp_f) // [in] rvp (degree d-1) +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_f, alignment_of(lambda_bytes)); + uint8_t* const pub = (uint8_t*)out_pub; + const uint8_t* const in = (uint8_t*)in_f; + const uint8_t* const rvp = (uint8_t*)in_rvp_f; + flambda_max_t pubi; // we use a temp variable for alignment issues + for (uint64_t i = 0; i < degree; i++) { + vole_params->flambda_sum(pubi, rvp + i * lambda_bytes, in + (i + 1) * lambda_bytes); + memcpy(pub + i * lambda_bytes, pubi, lambda_bytes); + } +} + +/** + * verifier check-zero gate (degree d) + */ +EXPORT uint8_t verifier_cst_vole_check_zero_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + flambda_t* out_value, // [out] deduced output value + const fpoly_t* in_pub, // [in] publication (degree d-1) -- not aligned + const flambda_t* in_q, // [in] input (degree d) + const flambda_t* in_rvp_q, // [in] rvp (degree d-1) + const flambda_t* delta2) // [in] verifier's point +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + const uint8_t* const pub = (uint8_t*)in_pub; + flambda_max_t pubi; // tmp variable for alignment purposes + // compute pub(delta2) via horner method + memcpy(out_value, pub + (degree - 1) * lambda_bytes, lambda_bytes); + for (int64_t i = degree - 2; i >= 0; i--) { + vole_params->flambda_product(out_value, out_value, delta2); + memcpy(pubi, pub + i * lambda_bytes, lambda_bytes); + vole_params->flambda_sum(out_value, out_value, pubi); + } + // compute (pub(delta2) + rvp_q) * delta2 + vole_params->flambda_sum(out_value, out_value, in_rvp_q); + vole_params->flambda_product(out_value, out_value, delta2); + // add in_q -> the constant term shall remain + vole_params->flambda_sum(out_value, out_value, in_q); + // zero test (does not need to be ct, nor efficient) + const uint8_t* const out = (uint8_t*)out_value; + for (uint64_t i = 0; i < lambda_bytes; i++) { + if (out[i]) return 0; + } + return 1; +} + +/** + * prover xor gate + */ +EXPORT void prover_cst_vole_xor_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree) // [in] b +{ + uint8_t* res = (uint8_t*)res_f; + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* b = (uint8_t*)b_f; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + // addition + if (a_degree < b_degree) { + for (size_t i = 0; i <= a_degree; i++) { + (*vole_params->flambda_sum)(res + lambda_bytes * i, a + lambda_bytes * i, b + lambda_bytes * i); + } + for (size_t i = a_degree + 1; i <= b_degree; i++) { + (*vole_params->flambda_set)(res + lambda_bytes * i, b + lambda_bytes * i); + } + } else { + for (size_t i = 0; i <= b_degree; i++) { + (*vole_params->flambda_sum)(res + lambda_bytes * i, a + lambda_bytes * i, b + lambda_bytes * i); + } + for (size_t i = b_degree + 1; i <= a_degree; i++) { + (*vole_params->flambda_set)(res + lambda_bytes * i, a + lambda_bytes * i); + } + } +} + +/** + * verifier xor gate + */ +EXPORT void verifier_cst_vole_xor_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_f, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_f, uint64_t a_degree, // [in] a + const flambda_t* b_f, uint64_t b_degree, // [in] b + const flambda_t* delta2) // [in] verifier's point (unused) +{ + (*vole_params->flambda_sum)(res_f, a_f, b_f); +} + +/** + * prover mul gate + */ +EXPORT void prover_cst_vole_mul_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree) // [in] b +{ + uint8_t* res = (uint8_t*)res_f; + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* b = (uint8_t*)b_f; + const size_t lambda_bytes = vole_params->lambda_bytes; + CASSERT(res != a && res != b, "function does not work in place"); + flambda_max_t tmp; + + // zeroize result + memset(res, 0, lambda_bytes * (a_degree + b_degree + 1)); + + // Schoolbook multiplication + for (size_t i_a = 0; i_a <= a_degree; i_a++) { + for (size_t i_b = 0; i_b <= b_degree; i_b++) { + (*vole_params->flambda_product)(tmp, a + lambda_bytes * i_a, b + lambda_bytes * i_b); + (*vole_params->flambda_sum)(res + lambda_bytes * (i_a + i_b), res + lambda_bytes * (i_a + i_b), tmp); + } + } +} + +/** + * verifier mul gate + */ +EXPORT void verifier_cst_vole_mul_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_q, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_q, uint64_t a_degree, // [in] a + const flambda_t* b_q, uint64_t b_degree, // [in] b + const flambda_t* delta2) // [in] verifier's point (unused) +{ + (*vole_params->flambda_product)(res_q, a_q, b_q); +} + +/** + * prover echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void prover_cst_vole_echelon_pow2_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + fpoly_t* res_f, // [out] res of degree 1 + const fpoly_t* a_f) // [in] (arity) a of degree 1 +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint8_t* const res = (uint8_t*)res_f; + const uint8_t* const a = (uint8_t*)a_f; + // note: we can speed-up the first one one since the cst term is over f2 + vole_params->flambda_echelon_pow2(k, res, a, arity, 2 * lambda_bytes); + vole_params->flambda_echelon_pow2(k, res + lambda_bytes, a + lambda_bytes, arity, 2 * lambda_bytes); +} +/** + * verifier echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void verifier_cst_vole_echelon_pow2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* delta2) // [in] verifier's point (unused) +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint8_t* const res = (uint8_t*)res_q; + const uint8_t* const a = (uint8_t*)a_q; + vole_params->flambda_echelon_pow2(k, res, a, arity, lambda_bytes); +} + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t prover_cst_check_unitary_gate_ct_ref_tmp_bytes(const vole_parameters* vole_params) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, 3 * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, 2 * lambda_bytes); + COMP_SPACE_RETURN(); +} + +/** + * prover check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void prover_cst_check_unitary_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // arity >= 1 + fpoly_t* res_f, // [out] res of degree 2 + const fpoly_t* a_f, // [in] (arity) a of deg 1 + const flambda_t* coeff, // [in] challenge coeff + uint8_t* tmp_space) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, 3 * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, 2 * lambda_bytes); + + prover_cst_vole_echelon_pow2_ct_ref(vole_params, arity, 1, tmp_fpoly_t1, a_f); + prover_cst_vole_echelon_pow2_ct_ref(vole_params, arity - 1, arity, tmp_fpoly_t2, a_f); + prover_cst_vole_mul_gate_ct_ref(vole_params, res_f, tmp_fpoly_t1, 1, tmp_fpoly_t2, 1); + + prover_cst_vole_echelon_pow2_ct_ref(vole_params, arity - 1, arity + 1, tmp_fpoly_t2, a_f); + + // Add using the xor gate + prover_cst_vole_xor_gate_ct_ref(vole_params, tmp_fpoly_t1, res_f, 2, tmp_fpoly_t2, 1); + + // Multiply by coeff + prover_cst_vole_mul_gate_ct_ref(vole_params, res_f, tmp_fpoly_t1, 2, coeff, 0); +} + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t verifier_cst_check_unitary_gate_ref_tmp_bytes(const vole_parameters* vole_params) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, lambda_bytes); + COMP_SPACE_RETURN(); +} + +/** + * verifier check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void verifier_cst_check_unitary_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* coeff, // [in] challenge coeff + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, lambda_bytes); + + verifier_cst_vole_echelon_pow2_ref(vole_params, arity, 1, tmp_fpoly_t1, a_q, delta2); + verifier_cst_vole_echelon_pow2_ref(vole_params, arity - 1, arity, tmp_fpoly_t2, a_q, delta2); + verifier_cst_vole_mul_gate_ref(vole_params, res_q, tmp_fpoly_t1, 1, tmp_fpoly_t2, 1, delta2); + + verifier_cst_vole_echelon_pow2_ref(vole_params, arity - 1, arity + 1, tmp_fpoly_t2, a_q, delta2); + + // Add using the xor gate + verifier_cst_vole_xor_gate_ref(vole_params, tmp_fpoly_t1, res_q, 2, tmp_fpoly_t2, 1, delta2); + + // Multiply by coeff + verifier_cst_vole_mul_gate_ref(vole_params, res_q, tmp_fpoly_t1, 2, coeff, 0, delta2); +} + +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes(const vole_parameters* vole_params, uint64_t arity, + uint64_t in_degree) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, (in_degree + 2) * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, (in_degree + 2) * lambda_bytes); + COMP_SPACE_RETURN(); +} + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_naive( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (real_arity) values of deg d + uint8_t* tmp_space) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* c = (uint8_t*)c_f; + uint64_t a_poly_bytes = (in_degree + 1) * lambda_bytes; + uint64_t c_poly_bytes = 2 * lambda_bytes; + + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, (in_degree + 2) * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, (in_degree + 2) * lambda_bytes); + + uint8_t* res_f_u8 = (uint8_t*)res_f; + + // a[0] + memcpy(res_f, a, (in_degree + 1) * lambda_bytes); + + // zeroing out the last coefficient + memset(res_f_u8 + (in_degree + 1) * lambda_bytes, 0, lambda_bytes); + + for (uint64_t i = 1; i < real_arity; i++) { + prover_cst_vole_xor_gate_ct_ref(vole_params, tmp_fpoly_t1, a + i * a_poly_bytes, in_degree, a, in_degree); + + // multiple the sum by a[i-1] + prover_cst_vole_mul_gate_ct_ref(vole_params, tmp_fpoly_t2, c + (i - 1) * c_poly_bytes, 1, tmp_fpoly_t1, in_degree); + + // sum the parts together + prover_cst_vole_xor_gate_ct_ref(vole_params, res_f, tmp_fpoly_t2, in_degree + 1, res_f, in_degree + 1); + } +} + +EXPORT uint64_t verifier_cst_vole_qary_mux_ctrl_bytes(const vole_parameters* vole_params, uint64_t arity) { + return arity * vole_params->lambda_bytes; +} + +/** + * Rewrite the control values as the extended control vector described in sdith_piop_circuits.h. + */ +EXPORT void verifier_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (real_arity) extended control + const flambda_t* c_q, // [in] (real_arity-1) control values + const flambda_t* delta2) { // [in] verifier's point (unused) + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + const uint8_t* c = (uint8_t*)c_q; + uint8_t* ctrl_u8 = (uint8_t*)ctrl; + + // ctrl[0] accumulates all the other control values + (*vole_params->flambda_set)(ctrl_u8, FLAMBDA_ONE); + for (uint64_t i = 1; i < real_arity; ++i) { + const uint8_t* ci = c + (i - 1) * lambda_bytes; + (*vole_params->flambda_set)(ctrl_u8 + i * lambda_bytes, ci); + (*vole_params->flambda_sum)(ctrl_u8, ctrl_u8, ci); + } +} + +/** + * verifier qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void verifier_cst_vole_qary_mux_gate_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + flambda_t* res_q, // [out] evaluation of the poly of degree d+1 + const flambda_t* ctrl, // [in] (real_arity) prepared control + const flambda_t* a_q, // [in] (real_arity) values of deg d + const flambda_t* delta2) { // [in] verifier's point (unused) + // res = sum_i ctrl[i] . a[i]: the verifier's values are single field elements, so the inputs + // of a gate are already the contiguous vector a dot product wants. + (*vole_params->flambda_dot_product)(res_q, a_q, ctrl, real_arity); +} + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t verifier_cst_vole_qary_mux_gate_ref_tmp_bytes(const vole_parameters* vole_params, uint64_t arity, + uint64_t in_degree) { + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, arity)); + COMP_SPACE_RETURN(); +} + +/** + * verifier qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void verifier_cst_vole_qary_mux_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + flambda_t* res_q, // [out] poly of degree d+1 + const flambda_t* c_q, // [in] (arity-1) control bits of deg. 1 + const flambda_t* a_q, // [in] (real_arity) values of deg d + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space) { // scratch space + TMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, real_arity)); + verifier_cst_vole_qary_mux_prepare_ctrl(vole_params, real_arity, ctrl, c_q, delta2); + verifier_cst_vole_qary_mux_gate_prep(vole_params, real_arity, res_q, ctrl, a_q, delta2); +} + +EXPORT uint64_t prover_cst_vole_qary_mux_ctrl_bytes(const vole_parameters* vole_params, uint64_t arity) { + return 2 * arity * vole_params->lambda_bytes; +} + +/** + * Rewrite the control bits as the two extended control vectors described in sdith_piop_circuits.h. + */ +EXPORT void prover_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (2 x real_arity) extended control + const fpoly_t* c_f) { // [in] (real_arity-1) control bits of deg. 1 + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t c_poly_bytes = 2 * lambda_bytes; + + const uint8_t* c = (uint8_t*)c_f; + uint8_t* ctrl0 = (uint8_t*)ctrl; + uint8_t* ctrl1 = ctrl0 + real_arity * lambda_bytes; + + // ctrl{0,1}[0] accumulate the coefficients of all the other control bits + (*vole_params->flambda_set)(ctrl0, FLAMBDA_ONE); + memset(ctrl1, 0, lambda_bytes); + for (uint64_t i = 1; i < real_arity; ++i) { + const uint8_t* ci = c + (i - 1) * c_poly_bytes; + (*vole_params->flambda_set)(ctrl0 + i * lambda_bytes, ci); + (*vole_params->flambda_set)(ctrl1 + i * lambda_bytes, ci + lambda_bytes); + (*vole_params->flambda_sum)(ctrl0, ctrl0, ci); + (*vole_params->flambda_sum)(ctrl1, ctrl1, ci + lambda_bytes); + } +} + +/** + * prover qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const flambda_t* ctrl, // [in] (2 x real_arity) prepared control + const fpoly_t* a_f) { // [in] (real_arity) values of deg d + const uint64_t lambda_bytes = vole_params->lambda_bytes; + // input i lives at a + i * a_poly_bytes: for a fixed coefficient j, the inputs are a strided vector + const uint64_t a_poly_bytes = (in_degree + 1) * lambda_bytes; + + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* ctrl0 = (uint8_t*)ctrl; + const uint8_t* ctrl1 = ctrl0 + real_arity * lambda_bytes; + uint8_t* res_f_u8 = (uint8_t*)res_f; + + memset(res_f_u8, 0, (in_degree + 2) * lambda_bytes); + for (uint64_t j = 0; j <= in_degree; ++j) { + // res[j] += sum_i ctrl0[i] . a[i][j] (a bit-select: the ctrl0[i] are in F2) + (*vole_params->flambda_dot_product_f2_acc)(res_f_u8 + j * lambda_bytes, // + a + j * lambda_bytes, a_poly_bytes, ctrl0, real_arity); + // res[j+1] += sum_i ctrl1[i] . a[i][j] + (*vole_params->flambda_dot_product_acc)(res_f_u8 + (j + 1) * lambda_bytes, // + a + j * lambda_bytes, a_poly_bytes, ctrl1, real_arity); + } +} + +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes(const vole_parameters* vole_params, + uint64_t arity) { + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, arity)); + COMP_SPACE_RETURN(); +} + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) using product_f2 + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (real_arity) values of deg d + uint8_t* tmp_space) { // scratch space + TMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, real_arity)); + prover_cst_vole_qary_mux_prepare_ctrl(vole_params, real_arity, ctrl, c_f); + prover_cst_vole_qary_mux_gate_ct_f2_prep(vole_params, real_arity, in_degree, res_f, ctrl, a_f); +} + +void tmp_bytes_init(tmp_bytes_comp_t* tmp_bytes_comp) { + tmp_bytes_comp->local_size = 0; + tmp_bytes_comp->last_alignment = 1; + tmp_bytes_comp->max_size = 0; +} + +void tmp_bytes_reserve_local_var(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_bytes) { + tmp_bytes_comp->local_size += var_bytes; + if (tmp_bytes_comp->local_size > tmp_bytes_comp->max_size) { + tmp_bytes_comp->max_size = tmp_bytes_comp->local_size; + } +} + +void tmp_bytes_reserve_local_var_aligned(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_align, uint64_t var_bytes) { + if (var_align > tmp_bytes_comp->last_alignment) { + tmp_bytes_comp->local_size = + (tmp_bytes_comp->local_size + tmp_bytes_comp->last_alignment - 1) & (uint64_t)(-tmp_bytes_comp->last_alignment); + tmp_bytes_comp->local_size += var_align - tmp_bytes_comp->last_alignment; + tmp_bytes_comp->last_alignment = var_align; + } else { + tmp_bytes_comp->local_size = (tmp_bytes_comp->local_size + var_align - 1) & (uint64_t)(-var_align); + } + tmp_bytes_comp->local_size += var_bytes; + if (tmp_bytes_comp->local_size > tmp_bytes_comp->max_size) { + tmp_bytes_comp->max_size = tmp_bytes_comp->local_size; + } +} + +void tmp_bytes_reserve_call(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t call_tmp_bytes) { + uint64_t ms = tmp_bytes_comp->local_size + call_tmp_bytes; + if (ms > tmp_bytes_comp->max_size) { + tmp_bytes_comp->max_size = ms; + } +} + +/** + * Validate the shape of a mux-circuit and return its largest arity. + * + * The layer loops below rely on every layer having at least one output: num_out == 0 would make + * "num_out - 1" wrap around and the last mux would be applied with a nonsense arity. That cannot + * happen as soon as num_inputs >= 1 and every arity is >= 1, since ceil(n/arity) >= 1 for n >= 1. + * The last layer must also collapse to a single output, otherwise the circuit would silently drop + * the inputs beyond the first mux: iterating the ceil-division is an overflow-free way to check + * the documented "num_inputs <= product of the arities". + */ +static uint64_t mux_circuit_check_shape( // + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities + uint64_t num_inputs) { // number of inputs + CREQUIRE(depth >= 1, "mux circuit depth must be >= 1"); + CREQUIRE(num_inputs >= 1, "mux circuit must have at least one input"); + uint64_t max_arity = 1; + uint64_t num_inputs_at_depth = num_inputs; + for (uint64_t d = 0; d < depth; ++d) { + CREQUIRE(arities[d] >= 1, "mux arity must be >= 1"); + if (arities[d] > max_arity) max_arity = arities[d]; + num_inputs_at_depth = (num_inputs_at_depth + arities[d] - 1) / arities[d]; + } + CREQUIRE(num_inputs_at_depth == 1, "mux arities too small for the number of inputs"); + return max_arity; +} + +/** + * scratch space required by prover_cst_mux_circuit_ct_ref + */ +EXPORT uint64_t prover_cst_mux_circuit_ct_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs) { // scratch space + + const uint64_t lambda_bytes = vole_params->lambda_bytes; + // tmp space for calculations of check_unitary_gate: 5 * lambda_bytes + // tmp space to hold intermediate values for check_unitary_gate: 3 * lambda_bytes; + // tmp space for calculations of qary_mux_gate: 2 * (depth + 2) + // tmp space to hold 2 intermediate values for qary_mux_gate: 2*3*max_inputs*lambda_bytes + // tmp space for the prepared control of a layer (full and last, incomplete, mux) + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_values, 32, 3 * lambda_bytes); // 3*lambda_bytes; + COMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary1, 32, 3 * max_inputs * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary2, 32, 3 * max_inputs * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_CALL(prover_cst_check_unitary_gate_ct_ref_tmp_bytes(vole_params)); + COMP_SPACE_RETURN(); +} + +const flambda_max_t FLAMBDA_2P32 = {UINT64_C(1) << 32, 0, 0, 0}; + +/** + * prover mux-circuit: + */ +EXPORT void prover_cst_mux_circuit_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + fpoly_t* res_f, // [out] res of degree depth + const fpoly_t* c_f, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge value for unitary tests + uint8_t* tmp_space) { // [tmp] scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + CASSERT_ALIGNMENT(res_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(c_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(a, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(chall_c, alignment_of(lambda_bytes)); + + TMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_values, 32, 3 * lambda_bytes); // 3*lambda_bytes; + TMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary1, 32, 3 * max_inputs * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary2, 32, 3 * max_inputs * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_CALL(prover_cst_check_unitary_gate_ct_ref_tmp_bytes(vole_params)); + + uint8_t* c = (uint8_t*)c_f; + uint64_t c_bytes = 2 * lambda_bytes; + flambda_max_t unary_cur_chall; + uint64_t unary_next_chall_power = 0; + + // tmp + uint8_t* res_f_u8 = (uint8_t*)res_f; + memset(res_f_u8, 0, (depth + 1) * lambda_bytes); + + // correct for check_unitary_sum + uint64_t c_pos = 0; + uint64_t num_inputs_at_depth = num_inputs; + uint8_t* a_in = (uint8_t*)a; + uint8_t* output_qary = intermediate_unitary_quary1; + + for (uint64_t d = 0; d < depth; d++) { + if (arities[d] > 2) { + // prepare the next unary challenge coefficient + if (unary_next_chall_power == 0) { + vole_params->flambda_set(unary_cur_chall, chall_c); + } else { + CASSERT(unary_next_chall_power <= vole_params->LAMBDA - 32, "unary challenge overflow (bad parameter set)"); + vole_params->flambda_product(unary_cur_chall, unary_cur_chall, FLAMBDA_2P32); + } + unary_next_chall_power += 32; + // apply the check + prover_cst_check_unitary_gate_ct_ref(vole_params, arities[d] - 1, intermediate_unitary_values, + c + c_pos * c_bytes, unary_cur_chall, tmp_space); + + prover_cst_vole_xor_gate_ct_ref(vole_params, res_f, res_f, depth, intermediate_unitary_values, 2); + // prepare the next challenge point + } + + const uint64_t num_out = (num_inputs_at_depth + arities[d] - 1) / arities[d]; + uint64_t unitary_qary_in_size = (d + 1) * lambda_bytes; + uint64_t unitary_qary_out_size = (d + 2) * lambda_bytes; + + // every mux of the layer shares the same control bits: prepare it once + prover_cst_vole_qary_mux_prepare_ctrl(vole_params, arities[d], mux_ctrl, c + c_pos * c_bytes); + + for (uint64_t j = 0; j + 1 < num_out; j++) { + prover_cst_vole_qary_mux_gate_ct_f2_prep(vole_params, arities[d], d, // + output_qary + j * unitary_qary_out_size, // + mux_ctrl, // + a_in + j * arities[d] * unitary_qary_in_size); + } + + // the last mux can be incomplete (fewer inputs => a control of its own) + { + uint64_t j = num_out - 1; // num_out >= 1: guaranteed by mux_circuit_check_shape + uint64_t last_arity = num_inputs_at_depth - j * arities[d]; + CASSERT(last_arity >= 1 && last_arity <= arities[d], "bad last mux arity"); + prover_cst_vole_qary_mux_prepare_ctrl(vole_params, last_arity, mux_ctrl_last, c + c_pos * c_bytes); + prover_cst_vole_qary_mux_gate_ct_f2_prep(vole_params, last_arity, d, // + output_qary + j * unitary_qary_out_size, // + mux_ctrl_last, // + a_in + j * arities[d] * unitary_qary_in_size); + } + + // return final value + if (d == depth - 1) { + prover_cst_vole_xor_gate_ct_ref(vole_params, res_f, res_f, depth, output_qary, d + 1); + } + + c_pos += arities[d] - 1; + num_inputs_at_depth = num_out; + if (d % 2 == 0) { + a_in = intermediate_unitary_quary1; + output_qary = intermediate_unitary_quary2; + } else { + a_in = intermediate_unitary_quary2; + output_qary = intermediate_unitary_quary1; + } + } +} + +/** + * scratch space required by verifier_cst_mux_circuit_ref + */ +EXPORT uint64_t verifier_cst_mux_circuit_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + // tmp space for calculations: 2 * lambda_bytes + // tmp space to hold intermediate values for check_unitary_gate: 2*lambda_bytes bytes + // tmp space to hold two intermediate values for qary_mux_gate: 2*3*max_inputs*lambda_bytes + // tmp space for the prepared control of a layer (full and last, incomplete, mux) + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + const uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, unitary_chk, 32, lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_even, 32, max_inputs* lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_odd, 32, max_inputs* lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_CALL(verifier_cst_check_unitary_gate_ref_tmp_bytes(vole_params)); // unitary chk + COMP_SPACE_RETURN(); +} + +/** + * verifier mux-circuit: + */ +EXPORT void verifier_cst_mux_circuit_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + flambda_t* res_q, // [out] res of degree depth + const flambda_t* c_q, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge value for unitary tests + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space) { // [tmp] scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(res_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(c_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(a, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(chall_c, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(delta2, alignment_of(lambda_bytes)); + + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + const uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + TMP_SPACE_MAP_ALIGNED(uint8_t*, unitary_chk, 32, lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_even, 32, max_inputs* lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_odd, 32, max_inputs* lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_CALL(verifier_cst_check_unitary_gate_ref_tmp_bytes(vole_params)); // unitary chk + + uint8_t* c = (uint8_t*)c_q; + uint64_t c_bytes = lambda_bytes; + flambda_max_t unary_cur_chall; + uint64_t unary_next_chall_power = 0; + + // tmp + uint8_t* res_q_u8 = (uint8_t*)res_q; + memset(res_q_u8, 0, lambda_bytes); + + uint64_t c_pos = 0; + uint64_t num_inputs_at_depth = num_inputs; + uint8_t* a_in = (uint8_t*)a; + uint8_t* output_qary = in_out_even; + uint64_t unitary_qary_in_size = lambda_bytes; + uint64_t unitary_qary_out_size = lambda_bytes; + for (uint64_t d = 0; d < depth; d++) { + if (arities[d] > 2) { + // prepare the next unary challenge coefficient + if (unary_next_chall_power == 0) { + vole_params->flambda_set(unary_cur_chall, chall_c); + } else { + CASSERT(unary_next_chall_power <= vole_params->LAMBDA - 32, "unary challenge overflow (bad parameter set)"); + vole_params->flambda_product(unary_cur_chall, unary_cur_chall, FLAMBDA_2P32); + } + unary_next_chall_power += 32; + // apply the check + verifier_cst_check_unitary_gate_ref(vole_params, arities[d] - 1, // + unitary_chk, // + c + c_pos * c_bytes, // + unary_cur_chall, delta2, tmp_space); + verifier_cst_vole_xor_gate_ref(vole_params, res_q, res_q, depth, unitary_chk, 2, delta2); + } + + const uint64_t num_out = (num_inputs_at_depth + arities[d] - 1) / arities[d]; + + // every mux of the layer shares the same control values: prepare it once + verifier_cst_vole_qary_mux_prepare_ctrl(vole_params, arities[d], mux_ctrl, c + c_pos * c_bytes, delta2); + + for (uint64_t j = 0; j + 1 < num_out; j++) { + verifier_cst_vole_qary_mux_gate_prep(vole_params, arities[d], // + output_qary + j * unitary_qary_out_size, // + mux_ctrl, // + a_in + j * arities[d] * unitary_qary_in_size, // + delta2); + } + + // the last mux can be incomplete (fewer inputs => a control of its own) + { + uint64_t j = num_out - 1; // num_out >= 1: guaranteed by mux_circuit_check_shape + uint64_t last_arity = num_inputs_at_depth - j * arities[d]; + CASSERT(last_arity >= 1 && last_arity <= arities[d], "bad last mux arity"); + verifier_cst_vole_qary_mux_prepare_ctrl(vole_params, last_arity, mux_ctrl_last, c + c_pos * c_bytes, delta2); + verifier_cst_vole_qary_mux_gate_prep(vole_params, last_arity, // + output_qary + j * unitary_qary_out_size, // + mux_ctrl_last, // + a_in + j * arities[d] * unitary_qary_in_size, // + delta2); + } + + // return final value + if (d == depth - 1) { + verifier_cst_vole_xor_gate_ref(vole_params, res_q, res_q, depth, output_qary, d + 1, delta2); + } + + c_pos += arities[d] - 1; + num_inputs_at_depth = num_out; + + if (d % 2 == 0) { + a_in = in_out_even; + output_qary = in_out_odd; + } else { + a_in = in_out_odd; + output_qary = in_out_even; + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common/rijndael256.c b/src/sig/sdith/sdith_sdith_common/rijndael256.c new file mode 100644 index 0000000000..f6a1af615b --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/rijndael256.c @@ -0,0 +1,187 @@ +#include +#include "rijndael256.h" + +static const uint8_t __sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 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 __mul2[256] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, + 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, + 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, + 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, + 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, + 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 +}; + +static const uint8_t __mul3[256] = { + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, + 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, + 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, + 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, + 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, + 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, + 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, + 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, + 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, + 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, + 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a +}; + +static const size_t __SR2[Nb] = {2, 14, 26, 6, 18, 30, 10, 22}; + +static const uint8_t __rc[14] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d}; + +static inline void _SubBytes(rijndael256_state_t state) +{ + for (size_t i = 0; i < Nbytes; i++) + { + state[i] = __sbox[state[i]]; + } +} + +static inline void _ShiftRows(rijndael256_state_t state) +{ + // shift row 1 by 1 + for (size_t i = 0; i < Nb-1; i++) + { + state[4*i+1] ^= state[4*i+5]; + state[4*i+5] ^= state[4*i+1]; + state[4*i+1] ^= state[4*i+5]; + } + + // shift row 2 by 3 + for (size_t i = 0; i < Nb-1; i++) + { + state[__SR2[i+0]] ^= state[__SR2[i+1]]; + state[__SR2[i+1]] ^= state[__SR2[i+0]]; + state[__SR2[i+0]] ^= state[__SR2[i+1]]; + } + + // shift row 3 by 4 + for (size_t i = 0; i < Nb/2; i++) + { + state[4*i+ 3] ^= state[4*i+19]; + state[4*i+19] ^= state[4*i+ 3]; + state[4*i+ 3] ^= state[4*i+19]; + } +} + +static inline void _MixColumns(rijndael256_state_t state) +{ + for (size_t i = 0; i < Nb; i++) + { + uint8_t tmp[4] = { + state[4*i+0], + state[4*i+1], + state[4*i+2], + state[4*i+3] + }; + + state[4*i+0] = __mul2[tmp[0]] ^ __mul3[tmp[1]] ^ tmp[2] ^ tmp[3]; + state[4*i+1] = __mul2[tmp[1]] ^ __mul3[tmp[2]] ^ tmp[3] ^ tmp[0]; + state[4*i+2] = __mul2[tmp[2]] ^ __mul3[tmp[3]] ^ tmp[0] ^ tmp[1]; + state[4*i+3] = __mul2[tmp[3]] ^ __mul3[tmp[0]] ^ tmp[1] ^ tmp[2]; + } +} + +static inline void _AddRoundKey(rijndael256_state_t state, const rijndael256_key_t key) +{ + for (size_t i = 0; i < Nbytes; i++) + { + state[i] ^= key[i]; + } +} + +static void _round(rijndael256_state_t state, const rijndael256_key_t key) +{ + _SubBytes(state); + _ShiftRows(state); + _MixColumns(state); + _AddRoundKey(state, key); +} + +static void _keyschedule(rijndael256_key_t key, const rijndael256_key_t oldkey, int round) +{ + for (size_t j = 0; j < Nk; j++) + { + if (j == 0) + { + key[0] = oldkey[0] ^ __sbox[oldkey[29]] ^ __rc[round-1]; + key[1] = oldkey[1] ^ __sbox[oldkey[30]]; + key[2] = oldkey[2] ^ __sbox[oldkey[31]]; + key[3] = oldkey[3] ^ __sbox[oldkey[28]]; + } else if (j == 4) { + key[16] = oldkey[16] ^ __sbox[key[12]]; + key[17] = oldkey[17] ^ __sbox[key[13]]; + key[18] = oldkey[18] ^ __sbox[key[14]]; + key[19] = oldkey[19] ^ __sbox[key[15]]; + } else { + for (size_t i = 0; i < 4; i++) + { + key[j*4+i] = oldkey[j*4+i] ^ key[(j-1)*4+i]; + } + } + } +} + +static void _encrypt(rijndael256_state_t res, const rijndael256_rk_t *roundkeys) +{ + _AddRoundKey(res, roundkeys->rk[0]); + for (size_t i = 1; i < Nr; i++) + { + _round(res, roundkeys->rk[i]); + } + _SubBytes(res); + _ShiftRows(res); + _AddRoundKey(res, roundkeys->rk[Nr]); +} + +void rijndael256_key_schedule_ref(rijndael256_rk_t *roundkeys, const uint8_t key[32]) +{ + // expand key + memcpy(roundkeys->rk[0], key, Nbytes); + for (size_t i = 1; i <= Nr; i++) + { + _keyschedule(roundkeys->rk[i], roundkeys->rk[i-1], i); + } +} + + + +void rijndael256_encrypt_1block_ref(uint8_t res[ 32], const uint8_t x[ 32], const rijndael256_rk_t *roundkeys) +{ + memcpy(res, x, 32); + // encrypt + _encrypt(res, roundkeys); +} diff --git a/src/sig/sdith/sdith_sdith_common/rijndael256.h b/src/sig/sdith/sdith_sdith_common/rijndael256.h new file mode 100644 index 0000000000..489c897616 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/rijndael256.h @@ -0,0 +1,41 @@ +#ifndef RIJNDAEL256__H +#define RIJNDAEL256__H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#include "sdith_inline.h" + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +#define Nb 8 +#define Nk 8 +#define Nbytes (Nb*4) +#define Nr 14 + +typedef uint8_t rijndael256_state_t[Nbytes]; + +#if Nb != Nk +#error "This implementation expects Nb == Nk." +#endif + +typedef uint8_t rijndael256_key_t[Nbytes]; + +typedef struct { + rijndael256_key_t rk[Nr+1]; +} rijndael256_rk_t; + +EXPORT void rijndael256_key_schedule_ref(rijndael256_rk_t *roundkeys, const uint8_t key[32]); +EXPORT void rijndael256_encrypt_1block_ref(uint8_t res[ 32], const uint8_t x[ 32], const rijndael256_rk_t *roundkeys); + +#endif diff --git a/src/sig/sdith/sdith_sdith_common/rijndael256_ctrle.h b/src/sig/sdith/sdith_sdith_common/rijndael256_ctrle.h new file mode 100644 index 0000000000..1ec160cfa9 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/rijndael256_ctrle.h @@ -0,0 +1,83 @@ +#ifndef RIJNDAEL256_CTRLE_H +#define RIJNDAEL256_CTRLE_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +#define RIJNDAEL256_RK_BYTES 480 +#define RIJNDAEL256_RNG_BYTES 608 + +/** (special API) batched key schedule: expand 1..4 independent rijndael256 keys + * into 1..4 round-key buffers (each RIJNDAEL256_RK_BYTES). Output is bit-identical + * to rijndael256_ctrle_set_key (KAT-preserving). The avx2 path uses aesenclast for + * the SubWord step and interleaves the independent keys to hide its latency; the ref + * path just loops the scalar x1. */ +EXPORT void rijndael256_key_schedule_x1_ref(void* rk0, const void* k0); +EXPORT void rijndael256_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void rijndael256_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2); +EXPORT void rijndael256_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); +EXPORT void rijndael256_key_schedule_x1_avx2(void* rk0, const void* k0); +EXPORT void rijndael256_key_schedule_x2_avx2(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void rijndael256_key_schedule_x3_avx2(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2); +EXPORT void rijndael256_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); + +/** (special API) no-carry CTR encryption. Encrypts N consecutive 32-byte blocks: + * out[i] = Rijndael256(round_keys, ctr_block with its low 64 bits += i), i in 0..N-1. + * Only the low 64 bits of the counter increment (no carry). Stateless: ctr_block + * (32 bytes) is not modified. Chains into rijndael256_ctrle_nocarry_nblocks. + * (3/4-block variants added only if they beat the 2-block chaining.) */ +EXPORT void rijndael256_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks); +EXPORT void rijndael256_ctrle_nocarry_1block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_2block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_nblocks_avx2(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks); + +/** + * (special API) Rijndael-256 proof-of-work grind over two independent keys. + * The Rijndael-256 analogue of aes128_proofow_grind_avx2. Encrypts the two 32-byte + * plaintext blocks in_pt512 (p0 || p1, 64 bytes) under the two round-key sets rk + * (rk[2], each RIJNDAEL256_RK_BYTES, contiguous = 960 bytes). If the ciphertexts + * satisfy the grinding condition ((c0.lo64 ^ c1.lo64) & mask_w) == 0, success: stores + * the two 32-byte ciphertexts in out_ct512 (c0 || c1), stores the winning counter in + * *in_out_counter, and returns 1. Otherwise increments the counter and the low 64 bits + * of both plaintexts by 1 (no carry into the upper bits) and retries. If the counter + * reaches 2^32 with no hit, stores 2^32 in *in_out_counter and returns 0. The winning + * counter is the smallest one in [initial, 2^32). + */ +EXPORT int rijndael256_proofow_grind_avx2( // + void* out_ct512, // [out] c0 || c1 (64 bytes) satisfying low64(c0 ^ c1) & mask_w == 0 + uint64_t* in_out_counter, // [in/out] starting counter (< 2^32) + const void* in_pt512, // [in] p0 || p1 (64 bytes) the initial plaintexts + const void* rk, // [in] two round-key sets rk[2][RIJNDAEL256_RK_BYTES] (960 bytes) + uint64_t mask_w // [in] the grinding condition +); + +typedef union { + uint64_t v64[4]; + uint8_t v8[32]; +} ctr256_t; + +typedef union { + uint64_t v64[4]; + uint8_t v8[32]; +} ctr256_align32_t __attribute__((aligned(32))); + +#endif // RIJNDAEL256_CTRLE_H diff --git a/src/sig/sdith/sdith_sdith_common/rijndael256_ctrle_special_ref.c b/src/sig/sdith/sdith_sdith_common/rijndael256_ctrle_special_ref.c new file mode 100644 index 0000000000..e5d0e88341 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/rijndael256_ctrle_special_ref.c @@ -0,0 +1,48 @@ +#include + +#include "rijndael256.h" +#include "rijndael256_ctrle.h" + +/* -------- batched key schedule (ref: just loop the scalar x1) -------- */ +EXPORT void rijndael256_key_schedule_x1_ref(void* rk0, const void* k0) { rijndael256_key_schedule_ref(rk0, k0); } +EXPORT void rijndael256_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1) { + rijndael256_key_schedule_ref(rk0, k0); + rijndael256_key_schedule_ref(rk1, k1); +} +EXPORT void rijndael256_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2) { + rijndael256_key_schedule_ref(rk0, k0); + rijndael256_key_schedule_ref(rk1, k1); + rijndael256_key_schedule_ref(rk2, k2); +} +EXPORT void rijndael256_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + rijndael256_key_schedule_ref(rk0, k0); + rijndael256_key_schedule_ref(rk1, k1); + rijndael256_key_schedule_ref(rk2, k2); + rijndael256_key_schedule_ref(rk3, k3); +} + +/* -------- no-carry CTR encryption (ref) -------- + * block i uses the counter with only its low 64 bits incremented by i; no carry + * into the upper bits (caller's guarantee). */ +static inline void rijndael256_nocarry_ref_impl(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + ctr256_t ctr; + uint8_t* oo = (uint8_t*)out; + memcpy(ctr.v8, ctr_block, 32); + for (uint64_t i = 0; i < nblocks; ++i) { + rijndael256_encrypt_1block_ref(oo + 32 * i, ctr.v8, (const rijndael256_rk_t*)round_keys); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } +} +EXPORT void rijndael256_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block) { + rijndael256_nocarry_ref_impl(out, round_keys, ctr_block, 1); +} +EXPORT void rijndael256_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block) { + rijndael256_nocarry_ref_impl(out, round_keys, ctr_block, 2); +} +EXPORT void rijndael256_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + rijndael256_nocarry_ref_impl(out, round_keys, ctr_block, nblocks); +} diff --git a/src/sig/sdith/sdith_sdith_common/rsd.c b/src/sig/sdith/sdith_sdith_common/rsd.c new file mode 100644 index 0000000000..b2007302e4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/rsd.c @@ -0,0 +1,282 @@ +#include +#include + +#include "sdith_prng.h" +#include "sdith_rsd.h" +#include "vole_private.h" + +EXPORT uint64_t rsd_generate_random_instance_tmp_bytes(const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim) { + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, vole_params->LAMBDA, rsd_codim); + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, h_row, 32, rsd_codim_slice); + COMP_SPACE_RETURN(); +} + +/** generate a random rsd instance out of the master key entropy. + * Constant-time in the solution it produces, except for the rejection loop of + * the position sampler (see below). tmp_space holds one expanded H row on + * return: the caller must scrub it. */ +EXPORT void rsd_generate_random_instance_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // prng + matrix-prng family + bitvec_t* y, uint64_t y_bytes, // out: syndrome (ceil(rsd_codim/8) bytes are set) + uint32_t* solution, // out: rsd_w integers in [0,n/w-1] + const seed_t* sk_seed, // in: secret key seed (lambda bits) + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + uint8_t* tmp_space // scratch space +) { + const uint64_t col_bytes = (rsd_codim + 7) >> 3; + CREQUIRE(rsd_n != 0, "empty rsd_n (%" PRId64 ")", rsd_n); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(y_bytes >= col_bytes, "y_bytes too small (%" PRId64 " vs %" PRId64 ")", y_bytes, col_bytes); + CREQUIRE(rsd_n % rsd_w == 0, "rsd_n (%" PRId64 ") is not a multiple of rsd_w (%" PRId64 ")", rsd_n, rsd_w); + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, vole_params->LAMBDA, rsd_codim); + CASSERT(col_bytes <= rsd_codim_slice, "invalid rsd_codim_slice"); + // one H row at a time: the matrix prng draws any row independently, so the + // rsd_w rows y needs cost rsd_w cipher calls instead of the whole matrix. + TMP_SPACE_MAP_ALIGNED(uint8_t*, h_row, 32, rsd_codim_slice); + // sample the solution positions from the keygen prng (the ctr keystream of the + // secret-key seed, read as little-endian uint32s). + keygen_rng_ctx sk_rng; + vole_params->keygen_rng.init(&sk_rng, sk_seed); + // generate the solution vector + const uint32_t npw = rsd_n / rsd_w; + // hit and miss version (the rejection loop is not ct, but a rejected draw is + // discarded and independent of the accepted one, so its count says nothing + // about the solution). The reduction of the accepted draw is ct: it is the + // secret itself. + const uint32_t npw_max = UINT32_MAX - (UINT32_MAX % npw); + for (uint64_t i = 0; i < rsd_w; i++) { + uint32_t pos; + do { + pos = vole_params->keygen_rng.next_u32(&sk_rng); + } while (pos >= npw_max); + uint32_t quo; + vole_params->ct.div_rem_u32(&quo, &solution[i], pos, npw); + } + vole_params->keygen_rng.release(&sk_rng); + // prepare the pk_rng to draw rows of h (row-wise matrix prng) + matrix_rng_t pk_rng; + vole_params->matrix_prg.matrix_rng_init(&pk_rng, pk_seed, rsd_codim); + // Compute y. The plain form of the loop body is: + // if (real_index < rsd_codim) { + // yy ^= single_bit_at(real_index) // the identity block of H + // } else { + // yy ^= get_pk_row(real_index - rsd_codim) // the random block of H + // } + // but real_index is secret, so the test may not be branched on: both arms run + // for every i, and a mask keeps the one that counts. The extra cost is one + // cipher row per identity-block hit -- a handful. + memset(y, 0, y_bytes); + for (uint64_t i = 0; i < rsd_w; i++) { + const uint64_t real_index = i * npw + solution[i]; + const uint64_t in_id = vole_params->ct.mask_lt(real_index, rsd_codim); // ~0 on the identity block + const uint64_t in_rnd = ~in_id; // ~0 on the random block + // else-arm: draw the row unconditionally (index clamped to 0 when unused, + // so the draw itself reveals nothing) and xor it under the mask + vole_params->matrix_prg.matrix_rng_get_row(&pk_rng, h_row, (real_index - rsd_codim) & in_rnd); + vole_params->ct.bitvec_xor_to_masked(y, col_bytes, h_row, in_rnd); + // then-arm: flip bit real_index, at a secret position (clamped to 0 when + // unused, the same way as the else-arm: the xor is a no-op under a zero + // mask, but the position must stay inside y for the debug range check) + vole_params->ct.bitvec_xorbit(y, col_bytes, real_index & in_id, in_id); + } + vole_params->matrix_prg.matrix_rng_release(&pk_rng); +} + +/** expand the public key from the pubkey seed */ +EXPORT void rsd_expand_public_key_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // matrix-prng family + bitmat_t* h, uint64_t h_slice_bytes, // out: (rsd_n - rsd_codim) x rsd_n matrix + const seed_t* h_seed // in: pubkey seed (lambda bits) +) { + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, lambda, rsd_codim); + const uint64_t row_out_bytes = rsd_codim_limbs * lambda_bytes; // matrix_prg row size + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + CREQUIRE(h_slice_bytes >= row_out_bytes, // + "h_slice_bytes too small (%" PRId64 " vs %" PRId64 ")", h_slice_bytes, row_out_bytes); + const uint64_t n_minus_k = rsd_n - rsd_codim; + memset(h, 0, n_minus_k * h_slice_bytes); + // Each H row is one matrix_prg row (rsd_codim bits, bits beyond that masked to + // zero, padded to rsd_codim_limbs limbs). The rows are independent, so we + // write each directly into its (block-aligned) slice of h. + matrix_rng_t h_rng; + vole_params->matrix_prg.matrix_rng_init(&h_rng, h_seed, rsd_codim); + uint8_t* const hh = (uint8_t*)h; + if (h_slice_bytes == rsd_codim_slice) { + // the prng rows tile h exactly: the whole matrix is a single batch, written + // in place (h holds the expanded matrix anyway, so this costs no extra RAM). + vole_params->matrix_prg.matrix_rng_get_rows(&h_rng, hh, 0, n_minus_k); + } else { + // h is laid out with wider slices than the prng row size: one row at a time + // so the extra padding bytes of each slice stay zero. + for (uint64_t i = 0; i < n_minus_k; i++) { + vole_params->matrix_prg.matrix_rng_get_row(&h_rng, hh + h_slice_bytes * i, i); + } + } + vole_params->matrix_prg.matrix_rng_release(&h_rng); +} + +EXPORT uint64_t rsd_public_key_times_challenge_tmp_bytes(const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim) { + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + const uint64_t lambda = vole_params->LAMBDA; + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, lambda, rsd_codim); + // the scratch holds the pre-processed challenge, which y_full aliases, so it + // must also be wide enough for one slice. + const uint64_t scratch_bytes = matrix_rng_prep_chall_nelems(rsd_codim) * vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, scratch, 32, scratch_bytes < rsd_codim_slice ? rsd_codim_slice : scratch_bytes); + COMP_SPACE_RETURN(); +} + +/** expand and multiply the public key with challenge points */ +EXPORT void rsd_public_key_times_challenge_ref( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + flambda_t* chall_a_H, // out: n elements + flambda_t* chall_a_y, // out: 1 element + const flambda_t* chall_a, // in: rsd_codim_limbs elements + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + const bitvec_t* y, // in: pubkey y (rsd_codim bits padded with zeros) + uint8_t* tmp_space // scratch space +) { + static const uint64_t TWO[] = {2, 0, 0, 0}; + CASSERT(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CASSERT(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CASSERT(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, lambda, rsd_codim); + const uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + const uint64_t rsd_padding_bytes = rsd_codim_limbs * lambda_bytes - rsd_codim_bytes; + const uint64_t n_minus_k = rsd_n - rsd_codim; + const uint8_t h_last_mask = 0xFF >> ((-rsd_codim) & 7); + const uint64_t scratch_bytes = matrix_rng_prep_chall_nelems(rsd_codim) * lambda_bytes; + TMP_SPACE_MAP_ALIGNED(uint8_t*, scratch, 32, + scratch_bytes < rsd_codim_slice ? rsd_codim_slice : scratch_bytes); + uint8_t* y_full = scratch; // alias (y_full fits in rsd_codim_slice by definition) + +#ifndef NDEBUG + uint64_t leftover_bits = rsd_codim & 7; + uint8_t* y_u8 = (uint8_t*)y; + if (leftover_bits) { + uint64_t mask = ((1 << (8 - leftover_bits)) - 1) << leftover_bits; + uint64_t idx = ((rsd_codim + 7) >> 3) - 1; + CASSERT((y_u8[idx] & mask) == 0, "empty bits of y are not zero-ed out"); + } +#endif // NDEBUG + + // deal with y (chall_a_y = ) + memcpy(y_full, y, rsd_codim_bytes); + y_full[rsd_codim_bytes - 1] &= h_last_mask; + memset(y_full + rsd_codim_bytes, 0, rsd_padding_bytes); + vole_params->flambda_dot_product(chall_a_y, y_full, chall_a, rsd_codim_limbs); + // deal with the id block of H + uint8_t* dest = chall_a_H; + { + uint64_t s = rsd_codim; + for (uint64_t i = 0; i < rsd_codim_limbs; i++) { + uint64_t block_s = lambda < s ? lambda : s; + vole_params->flambda_set(dest, chall_a + i * lambda_bytes); + dest += lambda_bytes; + for (uint64_t j = 1; j < block_s; j++) { + vole_params->flambda_product(dest, dest - lambda_bytes, TWO); + dest += lambda_bytes; + } + s -= block_s; + } + CASSERT(dest == chall_a_H + rsd_codim * lambda_bytes, "bug!"); + CASSERT(s == 0, "bug!"); + } + // deal with the regular rows of H. H is never materialised: the whole block is + // one fused call that generates each row and multiplies it by the challenge + // without the row ever reaching memory. + matrix_rng_t h_rng; + vole_params->matrix_prg.matrix_rng_init(&h_rng, pk_seed, rsd_codim); + vole_params->matrix_prg.matrix_rng_preprocess_chall(&h_rng, scratch, chall_a); + vole_params->matrix_prg.matrix_rng_rows_times_chall(&h_rng, dest, scratch, 0, n_minus_k); + vole_params->matrix_prg.matrix_rng_release(&h_rng); +#ifndef NDEBUG + dest += n_minus_k * lambda_bytes; + CASSERT(dest == chall_a_H + rsd_n * lambda_bytes, "bug!"); +#endif // NDEBUG +} + +/** unary encoding of the solution (for mux circuits). Constant-time in the + * solution: the dimensions and the arities are public, only the coefficients + * are not. */ +EXPORT void rsd_encode_solution_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // ct helpers + uint64_t mux_depth, const uint64_t* mux_arities, // mux depth and arities + bitvec_t* encoded_solution, uint64_t encoded_solution_bytes, // encoded solution + const uint32_t* solution // in: solution coefficients +) { + CREQUIRE(rsd_n != 0, "empty rsd_n (%" PRId64 ")", rsd_n); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + CREQUIRE(mux_depth != 0, "empty mux_depth (%" PRId64 ")", mux_depth); + CREQUIRE(rsd_n % rsd_w == 0, "rsd_n (%" PRId64 ") is not a multiple of rsd_w (%" PRId64 ")", rsd_n, rsd_w); + const uint64_t npw = rsd_n / rsd_w; + uint64_t mux_size = 1; + uint64_t mux_inputs = 0; + for (uint64_t j = 0; j < mux_depth; j++) { + const uint64_t arj = mux_arities[j]; + CREQUIRE(arj >= 2, "mux_arity[%" PRId64 "]=%" PRId64 " too small", j, arj); + // the one-hot field of a level must fit in the uint32 bitvec_xoru32 takes + CREQUIRE(arj < 32, "mux_arity[%" PRId64 "]=%" PRId64 " too large", j, arj); + mux_inputs += arj - 1; + mux_size *= arj; + } + CREQUIRE(mux_size >= npw, "mux arities too small (max_tree_size: %" PRId64 " vs. %" PRId64 ")", mux_size, npw); + uint64_t encoded_solution_actual_bytes = (mux_inputs * rsd_w + 7) >> 3; + CREQUIRE(encoded_solution_bytes >= encoded_solution_actual_bytes, // + "encoded_solutions too small (size: %" PRId64 " vs. min size: %" PRId64 ")", // + encoded_solution_bytes, encoded_solution_actual_bytes); + uint8_t* const sol = encoded_solution; + memset(sol, 0, encoded_solution_bytes); + // Every (element, mux level) owns a field of arj-1 bits at a PUBLIC offset + // bitpos, since bitpos only ever advances by the public arj-1. Inside that + // field the plain form of the body is: + // if (sij != 0) { sol ^= single_bit_at(bitpos + sij - 1) } + // with sij secret. Rather than address that bit, we build the one-hot field + // as a value and xor the whole field in at its public offset: the address is + // public, only the bits are secret. + uint64_t bitpos = 0; + for (uint64_t i = 0; i < rsd_w; i++) { + uint32_t si = solution[i]; + for (uint64_t j = 0; j < mux_depth; j++) { + const uint64_t arj = mux_arities[j]; + uint32_t sij; + vole_params->ct.div_rem_u32(&si, &sij, si, (uint32_t)arj); + // (sij == 0) ? 0 : 1 << (sij - 1), with no test: the >> 1 turns the sij=0 + // case into 0 by itself. arj < 32 keeps the shift in range for every sij. + // The shift amount is secret, which is fine: a shift by a register count + // is data-independent on every target here (x86-64 SHL/SHR, aarch64 LSL). + const uint32_t one_hot = (UINT32_C(1) << sij) >> 1; + vole_params->ct.bitvec_xoru32(sol, encoded_solution_bytes, bitpos, arj - 1, one_hot); + bitpos += arj - 1; + } + CASSERT(si == 0, "bug"); + } + CASSERT(bitpos == rsd_w * mux_inputs, "bug"); +} diff --git a/src/sig/sdith/sdith_sdith_common/sdith_algebra.h b/src/sig/sdith/sdith_sdith_common/sdith_algebra.h new file mode 100644 index 0000000000..110c3c2dbb --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_algebra.h @@ -0,0 +1,43 @@ +#ifndef SDITH_ALGEBRA_H +#define SDITH_ALGEBRA_H + +// This file contains the declaration of all algebra functions over vectors and matrices over F2 + +#include "commons.h" + +/** vector addition over F2 */ +EXPORT void bitvec_xor_to_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* b); +EXPORT void bitvec_xor_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b); +EXPORT void bitvec_xor_to_avx2(uint64_t bytelen, bitvec_t* res, const bitvec_t* b); +EXPORT void bitvec_xor_avx2(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b); +/** cascade vector addition over F2 (b^=c then a^=b) */ +EXPORT void bitvec_cascade_xor_to_ref(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a); +EXPORT void bitvec_cascade_xor_to_avx2(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a); + +/** matrix vector product over F2 */ +// (expect nrows between 120 and 260, ncols can be restricted to a multiple of 8) +EXPORT void matrix_vector_product_f2_ref( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b); // bit vector of size ncols +EXPORT void matrix_vector_product_f2_avx2( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b); // bit vector of size ncols + +/** matrix vector product over F2 */ +// (expect nrows between 120 and 260, ncols can be restricted to a multiple of 8. lambda will be 128, 192, or 256) +EXPORT void matrix_f2_times_vector_flambda_ref( // + uint64_t lambda, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b); // vector of size ncols +EXPORT void matrix_f2_times_vector_flambda_avx2( // + uint64_t lambda, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b); // vector of size ncols + +#endif // SDITH_ALGEBRA_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_arithmetic.h b/src/sig/sdith/sdith_sdith_common/sdith_arithmetic.h new file mode 100644 index 0000000000..07e53aafe9 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_arithmetic.h @@ -0,0 +1,185 @@ +#ifndef SDITH_ARITHMETIC_H +#define SDITH_ARITHMETIC_H + +// This file contains the declaration of all aritmetic functions over F_2^128, F_2^192, and F_2^256 + +#include "commons.h" + +typedef union gf128_t gf128 __attribute((aligned(16))); +typedef union gf192_t gf192 __attribute((aligned(8))); +typedef union gf256_t gf256 __attribute((aligned(32))); + +/* res = a [requires a flambda_t version] */ +EXPORT void gf128_set_ref(gf128* res, const gf128* a); +EXPORT void gf192_set_ref(gf192* res, const gf192* a); +EXPORT void gf256_set_ref(gf256* res, const gf256* a); +EXPORT void gf128_flambda_set_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf192_flambda_set_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf256_flambda_set_ref(flambda_t* res, const flambda_t* a); + +/* res = a + b [requires a flambda_t version] */ +EXPORT void gf128_sum_ref(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf128_sum_avx2(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf256_sum_ref(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_sum_avx2(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf128_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf128_flambda_sum_avx2(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_sum_avx2(flambda_t* res, const flambda_t* a, const flambda_t* b); + +/* res = a * b [requires a flambda_t version] */ +EXPORT void gf128_product_ref(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf128_product_f2_ref(gf128* res, const gf128* a, const gf128* b_f2); +EXPORT void gf128_product_pclmul(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf128_product_pclmul_f2(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf192_product_ref(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf192_product_f2_ref(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf192_product_pclmul(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf256_product_ref(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_product_f2_ref(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_product_pclmul(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_product_pclmul_f2(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf128_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf128_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2); +EXPORT void gf128_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf128_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, const flambda_t* b); + +/* res = sum_{i=0}^{size-1} x[i] * y[i] [requires a flambda_t version] */ +EXPORT void gf128_dot_product_ref(gf128* res, const gf128* x, const gf128* y, const uint64_t size); +EXPORT void gf128_dot_product_pclmul(gf128* res, const gf128* x, const gf128* y, const uint64_t size); +EXPORT void gf192_dot_product_ref(gf192* res, const gf192* x, const gf192* y, const uint64_t size); +EXPORT void gf192_dot_product_pclmul(gf192* res, const gf192* x, const gf192* y, const uint64_t size); +EXPORT void gf256_dot_product_ref(gf256* res, const gf256* x, const gf256* y, const uint64_t size); +EXPORT void gf256_dot_product_pclmul(gf256* res, const gf256* x, const gf256* y, const uint64_t size); +EXPORT void gf128_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf128_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf192_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf192_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf256_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf256_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); + +/* res += sum_{i=0}^{size-1} x[i . x_byte_slice] * y[i] (x is strided, y is contiguous) + * x_byte_slice is a byte stride, and must be a multiple of the element size. [requires a flambda_t version] */ +EXPORT void gf128_dot_product_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size); +EXPORT void gf128_dot_product_acc_pclmul(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size); +EXPORT void gf192_dot_product_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size); +EXPORT void gf192_dot_product_acc_pclmul(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size); +EXPORT void gf256_dot_product_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size); +EXPORT void gf256_dot_product_acc_pclmul(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size); +EXPORT void gf128_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf128_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf192_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf192_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf256_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf256_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); + +/* res += sum_{i=0}^{size-1} x[i . x_byte_slice] * y_f2[i], where every y_f2[i] is 0 or 1. + * Same conventions as the *_acc dot products above. [requires a flambda_t version] */ +EXPORT void gf128_dot_product_f2_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size); +EXPORT void gf128_dot_product_f2_acc_avx2(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size); +EXPORT void gf192_dot_product_f2_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size); +EXPORT void gf192_dot_product_f2_acc_avx2(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size); +EXPORT void gf256_dot_product_f2_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size); +EXPORT void gf256_dot_product_f2_acc_avx2(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size); +EXPORT void gf128_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf128_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf192_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf192_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf256_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf256_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); + +/* res = a^-1 [requires a flambda_t version] */ +EXPORT void gf128_inverse_ref(gf128* res, const gf128* a); +EXPORT void gf128_inverse_pclmul(gf128* res, const gf128* a); +EXPORT void gf192_inverse_ref(gf192* res, const gf192* a); +EXPORT void gf192_inverse_pclmul(gf192* res, const gf192* a); +EXPORT void gf256_inverse_ref(gf256* res, const gf256* a); +EXPORT void gf256_inverse_pclmul(gf256* res, const gf256* a); +EXPORT void gf128_flambda_inverse_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf128_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a); +EXPORT void gf192_flambda_inverse_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf192_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a); +EXPORT void gf256_flambda_inverse_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf256_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a); + +/** Combine lambda bit Vole into a big field Vole */ +/** res = sum 2^i.x_i [requires a flambda_t version] */ +EXPORT void gf128_sum_pow2_naive(gf128* res, const gf128* x); +EXPORT void gf128_sum_pow2_ref(gf128* res, const gf128* x); +EXPORT void gf192_sum_pow2_naive(gf192* res, const gf192* x); +EXPORT void gf192_sum_pow2_ref(gf192* res, const gf192* x); +EXPORT void gf192_sum_pow2_avx2(gf192* res, const gf192* x); +EXPORT void gf256_sum_pow2_naive(gf256* res, const gf256* x); +EXPORT void gf256_sum_pow2_ref(gf256* res, const gf256* x); +EXPORT void gf128_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x); +// EXPORT void gf128_flambda_sum_pow2_avx2(flambda_t* res, const flambda_t* x); +EXPORT void gf192_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x); +// EXPORT void gf192_flambda_sum_pow2_avx2(flambda_t* res, const flambda_t* x); +EXPORT void gf256_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x); +// EXPORT void gf256_flambda_sum_pow2_avx2(flambda_t* res, const flambda_t* x); + +/** sum_{i=0 to k-1} x_i . 2^{k.i} [requires flambda version] */ +EXPORT void gf128_echelon_pow2_naive(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_echelon_pow2_ref(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_echelon_pow2_avx(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_echelon_pow2_naive(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_echelon_pow2_ref(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_echelon_pow2_avx(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_echelon_pow2_naive(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_echelon_pow2_ref(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_echelon_pow2_avx(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); + +/** This function takes a matrix of B x B bits, and transposes it */ +EXPORT void transpose_128_128_naive(void* out, const void* in); +EXPORT void transpose_192_192_naive(void* out, const void* in); +EXPORT void transpose_256_256_naive(void* out, const void* in); +EXPORT void transpose_128_128_ref(void* x); +EXPORT void transpose_192_192_ref(void* x); +EXPORT void transpose_256_256_ref(void* x); +EXPORT void transpose_128_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_192_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_256_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_128_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_192_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_256_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice); + +#endif // SDITH_ARITHMETIC_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_ct_utils.h b/src/sig/sdith/sdith_sdith_common/sdith_ct_utils.h new file mode 100644 index 0000000000..737cd7b559 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_ct_utils.h @@ -0,0 +1,108 @@ +#ifndef SDITH_CT_UTILS_H +#define SDITH_CT_UTILS_H + +// Constant-time helpers. +// +// Scope: this is a digital signature, so the verifier only ever touches public +// data and has nothing to protect. Only the prover side must be constant-time, +// and only with respect to the secret key (the rsd solution), the keygen +// entropy, and the root ggm seed. Everything derived from the public key, from +// the message, or from the parameters may branch and index freely. +// +// "Constant-time" here means: no branch and no memory address depends on a +// secret. Secret *values* may flow through arithmetic and through AES-NI, which +// are data-independent. The idiom is a mask -- 0 or ~0 (all ones) -- built from +// a secret comparison and then AND-ed into the value that would otherwise have +// been selected by an `if`. +// +// As everywhere else in this codebase there is a _ref and an _avx +// implementation of each function, and as everywhere else the _ref one is the +// readable definition rather than the fast (here: rather than the hardened) +// one: it is written the way the algorithm reads, and a C compiler is free to +// turn its masks back into branches. The _avx implementations are the ones that +// are actually constant-time -- they pin the mask arithmetic down in inline +// assembly, which the compiler cannot rewrite. The two agree bit for bit, so +// the _ref ones stay usable as the test oracle. +// +// Functions are suffixed _ct_ref / _ct_avx; inside the ct_utils struct the _ct +// is implied and dropped. + +#include "commons.h" + +// Naming convention below: an input that may carry a secret is prefixed +// secret_, one that is required to be public is prefixed public_. Lengths +// (bytelen) are public everywhere in this codebase and are left unprefixed. +// The distinction is load-bearing: bitvec_xoru32 may only be handed a PUBLIC +// bit position (it writes at that address), while bitvec_xorbit accepts a +// SECRET one (and pays a full sweep of the vector for it). + +/** mask_lt: -(a < b), i.e. ~0 when a < b and 0 otherwise (unsigned) */ +/** mask_eq: -(a == b), i.e. ~0 when a == b and 0 otherwise */ +typedef uint64_t CT_MASK_F(uint64_t secret_a, uint64_t secret_b); + +/** q = n / d and r = n % d. */ +typedef void CT_DIV_REM_U32_F(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d); + +/** res ^= b & mask, over bytelen bytes. mask is 0 or ~0 (a whole-vector select). */ +typedef void CT_BITVEC_XOR_TO_MASKED_F(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask); + +/** res[public_bitpos .. public_bitpos+public_nbits) ^= the low public_nbits + * bits of value (public_nbits <= 32). Only the value is secret. */ +typedef void CT_BITVEC_XORU32_F(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value); + +/** res[secret_bitpos] ^= 1, if mask is ~0 (nothing if mask is 0). */ +typedef void CT_BITVEC_XORBIT_F(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask); + +EXPORT uint64_t mask_lt_ct_ref(uint64_t secret_a, uint64_t secret_b); +EXPORT uint64_t mask_eq_ct_ref(uint64_t secret_a, uint64_t secret_b); +EXPORT void div_rem_u32_ct_ref(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d); +EXPORT void bitvec_xor_to_masked_ct_ref(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask); +EXPORT void bitvec_xoru32_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value); +EXPORT void bitvec_xorbit_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask); + +#ifdef __x86_64__ +EXPORT uint64_t mask_lt_ct_avx(uint64_t secret_a, uint64_t secret_b); +EXPORT uint64_t mask_eq_ct_avx(uint64_t secret_a, uint64_t secret_b); +EXPORT void div_rem_u32_ct_avx(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d); +EXPORT void bitvec_xor_to_masked_ct_avx(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask); +EXPORT void bitvec_xoru32_ct_avx(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value); +EXPORT void bitvec_xorbit_ct_avx(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask); +#endif + +typedef struct ct_utils_t { + CT_MASK_F* mask_lt; + CT_MASK_F* mask_eq; + CT_DIV_REM_U32_F* div_rem_u32; + CT_BITVEC_XOR_TO_MASKED_F* bitvec_xor_to_masked; + CT_BITVEC_XORU32_F* bitvec_xoru32; + CT_BITVEC_XORBIT_F* bitvec_xorbit; +} ct_utils; + +static const ct_utils ct_utils_ref = { + mask_lt_ct_ref, // + mask_eq_ct_ref, // + div_rem_u32_ct_ref, // + bitvec_xor_to_masked_ct_ref, // + bitvec_xoru32_ct_ref, // + bitvec_xorbit_ct_ref, // +}; +// ONLY_REF_IMPLEMENTATION drops the *_avx2.c translation units, so this table +// would hold undefined references: it is only compiled with the avx2 backend. +#if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) +static const ct_utils ct_utils_avx = { + mask_lt_ct_avx, // + mask_eq_ct_avx, // + div_rem_u32_ct_avx, // + bitvec_xor_to_masked_ct_avx, // + bitvec_xoru32_ct_avx, // + bitvec_xorbit_ct_avx, // +}; +#endif + +#endif // SDITH_CT_UTILS_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_inline.h b/src/sig/sdith/sdith_sdith_common/sdith_inline.h new file mode 100644 index 0000000000..b55b41d2ca --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_inline.h @@ -0,0 +1,21 @@ +#ifndef sdith_inline_H +#define sdith_inline_H + +// Force inlining of a file-local helper. +// Designed to be behaviourally consistent across different compilers. +#if defined(_MSC_VER) +#define SDITH_ALWAYS_INLINE static __forceinline +#elif defined(__GNUC__) || defined(__clang__) +#define SDITH_ALWAYS_INLINE static inline __attribute__((__always_inline__)) +#else +#define SDITH_ALWAYS_INLINE static inline +#endif + +// Mark a variable as possibly unused, to suppress compiler warnings. +#if defined(__GNUC__) || defined(__clang__) +#define SDITH_MAYBE_UNUSED __attribute__((__unused__)) +#else +#define SDITH_MAYBE_UNUSED +#endif + +#endif // sdith_inline_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_namespace.h b/src/sig/sdith/sdith_sdith_common/sdith_namespace.h new file mode 100644 index 0000000000..8691c1c0e4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_namespace.h @@ -0,0 +1,528 @@ +#ifndef SDITH_NAMESPACE_H +#define SDITH_NAMESPACE_H + +/** + * Generated by integration/liboqs/gen_namespace.sh. Do not edit by hand. + * + * liboqs compiles the shared SDitH sources once and links every scheme variant + * against that single copy, so these symbols are global in liboqs' own library. + */ + +#ifdef APPLY_NAMESPACE + +#ifndef concat2 +#define _concat2(a, b) a##b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_NAMESPACE_FOR_LIBOQS(s) concat2(APPLY_NAMESPACE, s) + +#define CAT1_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_CIPHERPOW_PARAMETERS) +#define CAT1_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_PARAMETERS) +#define CAT1_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_CIPHERPOW_PARAMETERS) +#define CAT1_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_PARAMETERS) +#define CAT3_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_CIPHERPOW_PARAMETERS) +#define CAT3_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_PARAMETERS) +#define CAT3_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_CIPHERPOW_PARAMETERS) +#define CAT3_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_PARAMETERS) +#define CAT5_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_CIPHERPOW_PARAMETERS) +#define CAT5_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_PARAMETERS) +#define CAT5_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_CIPHERPOW_PARAMETERS) +#define CAT5_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_PARAMETERS) +#define FLAMBDA_2P32 SDITH_NAMESPACE_FOR_LIBOQS(FLAMBDA_2P32) +#define GF128_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF128_ONE) +#define GF128_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF128_ZERO) +#define GF192_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF192_ONE) +#define GF192_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF192_ZERO) +#define GF256_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF256_ONE) +#define GF256_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF256_ZERO) +#define HASH_AUX_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_AUX_PREFIX) +#define HASH_BAVC_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_BAVC_PREFIX) +#define HASH_LINES_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_LINES_PREFIX) +#define HASH_PIOP_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_PIOP_PREFIX) +#define PROOFOW_CTR_REVEALED_BYTES SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_CTR_REVEALED_BYTES) +#define PROOFOW_H0_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H0_PREFIX) +#define PROOFOW_H1_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H1_PREFIX) +#define aes128_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_avx2) +#define aes128_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_ref) +#define aes128_ctrle_nocarry_2blk_x4keys_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2blk_x4keys_avx2) +#define aes128_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_avx2) +#define aes128_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_ref) +#define aes128_ctrle_nocarry_3blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_avx2) +#define aes128_ctrle_nocarry_3blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_ref) +#define aes128_ctrle_nocarry_4blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_avx2) +#define aes128_ctrle_nocarry_4blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_ref) +#define aes128_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_avx2) +#define aes128_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_ref) +#define aes128_ctrle_set_key_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_set_key_avx2) +#define aes128_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_encrypt_1block_ref) +#define aes128_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_avx2) +#define aes128_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_ref) +#define aes128_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_avx2) +#define aes128_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_ref) +#define aes128_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_avx2) +#define aes128_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_ref) +#define aes128_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_avx2) +#define aes128_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_ref) +#define aes128_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(aes128_keyexp_x4_enclast) +#define aes128_prepare_rk_buffer SDITH_NAMESPACE_FOR_LIBOQS(aes128_prepare_rk_buffer) +#define aes128_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_proofow_grind_avx2) +#define aes128_release_key SDITH_NAMESPACE_FOR_LIBOQS(aes128_release_key) +#define aes128_set_key_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_ref) +#define aes128_set_key_reuse_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_reuse_ref) +#define binval_of SDITH_NAMESPACE_FOR_LIBOQS(binval_of) +#define binval_of_compat SDITH_NAMESPACE_FOR_LIBOQS(binval_of_compat) +#define bit_of SDITH_NAMESPACE_FOR_LIBOQS(bit_of) +#define bitmat_get_value SDITH_NAMESPACE_FOR_LIBOQS(bitmat_get_value) +#define bitvec_cascade_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_avx2) +#define bitvec_cascade_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_ref) +#define bitvec_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(bitvec_is_zero_nonct) +#define bitvec_xor_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_avx2) +#define bitvec_xor_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_ref) +#define bitvec_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_avx2) +#define bitvec_xor_to_masked_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_avx) +#define bitvec_xor_to_masked_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_ref) +#define bitvec_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_ref) +#define bitvec_xorbit_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_avx) +#define bitvec_xorbit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_ref) +#define bitvec_xoru32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_avx) +#define bitvec_xoru32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_ref) +#define both_vole_consistency_check_matrix SDITH_NAMESPACE_FOR_LIBOQS(both_vole_consistency_check_matrix) +#define bytes_of_proofow_ctx_cipher_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat1) +#define bytes_of_proofow_ctx_cipher_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat3) +#define bytes_of_proofow_ctx_cipher_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat5) +#define bytes_of_proofow_ctx_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat1) +#define bytes_of_proofow_ctx_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat3) +#define bytes_of_proofow_ctx_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat5) +#define ceil_log2i SDITH_NAMESPACE_FOR_LIBOQS(ceil_log2i) +#define compute_extended_parameters SDITH_NAMESPACE_FOR_LIBOQS(compute_extended_parameters) +#define compute_rsd_codim SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim) +#define compute_rsd_codim_slice SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim_slice) +#define compute_tweaked_salts SDITH_NAMESPACE_FOR_LIBOQS(compute_tweaked_salts) +#define delta1_from_delta0_ref SDITH_NAMESPACE_FOR_LIBOQS(delta1_from_delta0_ref) +#define delta2_from_delta1_ref SDITH_NAMESPACE_FOR_LIBOQS(delta2_from_delta1_ref) +#define div_rem_u32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_avx) +#define div_rem_u32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_ref) +#define estimate_topen SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen) +#define estimate_topen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen_tmp_bytes) +#define extend_leaf_seed_cat1_aes128_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_avx2) +#define extend_leaf_seed_cat1_aes128_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_ref) +#define extend_leaf_seed_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_avx2) +#define extend_leaf_seed_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_ref) +#define extend_leaf_seed_cat3_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_avx2) +#define extend_leaf_seed_cat3_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_ref) +#define extend_leaf_seed_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_avx2) +#define extend_leaf_seed_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_ref) +#define extend_leaf_seed_cat5_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_avx2) +#define extend_leaf_seed_cat5_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_ref) +#define extend_leaf_seed_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_avx2) +#define extend_leaf_seed_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_ref) +#define extended_node_seed_bytes_cat1_aes128 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat1_aes128) +#define extended_node_seed_bytes_cat3_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat3_rijndael256) +#define extended_node_seed_bytes_cat5_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat5_rijndael256) +#define extract_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(extract_kappabit_uint) +#define extseed_buf_noop SDITH_NAMESPACE_FOR_LIBOQS(extseed_buf_noop) +#define flambda_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(flambda_is_zero_nonct) +#define flambda_power SDITH_NAMESPACE_FOR_LIBOQS(flambda_power) +#define floor_log2i SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i) +#define floor_log2i_compat SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i_compat) +#define full_ggm_tree_open_sibling_path_from_root SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root) +#define full_ggm_tree_open_sibling_path_from_root_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root_tmp_bytes) +#define gf128_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_pclmul) +#define gf128_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_ref) +#define gf128_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_avx2) +#define gf128_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_ref) +#define gf128_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_pclmul) +#define gf128_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_ref) +#define gf128_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_avx) +#define gf128_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_naive) +#define gf128_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_ref) +#define gf128_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_pclmul) +#define gf128_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_ref) +#define gf128_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_avx2) +#define gf128_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_ref) +#define gf128_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_pclmul) +#define gf128_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_ref) +#define gf128_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_avx) +#define gf128_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_ref) +#define gf128_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_pclmul) +#define gf128_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_ref) +#define gf128_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_f2_ref) +#define gf128_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul) +#define gf128_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul_f2) +#define gf128_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_ref) +#define gf128_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_set_ref) +#define gf128_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_avx2) +#define gf128_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_pow2_ref) +#define gf128_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_ref) +#define gf128_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_pclmul) +#define gf128_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_ref) +#define gf128_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_f2_ref) +#define gf128_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul) +#define gf128_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul_f2) +#define gf128_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_ref) +#define gf128_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_set_ref) +#define gf128_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_avx2) +#define gf128_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_naive) +#define gf128_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_ref) +#define gf128_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_ref) +#define gf128p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_lsh) +#define gf128p_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128p_mul) +#define gf128p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_rsh) +#define gf128p_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128p_sum) +#define gf128v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf128v_bitof) +#define gf128v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf128v_equals) +#define gf128v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_lsh) +#define gf128v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128v_mul) +#define gf128v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_rsh) +#define gf128v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128v_sum) +#define gf192_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_pclmul) +#define gf192_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_ref) +#define gf192_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_avx2) +#define gf192_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_ref) +#define gf192_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_pclmul) +#define gf192_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_ref) +#define gf192_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_avx) +#define gf192_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_naive) +#define gf192_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_ref) +#define gf192_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_pclmul) +#define gf192_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_ref) +#define gf192_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_avx2) +#define gf192_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_ref) +#define gf192_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_pclmul) +#define gf192_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_ref) +#define gf192_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_avx) +#define gf192_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_ref) +#define gf192_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_pclmul) +#define gf192_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_ref) +#define gf192_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_f2_ref) +#define gf192_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_pclmul) +#define gf192_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_ref) +#define gf192_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_set_ref) +#define gf192_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_pow2_ref) +#define gf192_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_ref) +#define gf192_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_pclmul) +#define gf192_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_ref) +#define gf192_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_f2_ref) +#define gf192_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_pclmul) +#define gf192_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_ref) +#define gf192_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_set_ref) +#define gf192_sum_pow2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_avx2) +#define gf192_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_naive) +#define gf192_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_ref) +#define gf192_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_ref) +#define gf192p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_lsh) +#define gf192p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_rsh) +#define gf192v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf192v_bitof) +#define gf192v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf192v_equals) +#define gf192v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_lsh) +#define gf192v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf192v_mul) +#define gf192v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_rsh) +#define gf192v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf192v_sum) +#define gf256_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_pclmul) +#define gf256_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_ref) +#define gf256_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_avx2) +#define gf256_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_ref) +#define gf256_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_pclmul) +#define gf256_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_ref) +#define gf256_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_avx) +#define gf256_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_naive) +#define gf256_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_ref) +#define gf256_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_pclmul) +#define gf256_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_ref) +#define gf256_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_avx2) +#define gf256_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_ref) +#define gf256_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_pclmul) +#define gf256_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_ref) +#define gf256_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_avx) +#define gf256_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_ref) +#define gf256_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_pclmul) +#define gf256_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_ref) +#define gf256_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_f2_ref) +#define gf256_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul) +#define gf256_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul_f2) +#define gf256_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_ref) +#define gf256_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_set_ref) +#define gf256_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_avx2) +#define gf256_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_pow2_ref) +#define gf256_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_ref) +#define gf256_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_pclmul) +#define gf256_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_ref) +#define gf256_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_f2_ref) +#define gf256_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul) +#define gf256_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul_f2) +#define gf256_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_ref) +#define gf256_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_set_ref) +#define gf256_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_avx2) +#define gf256_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_naive) +#define gf256_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_ref) +#define gf256_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_ref) +#define gf256p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_lsh) +#define gf256p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_rsh) +#define gf256v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf256v_bitof) +#define gf256v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf256v_equals) +#define gf256v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_lsh) +#define gf256v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf256v_mul) +#define gf256v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_rsh) +#define gf256v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf256v_sum) +#define gfprod128 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128) +#define gfprod128_f2 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128_f2) +#define ggm_commit_rng_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_avx2) +#define ggm_commit_rng_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_ref) +#define ggm_commit_rng_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_avx2) +#define ggm_commit_rng_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_ref) +#define ggm_commit_rng_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_avx2) +#define ggm_commit_rng_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_avx2) +#define ggm_seed_rng_lr_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_ref) +#define ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2) +#define ggm_seed_rng_lr_ext_cat1_aes128_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_ref) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_avx2) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_avx2) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref) +#define grey_of SDITH_NAMESPACE_FOR_LIBOQS(grey_of) +#define hidden_leaves_indexes SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes) +#define hidden_leaves_indexes2 SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes2) +#define inv_grey_of SDITH_NAMESPACE_FOR_LIBOQS(inv_grey_of) +#define keygen_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_avx) +#define keygen_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_ref) +#define keygen_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_avx) +#define keygen_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_ref) +#define keygen_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_avx) +#define keygen_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_ref) +#define keygen_rng_next_u32_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_avx) +#define keygen_rng_next_u32_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_ref) +#define keygen_rng_next_u32_rijndael256_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_avx) +#define keygen_rng_next_u32_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_ref) +#define keygen_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_aes128_cat1_ref) +#define keygen_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_noop) +#define map_public_key SDITH_NAMESPACE_FOR_LIBOQS(map_public_key) +#define map_secret_key SDITH_NAMESPACE_FOR_LIBOQS(map_secret_key) +#define map_signature SDITH_NAMESPACE_FOR_LIBOQS(map_signature) +#define mask_eq_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_avx) +#define mask_eq_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_ref) +#define mask_lt_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_avx) +#define mask_lt_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_ref) +#define matrix_f2_times_vector_flambda_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_avx2) +#define matrix_f2_times_vector_flambda_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_ref) +#define matrix_rng_get_row_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_avx) +#define matrix_rng_get_row_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_ref) +#define matrix_rng_get_row_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_avx) +#define matrix_rng_get_row_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_ref) +#define matrix_rng_get_row_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_avx) +#define matrix_rng_get_row_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_ref) +#define matrix_rng_get_rows_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_avx) +#define matrix_rng_get_rows_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_ref) +#define matrix_rng_get_rows_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_avx) +#define matrix_rng_get_rows_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_ref) +#define matrix_rng_get_rows_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_avx) +#define matrix_rng_get_rows_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_ref) +#define matrix_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_avx) +#define matrix_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_ref) +#define matrix_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_avx) +#define matrix_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_ref) +#define matrix_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_avx) +#define matrix_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_ref) +#define matrix_rng_preprocess_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_avx) +#define matrix_rng_preprocess_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_ref) +#define matrix_rng_preprocess_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_avx) +#define matrix_rng_preprocess_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_ref) +#define matrix_rng_preprocess_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_avx) +#define matrix_rng_preprocess_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_ref) +#define matrix_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_aes128_cat1_ref) +#define matrix_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_noop) +#define matrix_rng_rows_times_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_avx) +#define matrix_rng_rows_times_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_ref) +#define matrix_rng_rows_times_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_avx) +#define matrix_rng_rows_times_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_ref) +#define matrix_rng_rows_times_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_avx) +#define matrix_rng_rows_times_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_ref) +#define matrix_vector_product_f2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_avx2) +#define matrix_vector_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_ref) +#define partition SDITH_NAMESPACE_FOR_LIBOQS(partition) +#define prepare_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(prepare_extseed_buf_cat1_aes128_ref) +#define proofow_grind_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_avx) +#define proofow_grind_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_ref) +#define proofow_grind_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_avx) +#define proofow_grind_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_ref) +#define proofow_grind_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_avx) +#define proofow_grind_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_ref) +#define proofow_grind_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1) +#define proofow_grind_w_shake_cat1_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1_4way) +#define proofow_grind_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3) +#define proofow_grind_w_shake_cat3_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3_4way) +#define proofow_grind_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5) +#define proofow_grind_w_shake_cat5_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5_4way) +#define proofow_init_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_avx) +#define proofow_init_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_ref) +#define proofow_init_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_avx) +#define proofow_init_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_ref) +#define proofow_init_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_avx) +#define proofow_init_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_ref) +#define proofow_init_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat1) +#define proofow_init_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat3) +#define proofow_init_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat5) +#define proofow_release_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_cipher_cat1_ref) +#define proofow_release_noop SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_noop) +#define proofow_verify_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_avx) +#define proofow_verify_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_ref) +#define proofow_verify_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_avx) +#define proofow_verify_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_ref) +#define proofow_verify_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_avx) +#define proofow_verify_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_ref) +#define proofow_verify_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat1) +#define proofow_verify_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat3) +#define proofow_verify_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat5) +#define prover_cst_check_unitary_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref) +#define prover_cst_check_unitary_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref_tmp_bytes) +#define prover_cst_mux_circuit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref) +#define prover_cst_mux_circuit_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref_tmp_bytes) +#define prover_cst_vole_check_zero_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_check_zero_gate_ct_ref) +#define prover_cst_vole_echelon_pow2_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_echelon_pow2_ct_ref) +#define prover_cst_vole_mul_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_mul_gate_ct_ref) +#define prover_cst_vole_packed_secret_input_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_packed_secret_input_ct_ref) +#define prover_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_ctrl_bytes) +#define prover_cst_vole_qary_mux_gate_ct_f2_prep SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_prep) +#define prover_cst_vole_qary_mux_gate_ct_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref) +#define prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes) +#define prover_cst_vole_qary_mux_gate_ct_naive SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_naive) +#define prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes) +#define prover_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_prepare_ctrl) +#define prover_cst_vole_xor_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_xor_gate_ct_ref) +#define prover_f2_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_std_to_cst_vole_ct_ref) +#define prover_f2_to_flambda_deg1_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_to_flambda_deg1_std_vole_ct_ref) +#define prover_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_deg1_to_degd_vole_ref) +#define prover_flambda_degd_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_degd_std_to_cst_vole_ct_ref) +#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref) +#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes) +#define prover_midsize_to_fullsize_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_midsize_to_fullsize_std_vole_ct_ref) +#define prover_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(prover_vole_consistency_check) +#define quickSort SDITH_NAMESPACE_FOR_LIBOQS(quickSort) +#define release_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(release_extseed_buf_cat1_aes128_ref) +#define rijndael256_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_avx2) +#define rijndael256_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_ref) +#define rijndael256_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_avx2) +#define rijndael256_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_ref) +#define rijndael256_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_avx2) +#define rijndael256_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_ref) +#define rijndael256_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_encrypt_1block_ref) +#define rijndael256_key_schedule_avx SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_avx) +#define rijndael256_key_schedule_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_ref) +#define rijndael256_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_avx2) +#define rijndael256_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_ref) +#define rijndael256_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_avx2) +#define rijndael256_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_ref) +#define rijndael256_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_avx2) +#define rijndael256_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_ref) +#define rijndael256_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_avx2) +#define rijndael256_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_ref) +#define rijndael256_keyexp_x1_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x1_enclast) +#define rijndael256_keyexp_x2_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x2_enclast) +#define rijndael256_keyexp_x3_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x3_enclast) +#define rijndael256_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x4_enclast) +#define rijndael256_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_proofow_grind_avx2) +#define rijndaelEncrypt SDITH_NAMESPACE_FOR_LIBOQS(rijndaelEncrypt) +#define rijndaelKeySetupEnc SDITH_NAMESPACE_FOR_LIBOQS(rijndaelKeySetupEnc) +#define rsd_encode_solution_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_encode_solution_ref) +#define rsd_expand_public_key_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_expand_public_key_ref) +#define rsd_generate_random_instance_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_ref) +#define rsd_generate_random_instance_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_tmp_bytes) +#define rsd_public_key_times_challenge_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_ref) +#define rsd_public_key_times_challenge_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_tmp_bytes) +#define sdith_keygen SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen) +#define sdith_keygen_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_entropy_bytes) +#define sdith_keygen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_tmp_bytes) +#define sdith_public_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_public_key_bytes) +#define sdith_secret_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_secret_key_bytes) +#define sdith_sign SDITH_NAMESPACE_FOR_LIBOQS(sdith_sign) +#define sdith_signature_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_bytes) +#define sdith_signature_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_entropy_bytes) +#define sdith_signature_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_tmp_bytes) +#define sdith_verify SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify) +#define sdith_verify_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify_tmp_bytes) +#define swap SDITH_NAMESPACE_FOR_LIBOQS(swap) +#define tmp_bytes_init SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_init) +#define tmp_bytes_reserve_call SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_call) +#define tmp_bytes_reserve_local_var SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var) +#define tmp_bytes_reserve_local_var_aligned SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var_aligned) +#define transpose_128_128_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_naive) +#define transpose_128_128_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_ref) +#define transpose_128_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_naive) +#define transpose_128_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_ref) +#define transpose_192_192_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_naive) +#define transpose_192_192_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_ref) +#define transpose_192_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_naive) +#define transpose_192_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_ref) +#define transpose_256_256_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_naive) +#define transpose_256_256_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_ref) +#define transpose_256_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_naive) +#define transpose_256_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_ref) +#define verifier_cst_check_unitary_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref) +#define verifier_cst_check_unitary_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref_tmp_bytes) +#define verifier_cst_mux_circuit_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref) +#define verifier_cst_mux_circuit_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref_tmp_bytes) +#define verifier_cst_vole_check_zero_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_check_zero_gate_ref) +#define verifier_cst_vole_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_echelon_pow2_ref) +#define verifier_cst_vole_mul_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_mul_gate_ref) +#define verifier_cst_vole_packed_secret_input_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_packed_secret_input_ref) +#define verifier_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_ctrl_bytes) +#define verifier_cst_vole_qary_mux_gate_prep SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_prep) +#define verifier_cst_vole_qary_mux_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref) +#define verifier_cst_vole_qary_mux_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref_tmp_bytes) +#define verifier_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_prepare_ctrl) +#define verifier_cst_vole_xor_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_xor_gate_ref) +#define verifier_f2_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_std_to_cst_vole_ref) +#define verifier_f2_to_flambda_deg1_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_to_flambda_deg1_std_vole_ref) +#define verifier_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_deg1_to_degd_vole_ref) +#define verifier_flambda_degd_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_degd_std_to_cst_vole_ref) +#define verifier_midsize_to_fullsize_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_midsize_to_fullsize_std_vole_ref) +#define verifier_open_midsize_grey_vole_from_seeds_bfs_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_ref) +#define verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes) +#define verifier_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(verifier_vole_consistency_check) +#define vole_consistency_check_matrix_ncols SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_ncols) +#define vole_consistency_check_matrix_nrows SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_nrows) +#define vole_parameters_init SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init) +#define vole_parameters_init_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_avx) +#define vole_parameters_init_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_ref) +#define vole_parameters_init_with_variant SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant) +#define vole_parameters_init_with_variant_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_avx) +#define vole_parameters_init_with_variant_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_ref) +#define vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2) +#define vole_rng_ext_cat1_aes128_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_ref) +#define vole_rng_ext_cat3_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_avx2) +#define vole_rng_ext_cat3_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_ref) +#define vole_rng_ext_cat5_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_avx2) +#define vole_rng_ext_cat5_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_ref) +#define xof_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake128) +#define xof_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake256) +#define xof_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake128) +#define xof_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake256) +#define xof_finalize_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake128) +#define xof_finalize_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake256) +#define xof_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake128) +#define xof_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake256) +#define xof_init_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake128) +#define xof_init_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake256) +#define xof_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake128) +#define xof_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake256) +#define xof_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake128) +#define xof_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake256) +#define xof_vector_ctx_bytes_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake128) +#define xof_vector_ctx_bytes_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake256) +#define xof_vector_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake128) +#define xof_vector_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake256) +#define xof_vector_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake128) +#define xof_vector_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake256) +#define xof_vector_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake128) +#define xof_vector_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake256) +#define xof_vector_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake128) +#define xof_vector_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake256) +#define xorto_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(xorto_kappabit_uint) + +#endif // APPLY_NAMESPACE + +#endif // SDITH_NAMESPACE_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_piop_circuits.h b/src/sig/sdith/sdith_sdith_common/sdith_piop_circuits.h new file mode 100644 index 0000000000..079db91fc7 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_piop_circuits.h @@ -0,0 +1,333 @@ +#ifndef SDITH_PIOP_CIRCUITS_H +#define SDITH_PIOP_CIRCUITS_H + +#include "vole_parameters.h" + +// vole circuit gates + +/** + * prover packed secret input gate (degree 1) + */ +EXPORT void prover_cst_vole_packed_secret_input_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + bitvec_t* out_pub, // [out] output publication (packed over f2) + fpoly_t* out_f, // [out] poly of degree 1 (cst term over f2) + const bitvec_t* in_value, // [in] secret bit values (packed over f2) + const bitvec_t* in_rvp_u, // [in] packed u terms + const flambda_t* in_rvp_v); // [in] packed v terms + +/** + * verifier packed secret input gate (degree 1) + */ +EXPORT void verifier_cst_vole_packed_secret_input_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + fpoly_t* out_q, // [out] vole evaluations + const bitvec_t* in_pub, // [in] publications (packed over f2) + const flambda_t* in_rvp_q, // [in] packed v terms + const flambda_t* delta2); // [in] verifier's point + +/** + * prover check-zero gate (degree d) + */ +EXPORT void prover_cst_vole_check_zero_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + fpoly_t* out_pub, // [out] output publication (degree d-1) + const fpoly_t* in_f, // [in] input (degree d) + const fpoly_t* in_rvp_f); // [in] rvp (degree d-1) + +/** + * verifier check-zero gate (degree d) + */ +EXPORT uint8_t verifier_cst_vole_check_zero_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + flambda_t* out_value, // [out] deduced output value + const fpoly_t* in_pub, // [in] publication (degree d-1) + const flambda_t* in_q, // [in] input (degree d) + const flambda_t* in_rvp_q, // [in] rvp (degree d-1) + const flambda_t* delta2); // [in] verifier's point + +/** + * prover xor gate + */ +EXPORT void prover_cst_vole_xor_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree); // [in] b + +/** + * verifier xor gate + */ +EXPORT void verifier_cst_vole_xor_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_f, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_f, uint64_t a_degree, // [in] a + const flambda_t* b_f, uint64_t b_degree, // [in] b + const flambda_t* delta2); // [in] verifier's point (unused) + +/** + * prover mul gate + */ +EXPORT void prover_cst_vole_mul_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree); // [in] b + +/** + * verifier mul gate + */ +EXPORT void verifier_cst_vole_mul_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_q, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_q, uint64_t a_degree, // [in] a + const flambda_t* b_q, uint64_t b_degree, // [in] b + const flambda_t* delta2); // [in] verifier's point (unused) + +/** + * prover echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void prover_cst_vole_echelon_pow2_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + fpoly_t* res_f, // [out] res of degree 1 + const fpoly_t* a_f); // [in] (arity) a of degree 1 + +/** + * verifier echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void verifier_cst_vole_echelon_pow2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* delta2); // [in] verifier's point (unused) + +/** @brief number of scratch bytes necessary for prover_cst_vole_qary_mux_gate_ct_ref */ +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree // common input degree +); + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + * KEPT ONLY FOR TEST PURPOSES: since c is binary, use prover_cst_vole_qary_mux_gate_ct_f2_ref + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_naive( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (arity) values of deg d + uint8_t* tmp_space); // scratch space + +/** @brief bytes of the prepared control of a qary-mux gate of the given arity */ +EXPORT uint64_t prover_cst_vole_qary_mux_ctrl_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity); // mux arity >= 1 + +/** + * Rewrite the control bits of a qary-mux gate as two "extended control" vectors, so that the + * gate becomes a pair of plain dot products over its inputs (see below): + * res = a[0] + sum_{i>0} c[i-1] (a[i]-a[0]) + * = sum_{i>=0} ctrl0[i] a[i] + X . sum_{i>=0} ctrl1[i] a[i] + * with, writing c[i-1] = c0[i] + c1[i].X for i > 0, + * ctrl0[i] = c0[i], ctrl1[i] = c1[i] (i > 0) + * ctrl0[0] = 1 + sum_{i>0} c0[i], ctrl1[0] = sum_{i>0} c1[i] (the "- a[0]" of every term) + * The ctrl0[i] stay in F2 (the c0[i] are bits), so the first dot product is a bit-select. + * The control is shared by every gate of a mux-circuit layer: prepare it once per layer. + * ctrl is the concatenation of ctrl0 (arity elements) and ctrl1 (arity elements). + */ +EXPORT void prover_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (2 x arity) extended control + const fpoly_t* c_f); // [in] (arity-1) control bits of deg. 1 + +/** + * prover qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const flambda_t* ctrl, // [in] (2 x arity) prepared control + const fpoly_t* a_f); // [in] (arity) values of deg d + +/** @brief number of scratch bytes necessary for prover_cst_vole_qary_mux_gate_ct_f2_ref */ +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity); // mux arity >= 1 + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) using product_f2 + * One-shot form: it derives the control into tmp_space on every call. A caller that applies + * several gates sharing the same c_f (a mux-circuit layer) should instead prepare the control + * once with prover_cst_vole_qary_mux_prepare_ctrl and call ..._f2_prep. + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (arity) values of deg d + uint8_t* tmp_space); // scratch space + +/** @brief bytes of the prepared control of a verifier qary-mux gate of the given arity */ +EXPORT uint64_t verifier_cst_vole_qary_mux_ctrl_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity); // mux arity >= 1 + +/** + * Rewrite the control values of a qary-mux gate as one "extended control" vector, so that the + * gate becomes a plain dot product over its inputs: + * res = a[0] + sum_{i>0} c[i-1] (a[i]-a[0]) = sum_{i>=0} ctrl[i] a[i] + * with ctrl[i] = c[i-1] for i > 0, and the i == 0 entry absorbing the "- a[0]" of every term: + * ctrl[0] = 1 + sum_{i>0} c[i-1]. + * This is the verifier counterpart of prover_cst_vole_qary_mux_prepare_ctrl: everything here is + * an evaluation at delta2, so there is a single vector (no degree-0/degree-1 split) and no F2 + * fast path (see the note below). + * The control is shared by every gate of a mux-circuit layer: prepare it once per layer. + */ +EXPORT void verifier_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (arity) extended control + const flambda_t* c_q, // [in] (arity-1) control values + const flambda_t* delta2); // [in] verifier's point (unused) + +/** + * verifier qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void verifier_cst_vole_qary_mux_gate_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* res_q, // [out] evaluation of the poly of degree d+1 + const flambda_t* ctrl, // [in] (arity) prepared control + const flambda_t* a_q, // [in] (arity) values of deg d + const flambda_t* delta2); // [in] verifier's point (unused) + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t verifier_cst_vole_qary_mux_gate_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree // common input degree +); + +/** + * verifier qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + * One-shot form: it derives the control into tmp_space on every call. A caller that applies + * several gates sharing the same c_q (a mux-circuit layer) should instead prepare the control + * once with verifier_cst_vole_qary_mux_prepare_ctrl and call ..._gate_prep. + */ +EXPORT void verifier_cst_vole_qary_mux_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + flambda_t* res_q, // [out] poly of degree d+1 + const flambda_t* c_q, // [in] (arity-1) control bits of deg. 1 + const flambda_t* a_q, // [in] (arity) values of deg d + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space); // scratch space + +/* + * There is no verifier-side F2-optimized mux gate. The prover's product_f2 fast + * path (prover_cst_vole_qary_mux_gate_ct_f2_ref) is only valid because the + * control bits are plaintext over F2 there (they are the constant term of u), so + * c*(a[i]-a[0]) reduces to a bit-select. On the verifier side the control bits + * are full-q values evaluated at delta2, so the mux gate must use full q-products + * throughout: the extended-control rewriting above applies to both sides, but the + * verifier's two dot products collapse into one and neither of them is over F2. + */ + +/** + * scratch bytes required by prover_cst_check_unitary_gate_ct_ref + */ +EXPORT uint64_t prover_cst_check_unitary_gate_ct_ref_tmp_bytes(const vole_parameters* vole_params); + +/** + * prover check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void prover_cst_check_unitary_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // arity >= 1 + fpoly_t* res_f, // [out] res of degree 2 + const fpoly_t* a_f, // [in] (arity) a of deg 1 + const flambda_t* coeff, // [in] challenge coeff + uint8_t* tmp_space); // scratch space + +/** + * scratch bytes required by verifier_cst_check_unitary_gate_ref + */ +EXPORT uint64_t verifier_cst_check_unitary_gate_ref_tmp_bytes(const vole_parameters* vole_params); + +/** + * verifier check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void verifier_cst_check_unitary_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* coeff, // [in] challenge coeff + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space); // scratch space + +/** + * scratch space required by prover_cst_mux_circuit_ct_ref + */ +EXPORT uint64_t prover_cst_mux_circuit_ct_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs); // scratch space + +/** + * prover mux-circuit: + */ +EXPORT void prover_cst_mux_circuit_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + fpoly_t* res_f, // [out] res of degree depth + const fpoly_t* c_f, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge coeff for unitary tests (unused if all muxes are binary) + uint8_t* tmp_space); // [tmp] scratch space + +/** + * scratch space required by verifier_cst_mux_circuit_ref + */ +EXPORT uint64_t verifier_cst_mux_circuit_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs); // scratch space + +/** + * verifier mux-circuit: + */ +EXPORT void verifier_cst_mux_circuit_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + flambda_t* res_q, // [out] res of degree depth + const flambda_t* c_q, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge coeff for unitary tests (unused if all muxes are binary) + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space); // [tmp] scratch space + +#endif // SDITH_PIOP_CIRCUITS_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_prng.c b/src/sig/sdith/sdith_sdith_common/sdith_prng.c new file mode 100644 index 0000000000..743a82e4a5 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_prng.c @@ -0,0 +1,1152 @@ +#include "sdith_prng.h" + +#include +#include + +#ifdef SDITH3_FOR_LIBOQS +#include "aes128_ctrle.h" +#include "aes_ansi_ref.h" +#include "fips202_glue.h" +#include "fips202x4_glue.h" +#else +#include "../aes/aes128_ctrle.h" +#include "../aes/aes_ansi_ref.h" +#include "../sha3/KeccakHash.h" +#include "../sha3/KeccakHashtimes4.h" +#endif + +#include "rijndael256_ctrle.h" +#include "sdith_prng_private.h" +#include "vole_private.h" + +#define STATIC_ASSERT(assert_name, condition) \ + uint8_t assert_name[(condition)?1:-1] + +// ggm seed rng, extended-seed variants (ref): consume the expanded round keys via +// encrypt_nblocks instead of scheduling the key inside oneshot. Same domain sep as +// the raw variant (node_idx, not node_idx<<1), so byte-identical to the raw output. +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_ref(void* lr_out256, const void* salt128, const void* extkey128, + uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + aesblk ctr = {.v64 = {0, 0}}; + CASSERT(domain_sep_check(salt128, node_idx, 2, theta), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt128, 16, node_idx); + aes128_ctrle_nocarry_2block_ref(lr_out256, extkey128, ctr.v64); +} +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_ref( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + uint8_t out512[64] = {}; + ctr256_t ctr256 = {.v8 = {}}; + CASSERT(domain_sep_check(salt192, node_idx, 2, theta), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt192, 24, node_idx); + rijndael256_ctrle_nocarry_2block_ref(out512, extkey, ctr256.v8); + // cat3 Enc = LSB_192(Rijndael-256): keep the low 24 bytes of each block + memcpy(lr_out384, out512, 24); + memcpy((uint8_t*)lr_out384 + 24, out512 + 32, 24); +} +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_ref( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + ctr256_t ctr256 = {.v8 = {}}; + CASSERT(domain_sep_check(salt256, node_idx, 2, theta), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt256, 32, node_idx); + rijndael256_ctrle_nocarry_2block_ref(lr_out512, extkey, ctr256.v8); +} + +// I8: naive x4 wrappers (ref). LR_STRIDE = 2 * lambda_bytes, EXT_STRIDE = one extended key. +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat1_aes128_x4_ref, // + ggm_seed_rng_lr_ext_cat1_aes128_ref, 32, 16 * 11) +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref, // + ggm_seed_rng_lr_ext_cat3_rijndael256_ref, 48, RIJNDAEL256_RK_BYTES) +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref, // + ggm_seed_rng_lr_ext_cat5_rijndael256_ref, 64, RIJNDAEL256_RK_BYTES) + +// --------------------------------------------------------------------------- +// Extended leaf seed: run the key schedule once, share it across commit + vole. +// For aes/rijndael the extended seed is the expanded round keys; the pad/schedule +// mirrors the raw commit/vole paths exactly, so outputs stay byte-identical. +// --------------------------------------------------------------------------- +EXPORT void extend_leaf_seed_cat1_aes128_ref(void* extended_seed_out, const void* seed128) { + // When building for liboqs, this allows allows key schedule reuse (see `aes_ansi_ref.h`) + // Requires the buffer to have been passed to aes128_prepare_rk_buffer first. + aes128_set_key_reuse_ref(extended_seed_out, seed128); +} +EXPORT void extend_leaf_seed_cat3_rijndael256_ref(void* extended_seed_out, const void* seed192) { + uint8_t key256[32] = {}; // k || 0^64 + memcpy(key256, seed192, 24); + rijndael256_key_schedule_x1_ref(extended_seed_out, key256); +} +EXPORT void extend_leaf_seed_cat5_rijndael256_ref(void* extended_seed_out, const void* seed256) { + rijndael256_key_schedule_x1_ref(extended_seed_out, seed256); +} + +// 4x leaf-seed expansion (ref): run the 1x schedule four times with shifted +// pointers. Seeds/outputs are packed at their natural stride, so the result is +// byte-identical to four separate 1x calls (KAT-preserving). +EXPORT void extend_leaf_seed_cat1_aes128_4x_ref(void* extended_seed_out, const void* seeds) { + uint8_t* out = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + for (int i = 0; i < 4; i++) extend_leaf_seed_cat1_aes128_ref(out + i * (16 * 11), s + i * 16); +} +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_ref(void* extended_seed_out, const void* seeds) { + uint8_t* out = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + for (int i = 0; i < 4; i++) extend_leaf_seed_cat3_rijndael256_ref(out + i * RIJNDAEL256_RK_BYTES, s + i * 24); +} +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_ref(void* extended_seed_out, const void* seeds) { + uint8_t* out = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + for (int i = 0; i < 4; i++) extend_leaf_seed_cat5_rijndael256_ref(out + i * RIJNDAEL256_RK_BYTES, s + i * 32); +} + +EXPORT void prepare_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes) { + aes128_prepare_rk_buffer(buf, nslots, slot_bytes); +} +EXPORT void release_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes) { + uint8_t* p = (uint8_t*) buf; + for (uint64_t i = 0; i < nslots; ++i) aes128_release_key(p + i * slot_bytes); +} +EXPORT void extseed_buf_noop(void* buf, uint64_t nslots, uint64_t slot_bytes) { + (void) buf; (void) nslots; (void) slot_bytes; // rijndael256: schedule is in-place +} + +EXPORT uint64_t extended_node_seed_bytes_cat1_aes128(void) { return 16 * 11; } +EXPORT uint64_t extended_node_seed_bytes_cat3_rijndael256(void) { return RIJNDAEL256_RK_BYTES; } +EXPORT uint64_t extended_node_seed_bytes_cat5_rijndael256(void) { return RIJNDAEL256_RK_BYTES; } + +// commit rng, extended-seed cores: take the expanded round keys and encrypt. +EXPORT void ggm_commit_rng_ext_cat1_aes128_ref(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx) { + aesblk ctr = {.v64 = {0, 0}}; + CASSERT(domain_sep_check(salt128, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt128, 16, node_idx << 1); + aes128_ctrle_nocarry_2block_ref(output256, extkey128, ctr.v64); +} +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_ref( // + void* output384, const void* salt192, const void* extkey, uint64_t node_idx) { + uint8_t output512[64] = {}; // pad with zeroes + ctr256_t ctr256 = {.v8 = {}}; // pad with zeroes + CASSERT(domain_sep_check(salt192, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt192, 24, node_idx << 1); + rijndael256_ctrle_nocarry_2block_ref(output512, extkey, ctr256.v8); + // cat3 Enc = LSB_192(Rijndael-256): keep the low 24 bytes of each block + memcpy(output384, output512, 24); + memcpy((uint8_t*)output384 + 24, output512 + 32, 24); +} +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_ref( // + void* output512, const void* salt256, const void* extkey, uint64_t node_idx) { + ctr256_t ctr256 = {.v8 = {}}; + CASSERT(domain_sep_check(salt256, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt256, 32, node_idx << 1); + rijndael256_ctrle_nocarry_2block_ref(output512, extkey, ctr256.v8); +} + +// vole rng, extended-seed cores: adopt the precomputed round keys, no schedule. +// The counter starts at the salt tweaked by the repetition index (see +// VOLE_RNG_REPET_SHIFT), and the domain_sep_check asserts that the last block of +// the stream still fits in the tweak field. +EXPORT void vole_rng_ext_cat1_aes128_ctrle_ref(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx) { + ctr128_t ctr = {}; + CASSERT((out_bytes & 15) == 0, "bug! out_bytes must be multiple of 16"); + CASSERT(domain_sep_check(salt128, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 4, GGM_TWEAK_BITS), + "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt128, 16, repet_idx << VOLE_RNG_REPET_SHIFT); + aes128_ctrle_nocarry_nblocks_ref(out, extseed, ctr.v64, out_bytes >> 4); +} +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx) { + ctr256_align32_t ctr = {}; + CASSERT((out_bytes & 31) == 0, "bug! out_bytes must be multiple of 32"); + CASSERT(domain_sep_check(salt192, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 5, GGM_TWEAK_BITS), + "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt192, 24, repet_idx << VOLE_RNG_REPET_SHIFT); + rijndael256_ctrle_nocarry_nblocks_ref(out, extseed, ctr.v64, out_bytes >> 5); +} +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx) { + ctr256_align32_t ctr = {}; + CASSERT((out_bytes & 31) == 0, "bug! out_bytes must be multiple of 32"); + CASSERT(domain_sep_check(salt256, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 5, GGM_TWEAK_BITS), + "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt256, 32, repet_idx << VOLE_RNG_REPET_SHIFT); + rijndael256_ctrle_nocarry_nblocks_ref(out, extseed, ctr.v64, out_bytes >> 5); +} + +EXPORT void xof_init_shake128(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE128(inst); +} +EXPORT void xof_init_shake256(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE256(inst); +} + +EXPORT void xof_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashUpdate(inst, in, in_bytes << 3); +} +EXPORT void xof_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashUpdate(inst, in, in_bytes << 3); +} + +EXPORT void xof_finalize_shake128(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); +} +EXPORT void xof_finalize_shake256(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); +} + +EXPORT void xof_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} +EXPORT void xof_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} + +// shortcut combo +EXPORT void xof_init_and_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE128(inst); + Keccak_HashUpdate(inst, in, in_bytes << 3); +} +EXPORT void xof_init_and_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE256(inst); + Keccak_HashUpdate(inst, in, in_bytes << 3); +} + +EXPORT void xof_finalize_and_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} +EXPORT void xof_finalize_and_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} + +EXPORT void xof_ctx_release_shake128(xof_ctx* xof) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + #else + OQS_SHA3_shake128_inc_ctx_release(&xof->shake128_state); + #endif +} +EXPORT void xof_ctx_release_shake256(xof_ctx* xof) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + #else + OQS_SHA3_shake256_inc_ctx_release(&xof->shake256_state); + #endif +} + +// vector shake function + +static const uint64_t SINGLE_XOF_STRIDE = (sizeof(KeccakWidth1600_SpongeInstance) + 31) & UINT64_C(-32); +static const uint64_t BATCH_XOF_STRIDE = (sizeof(KeccakWidth1600times4_SpongeInstance) + 31) & UINT64_C(-32); +static const uint64_t XOF_RATE_SHAKE128 = 1344; +static const uint64_t XOF_RATE_SHAKE256 = 1088; +static const uint64_t XOF_CAPACITY_SHAKE128 = 256; +static const uint64_t XOF_CAPACITY_SHAKE256 = 512; +#define BATCH_XOF(base, idx) ((KeccakWidth1600times4_SpongeInstance*)((uint8_t*)(base) + (idx) * BATCH_XOF_STRIDE)) +#define SINGLE_XOF(base, idx) ((KeccakWidth1600_SpongeInstance*)((uint8_t*)(base) + (idx) * SINGLE_XOF_STRIDE)) + + +//typedef struct xof_vector_ctx_t xof_vector_ctx; + +//typedef uint64_t XOF_VECTOR_CTX_BYTES_F(uint64_t num_xofs); +EXPORT uint64_t xof_vector_ctx_bytes_shake128(uint64_t num_xofs) { + // use (num_xofs / 4) x batched shake and (num_xofs % 4) single ones + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + return num_batches * BATCH_XOF_STRIDE + num_remainder * SINGLE_XOF_STRIDE; +} +EXPORT uint64_t xof_vector_ctx_bytes_shake256(uint64_t num_xofs) { + return xof_vector_ctx_bytes_shake128(num_xofs); // same +} + +//typedef void XOF_VECTOR_INIT_AND_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); +EXPORT void xof_vector_init_and_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + const unsigned char* prefix_ptrs[4] = { + (const unsigned char*)data, (const unsigned char*)data, + (const unsigned char*)data, (const unsigned char*)data}; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeInitialize(inst, XOF_RATE_SHAKE128, XOF_CAPACITY_SHAKE128); + KeccakWidth1600times4_SpongeAbsorb(inst, prefix_ptrs, data_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeInitialize(inst, XOF_RATE_SHAKE128, XOF_CAPACITY_SHAKE128); + KeccakWidth1600_SpongeAbsorb(inst, data, data_bytes); + } +} + +EXPORT void xof_vector_init_and_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + const unsigned char* prefix_ptrs[4] = { + (const unsigned char*)data, (const unsigned char*)data, + (const unsigned char*)data, (const unsigned char*)data}; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeInitialize(inst, XOF_RATE_SHAKE256, XOF_CAPACITY_SHAKE256); + KeccakWidth1600times4_SpongeAbsorb(inst, prefix_ptrs, data_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeInitialize(inst, XOF_RATE_SHAKE256, XOF_CAPACITY_SHAKE256); + KeccakWidth1600_SpongeAbsorb(inst, data, data_bytes); + } +} + +//typedef void XOF_VECTOR_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); +EXPORT void xof_vector_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + unsigned char** dbase = data + num_batches * 4; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeAbsorb(inst, (const unsigned char **)(data + 4 * b), data_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeAbsorb(inst, dbase[r], data_bytes); + } +} +EXPORT void xof_vector_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes) { + xof_vector_seed_shake128(xof, num_xofs, data, data_bytes); // same +} + +//typedef void XOF_VECTOR_FINALIZE_AND_OUTPUT_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); +EXPORT void xof_vector_finalize_and_output_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + unsigned char** dbase = out_hashes + num_batches * 4; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeAbsorbLastFewBits(inst, 0x1F); + KeccakWidth1600times4_SpongeSqueeze(inst, out_hashes + b * 4, hash_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeAbsorbLastFewBits(inst, 0x1F); + KeccakWidth1600_SpongeSqueeze(inst, dbase[r], hash_bytes); + } +} +EXPORT void xof_vector_finalize_and_output_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes) { + xof_vector_finalize_and_output_shake128(xof, num_xofs, out_hashes, hash_bytes); // same +} + +EXPORT void xof_vector_ctx_release_shake128(xof_vector_ctx* xof, uint64_t num_xofs) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + (void)num_xofs; // no-op + #else + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + OQS_SHA3_shake128_x4_inc_ctx_release(&inst->shake128_state); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + OQS_SHA3_shake128_inc_ctx_release(&inst->shake128_state); + } + #endif +} +EXPORT void xof_vector_ctx_release_shake256(xof_vector_ctx* xof, uint64_t num_xofs) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + (void)num_xofs; // no-op + #else + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + OQS_SHA3_shake256_x4_inc_ctx_release(&inst->shake256_state); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + OQS_SHA3_shake256_inc_ctx_release(&inst->shake256_state); + } + #endif +} + +// cipher-based proof of work + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat1() { return sizeof(struct proofow_state128_t); } + +EXPORT void proofow_init_cipher_cat1_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 32; + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake128(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake128(&xof); + xof_output_shake128(&xof, s->p, 64); // covers p0,p1,k0,k1 + xof_ctx_release_shake128(&xof); + s->p[0].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + aes128_key_schedule_x2_ref(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + static const uint64_t H_PIOP_BYTES = 32; // CAT1 + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + while (ctr < CTR_MAX) { + aes128_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + aes128_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) == 0) { + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake128(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake128(&xof); + *ctr_in_out = ctr; + return 1; + } + ++ctr; + ++s->p[0].v64[0]; + ++s->p[1].v64[0]; + } + return 0; +} + +EXPORT int proofow_verify_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 32; // CAT1 + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + aes128_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + aes128_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake128(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake128(&xof); + return 1; +} + +EXPORT void proofow_release_cipher_cat1_ref(proofow_ctx_t* proofow_state) { + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + aes128_release_key(s->rk[0]); + aes128_release_key(s->rk[1]); +} + +// Shared by every proof-of-work variant that holds no schedule of its own: the +// cat3/cat5 cipher ones expand rijndael256 in place, the avx cat1 one expands +// aes128 in place, and the shake ones run no cipher at all. +EXPORT void proofow_release_noop(proofow_ctx_t* proofow_state) { (void)proofow_state; } + +// cipher-based proof of work (cat5: rijndael256 block cipher + shake256 xof) + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat5() { return sizeof(struct proofow_state256_t); } + +EXPORT void proofow_init_cipher_cat5_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 64; // CAT5: 2*lambda = 512 bits + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) + xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + rijndael256_key_schedule_x2_ref(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + static const uint64_t H_PIOP_BYTES = 64; // CAT5 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + while (ctr < CTR_MAX) { + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) == 0) { + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } + ++ctr; + ++s->p[0].v64[0]; + ++s->p[1].v64[0]; + } + return 0; +} + +EXPORT int proofow_verify_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 64; // CAT5 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + return 1; +} + +// cipher-based proof of work (cat3: rijndael256 block cipher + shake256 xof). +// Identical to cat5 except h_piop is 2*lambda = 384 bits = 48 bytes, so the +// cat5 proofow_state256_t workspace (h_piop[64]) is reused as-is. + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat3() { return sizeof(struct proofow_state256_t); } + +EXPORT void proofow_init_cipher_cat3_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 48; // CAT3: 2*lambda = 384 bits + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) + xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + rijndael256_key_schedule_x2_ref(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + static const uint64_t H_PIOP_BYTES = 48; // CAT3 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + while (ctr < CTR_MAX) { + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) == 0) { + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } + ++ctr; + ++s->p[0].v64[0]; + ++s->p[1].v64[0]; + } + return 0; +} + +EXPORT int proofow_verify_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 48; // CAT3 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + return 1; +} + +/// shake-based proof of work + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat1() { return sizeof(struct proofow_shake_cat1_t); } + +EXPORT void proofow_init_shake_cat1( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + struct proofow_shake_cat1_t* const s = (struct proofow_shake_cat1_t*)proofow_state; + memset(s->delta0_and_vgrind, 0, sizeof(s->delta0_and_vgrind)); + memcpy(s->h_piop, h_piop, (lambda * 2) >> 3); + s->w = proofow_w; + s->kappa_tau = kappa * tau; + s->delta0_and_vgrind_bytes = (s->kappa_tau + proofow_w + 7) >> 3; + s->delta0_out_bytes = (s->kappa_tau + 7) >> 3; +} + +EXPORT int proofow_grind_w_shake_cat1( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +) { + static const uint64_t H_PIOP_BYTES = 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + struct proofow_shake_cat1_t* const s = (struct proofow_shake_cat1_t*)proofow_state; + xof_ctx ctx __attribute((aligned(16))); + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake128(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&ctx, &ctr, 4); + xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake128(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; + } + } + // no good counter: pow has failed + return 0; +} + +EXPORT int proofow_verify_w_shake_cat1( // + proofow_ctx_t* proofow_state, // + void* delta0_out, // + const uint64_t ctr_value // +) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t H_PIOP_BYTES = 32; + struct proofow_shake_cat1_t* const s = (struct proofow_shake_cat1_t*)proofow_state; + const uint64_t ctr = ctr_value; + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake128(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&ctx, &ctr, 4); + xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake128(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; +} + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat3() { return sizeof(struct proofow_shake_cat3_t); } + +EXPORT void proofow_init_shake_cat3( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + struct proofow_shake_cat3_t* const s = (struct proofow_shake_cat3_t*)proofow_state; + memset(s->delta0_and_vgrind, 0, sizeof(s->delta0_and_vgrind)); + memcpy(s->h_piop, h_piop, (lambda * 2) >> 3); + s->w = proofow_w; + s->kappa_tau = kappa * tau; + s->delta0_and_vgrind_bytes = (s->kappa_tau + proofow_w + 7) >> 3; + s->delta0_out_bytes = (s->kappa_tau + 7) >> 3; +} + +EXPORT int proofow_grind_w_shake_cat3( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +) { + static const uint64_t H_PIOP_BYTES = 48; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + struct proofow_shake_cat3_t* const s = (struct proofow_shake_cat3_t*)proofow_state; + xof_ctx ctx __attribute((aligned(16))); + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; + } + } + // no good counter: pow has failed + return 0; +} + +EXPORT int proofow_verify_w_shake_cat3( // + proofow_ctx_t* proofow_state, // + void* delta0_out, // + const uint64_t ctr_value // +) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t H_PIOP_BYTES = 48; + struct proofow_shake_cat3_t* const s = (struct proofow_shake_cat3_t*)proofow_state; + const uint64_t ctr = ctr_value; + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; +} + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat5() { return sizeof(struct proofow_shake_cat5_t); } + +EXPORT void proofow_init_shake_cat5( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + struct proofow_shake_cat5_t* const s = (struct proofow_shake_cat5_t*)proofow_state; + memset(s->delta0_and_vgrind, 0, sizeof(s->delta0_and_vgrind)); + memcpy(s->h_piop, h_piop, (lambda * 2) >> 3); + s->w = proofow_w; + s->kappa_tau = kappa * tau; + s->delta0_and_vgrind_bytes = (s->kappa_tau + proofow_w + 7) >> 3; + s->delta0_out_bytes = (s->kappa_tau + 7) >> 3; +} + +EXPORT int proofow_grind_w_shake_cat5( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +) { + static const uint64_t H_PIOP_BYTES = 64; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + struct proofow_shake_cat5_t* const s = (struct proofow_shake_cat5_t*)proofow_state; + xof_ctx ctx __attribute((aligned(16))); + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; + } + } + // no good counter: pow has failed + return 0; +} + +EXPORT int proofow_verify_w_shake_cat5( // + proofow_ctx_t* proofow_state, // + void* delta0_out, // + const uint64_t ctr_value // +) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t H_PIOP_BYTES = 64; + struct proofow_shake_cat5_t* const s = (struct proofow_shake_cat5_t*)proofow_state; + const uint64_t ctr = ctr_value; + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) { + xof_ctx_release_shake256(&ctx); + return 0; + } + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + xof_ctx_release_shake256(&ctx); + return 1; +} + +// 4-way batched SHAKE proof-of-work grind (AVX2 KeccakP-1600-times4). Drives 4 +// consecutive counters through one batched permutation instead of 4 scalar ones. The <4 tail near CTR_MAX falls back to the scalar path. +#define PROOFOW_GRIND_SHAKE_4WAY(CAT, SHAKE, HPB) \ + EXPORT int proofow_grind_w_shake_##CAT##_4way(proofow_ctx_t* proofow_state, \ + bitvec_t* delta0_out, uint64_t* ctr_in_out) {\ + static const uint64_t H_PIOP_BYTES = HPB; \ + static const uint64_t CTR_MAX = UINT64_C(1) << 32; \ + struct proofow_shake_##CAT##_t* const s = (struct proofow_shake_##CAT##_t*)proofow_state;\ + uint8_t xvbuf[sizeof(KeccakWidth1600times4_SpongeInstance) + 32] __attribute((aligned(64)));\ + xof_vector_ctx* const xv = (xof_vector_ctx*)xvbuf; \ + uint8_t buf[4][sizeof(s->delta0_and_vgrind)]; \ + uint32_t ctr32[4]; \ + uint8_t *ctr_ptrs[4], *out_ptrs[4]; \ + for (int j = 0; j < 4; j++) { \ + ctr_ptrs[j] = (uint8_t*)&ctr32[j]; \ + out_ptrs[j] = buf[j]; \ + } \ + uint64_t ctr = *ctr_in_out; \ + for (; ctr + 4 <= CTR_MAX; ctr += 4) { \ + for (int j = 0; j < 4; j++) ctr32[j] = (uint32_t)(ctr + j); \ + xof_vector_init_and_seed_##SHAKE(xv, 4, s->h_piop, H_PIOP_BYTES); \ + xof_vector_seed_##SHAKE(xv, 4, ctr_ptrs, 4); \ + xof_vector_finalize_and_output_##SHAKE(xv, 4, out_ptrs, s->delta0_and_vgrind_bytes); \ + for (int j = 0; j < 4; j++) \ + if (extract_kappabit_uint(s->w, s->kappa_tau, buf[j]) == 0) { \ + *ctr_in_out = ctr + j; \ + memcpy(delta0_out, buf[j], s->delta0_out_bytes); \ + xof_vector_ctx_release_##SHAKE(xv, 4); \ + return 1; \ + } \ + xof_vector_ctx_release_##SHAKE(xv, 4); \ + } \ + for (; ctr < CTR_MAX; ctr++) { /* <4 tail, byte-identical scalar path */ \ + xof_ctx c __attribute((aligned(16))); \ + xof_init_and_seed_##SHAKE(&c, s->h_piop, H_PIOP_BYTES); \ + xof_seed_##SHAKE(&c, &ctr, 4); \ + xof_finalize_and_output_##SHAKE(&c, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); \ + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { \ + *ctr_in_out = ctr; \ + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); \ + xof_ctx_release_##SHAKE(&c); \ + return 1; \ + } \ + xof_ctx_release_##SHAKE(&c); \ + } \ + return 0; \ + } +PROOFOW_GRIND_SHAKE_4WAY(cat1, shake128, 32) +PROOFOW_GRIND_SHAKE_4WAY(cat3, shake256, 48) +PROOFOW_GRIND_SHAKE_4WAY(cat5, shake256, 64) + +// set_2_b_minus_one (the last-block mask builder) is shared with the avx path, +// so it lives in sdith_prng_private.h. + +static inline void apply_last_blk_mask(uint64_t* res, const uint64_t* mask, uint64_t res_size) { + for (uint64_t i=0; irk, seed); + r->blocks_per_row = ((row_bit_size + 127) >> 7); // aes128 uses 128-bit block sizes + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 2, row_bit_size & 127); +} + +EXPORT void matrix_rng_init_rijndael256_cat3_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*) rng; + // the actual rijndael key is padded with zeroes + uint64_t key256[4] = {}; // ZERO + memcpy(key256, seed, 24); + rijndael256_key_schedule_x1_ref(r->rk, key256); + // we are using the full 256-bit rijndael block size, even if lambda is smaller. + r->blocks_per_row = ((row_bit_size + 255) >> 8); + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); +} + +EXPORT void matrix_rng_init_rijndael256_cat5_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*) rng; + rijndael256_key_schedule_x1_ref(r->rk, seed); + r->blocks_per_row = ((row_bit_size + 255) >> 8); // rijndael256 uses 256-bit block sizes + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); +} + +EXPORT void matrix_rng_release_aes128_cat1_ref(matrix_rng_t* rng) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + aes128_release_key(r->rk); +} + +// cat3/cat5 (and the avx cat1 path) expand their schedule inside the context. +EXPORT void matrix_rng_release_noop(matrix_rng_t* rng) { (void)rng; } + +EXPORT void matrix_rng_get_row_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); + ctr128_t* const cout = (ctr128_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr128_t ctr = {}; + ctr.v64[0] = row_index * bpr; + aes128_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask(cout[bpr - 1].v64, r->last_blk_mask.v64, 2); +} + +EXPORT void matrix_rng_get_row_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-bytes aligned"); + // cat3 is providing the same full rijndael256-ctr as cat 5 + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = row_index * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask(cout[bpr - 1].v64, r->last_blk_mask.v64, 4); +} + +EXPORT void matrix_rng_get_row_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = row_index * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask(cout[bpr - 1].v64, r->last_blk_mask.v64, 4); +} + +// Pre-processed challenge (see MATRIX_RNG_PREPROCESS_CHALL). With k = lambda/64, +// prep_chall[j] = chall[j / k] * X^(64 * (j % k)), +// so that = sum_j h_j * prep_chall[j] over the 64-bit words h_j of +// the row. The loop itself is preprocess_chall_generic in sdith_prng_private.h, +// shared with the avx path: only the field product differs, and both orderings +// of it give the very same table. + +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_aes128_cat1_t* r = (const struct matrix_rng_aes128_cat1_t*) rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), + 16, 2, gf128_flambda_product_ref); +} + +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_rijndael256_cat3_t* r = (const struct matrix_rng_rijndael256_cat3_t*) rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), + 24, 3, gf192_flambda_product_ref); +} + +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_rijndael256_cat5_t* r = (const struct matrix_rng_rijndael256_cat5_t*) rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), + 32, 4, gf256_flambda_product_ref); +} + +// Reference row-times-challenge (see MATRIX_RNG_ROWS_TIMES_CHALL). This is the +// definition transcribed literally: draw the row, split it into 64-bit words h_j, +// and accumulate sum_j h_j * prep_chall[j] with the ordinary field product and +// sum. Each h_j is a field element whose low 64 bits are the word and whose other +// bits are zero. No attempt is made to be quick: it is written to stay readable +// so it can serve as the oracle for the avx kernels, which are what the x86 +// build runs in production. +// +// Where there are no avx kernels this is the production path, and then the word +// decomposition does more work than it needs to. Writing k = lambda/64, the +// definition of the pre-processed challenge gives prep_chall[k*i] = chall[i] * +// X^0 = chall[i], so the sum collapses back to the plain limb dot product +// = sum_i row_limb[i] * prep_chall[k*i], +// running over the ceil(row_bits/lambda) limbs instead of the ceil(row_bits/64) +// words: k times fewer field products (k = 2, 3, 4 for cat1/cat3/cat5), and no +// change to the pre-processed challenge, so the two forms stay interchangeable. +// Reading whole limbs is in bounds because compute_rsd_codim_slice guarantees +// the row is wide enough to hold rsd_codim_limbs of them. Swap the inner loop +// for that form if a portable build ever needs the speed. +// +// The row is at most MATRIX_RNG_REF_MAX_ROW_BYTES; 2kB is a 16384-bit row, far +// above any rsd_codim. The buffer is 32-byte aligned as get_row requires. +#define MATRIX_RNG_REF_MAX_ROW_BYTES 2048 + +static void rows_times_chall_ref_generic( // + const matrix_rng_t* rng, flambda_t* dest, const flambda_t* prep_chall, // + const uint64_t first_row, const uint64_t nrows, // + const uint64_t row_bit_size, const uint64_t row_bytes, const uint64_t lambda_bytes, // + MATRIX_RNG_GET_ROW* get_row, FLAMBDA_PRODUCT_F* product, FLAMBDA_SUM_F* sum) { + CREQUIRE(row_bytes <= MATRIX_RNG_REF_MAX_ROW_BYTES, "row too wide (%ld bytes)", (long) row_bytes); + const uint64_t nwords = matrix_rng_prep_chall_nelems(row_bit_size); + const uint8_t* const pc = (const uint8_t*) prep_chall; + uint8_t* out = (uint8_t*) dest; + uint8_t row[MATRIX_RNG_REF_MAX_ROW_BYTES] __attribute__((aligned(32))); + for (uint64_t i = 0; i < nrows; ++i) { + get_row(rng, row, first_row + i); + flambda_max_t acc = {0, 0, 0, 0}; + for (uint64_t j = 0; j < nwords; ++j) { + // h_j: the j-th 64-bit word of the row, zero-extended to a field element + flambda_max_t h = {0, 0, 0, 0}; + memcpy(h, row + 8 * j, 8); + flambda_max_t term; + product(term, h, pc + j * lambda_bytes); + sum(acc, acc, term); + } + memcpy(out, acc, lambda_bytes); + out += lambda_bytes; + } +} + +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_aes128_cat1_t* r = (const struct matrix_rng_aes128_cat1_t*) rng; + rows_times_chall_ref_generic(rng, dest, prep_chall, first_row, nrows, // + r->row_bit_size, r->blocks_per_row * 16, 16, // + matrix_rng_get_row_aes128_cat1_ref, gf128_flambda_product_ref, + gf128_flambda_sum_ref); +} + +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_rijndael256_cat3_t* r = (const struct matrix_rng_rijndael256_cat3_t*) rng; + rows_times_chall_ref_generic(rng, dest, prep_chall, first_row, nrows, // + r->row_bit_size, r->blocks_per_row * 32, 24, // + matrix_rng_get_row_rijndael256_cat3_ref, gf192_flambda_product_ref, + gf192_flambda_sum_ref); +} + +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_rijndael256_cat5_t* r = (const struct matrix_rng_rijndael256_cat5_t*) rng; + rows_times_chall_ref_generic(rng, dest, prep_chall, first_row, nrows, // + r->row_bit_size, r->blocks_per_row * 32, 32, // + matrix_rng_get_row_rijndael256_cat5_ref, gf256_flambda_product_ref, + gf256_flambda_sum_ref); +} + +// Batched row generation. Rows first_row..first_row+nrows-1 occupy the counter +// range [first_row*bpr, (first_row+nrows)*bpr), which is contiguous, so the whole +// batch is one CTR call; only the per-row last-block masking is left to do. + +EXPORT void matrix_rng_get_rows_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); + ctr128_t* const cout = (ctr128_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr128_t ctr = {}; + ctr.v64[0] = first_row * bpr; + aes128_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask(cout[i * bpr + bpr - 1].v64, r->last_blk_mask.v64, 2); + } +} + +EXPORT void matrix_rng_get_rows_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-bytes aligned"); + // cat3 is providing the same full rijndael256-ctr as cat 5 + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = first_row * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask(cout[i * bpr + bpr - 1].v64, r->last_blk_mask.v64, 4); + } +} + +EXPORT void matrix_rng_get_rows_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = first_row * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask(cout[i * bpr + bpr - 1].v64, r->last_blk_mask.v64, 4); + } +} + +// --- keygen prng (reference) ------------------------------------------------ +// The plain CTR keystream of the secret-key seed (see keygen_rng_ctx). Only the +// key differs between the three categories; the draw loop is the shared +// DEFINE_KEYGEN_RNG_NEXT_U32 body. + +EXPORT void keygen_rng_init_aes128_cat1_ref(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_aes128_cat1_t* s = (struct keygen_rng_aes128_cat1_t*) rng; + aes128_key_schedule_x1_ref(s->rk, sk_seed); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_init_rijndael256_cat3_ref(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_rijndael256_t* s = (struct keygen_rng_rijndael256_t*) rng; + // the 192-bit seed is padded with 64 zero bits in the MSB to make a rijndael256 key + uint64_t key256[4] = {}; // ZERO + memcpy(key256, sk_seed, 24); + rijndael256_key_schedule_x1_ref(s->rk, key256); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_init_rijndael256_cat5_ref(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_rijndael256_t* s = (struct keygen_rng_rijndael256_t*) rng; + rijndael256_key_schedule_x1_ref(s->rk, sk_seed); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_release_aes128_cat1_ref(keygen_rng_ctx* rng) { + struct keygen_rng_aes128_cat1_t* s = (struct keygen_rng_aes128_cat1_t*) rng; + aes128_release_key(s->rk); +} + +// cat3/cat5 (and the avx cat1 path) expand their schedule inside the context. +EXPORT void keygen_rng_release_noop(keygen_rng_ctx* rng) { (void)rng; } + +DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_aes128_cat1_ref, keygen_rng_aes128_cat1_t, ctr128_t, + aes128_ctrle_nocarry_nblocks_ref) +DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_rijndael256_ref, keygen_rng_rijndael256_t, ctr256_t, + rijndael256_ctrle_nocarry_nblocks_ref) diff --git a/src/sig/sdith/sdith_sdith_common/sdith_prng.h b/src/sig/sdith/sdith_sdith_common/sdith_prng.h new file mode 100644 index 0000000000..e6bf87e415 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_prng.h @@ -0,0 +1,663 @@ +#ifndef AQ_VOLE_IMPL_RNG_H +#define AQ_VOLE_IMPL_RNG_H + +#include "commons.h" + +#ifdef SDITH3_FOR_LIBOQS +#include +#endif + +/** + * Domain separation of the GGM tree and vole PRNGs. + * + * compute_tweaked_salts derives, from the lambda-bit global salt, one masked + * salt per PRNG family: the two most significant bits carry the family prefix + * and the GGM_TWEAK_BITS least significant bits are cleared. Each PRNG call ORs + * its own tweak into that cleared field and uses the result as the lambda-bit + * initial CTR plaintext: + * - GGM seed / commit rng: the tweak is the node index (times 2, since each + * call consumes two consecutive counters), + * - vole rng: the tweak is repet_idx << VOLE_RNG_REPET_SHIFT, so the block + * counter of the call occupies the low VOLE_RNG_REPET_SHIFT bits. + */ +#define GGM_TWEAK_BITS 24 +#define VOLE_RNG_REPET_SHIFT 16 + +/** proof of work: state init */ +typedef struct proofow_ctx_t proofow_ctx_t; +typedef uint64_t BYTES_OF_PROOFOW_CTX_F(); +typedef void PROOFOW_INIT_F( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +typedef int PROOFOW_GRIND_W_F( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +); +typedef int PROOFOW_VERIFY_W_F( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + const uint64_t ctr_value // +); +/** proof of work: release whatever the init took hold of */ +typedef void PROOFOW_RELEASE_F(proofow_ctx_t* proofow_state); +// Only the cat1 cipher variant owns anything: its two aes128 schedules are heap +// contexts on the liboqs backend (see aes_ansi_ref.h). The cat3/cat5 cipher +// variants expand rijndael256 in place, the avx cat1 one expands aes128 in +// place, and the shake variants hold no cipher state at all, so all of those +// take proofow_release_noop. +EXPORT void proofow_release_cipher_cat1_ref(proofow_ctx_t* proofow_state); +EXPORT void proofow_release_noop(proofow_ctx_t* proofow_state); +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat1(); +EXPORT void proofow_init_cipher_cat1_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT void proofow_init_cipher_cat1_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); +EXPORT int proofow_verify_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat5(); +EXPORT void proofow_init_cipher_cat5_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); +EXPORT void proofow_init_cipher_cat5_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); + +// cipher-based proof of work (cat3: rijndael256 block cipher + shake256 xof, h_piop = 48 bytes) + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat3(); +EXPORT void proofow_init_cipher_cat3_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); +EXPORT void proofow_init_cipher_cat3_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); + +// shake-based proof of work + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat1(); +EXPORT void proofow_init_shake_cat1( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_shake_cat1(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_shake_cat1_4way(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_shake_cat1(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr_value); + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat3(); +EXPORT void proofow_init_shake_cat3( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_shake_cat3(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_shake_cat3_4way(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_shake_cat3(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr_value); + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat5(); +EXPORT void proofow_init_shake_cat5( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_shake_cat5(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_shake_cat5_4way(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_shake_cat5(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr_value); + + +// ggm seed rng, extended-seed variants: same as ggm_seed_rng_lr_* but the +// node_seed points at the expanded round keys (skips the key schedule). Output +// is byte-identical to the raw variant fed the matching extend_leaf_seed output. +typedef void GGM_EXTSEED_RNG_LR_F(void* lr_out, const void* salt, const void* extended_seed, uint64_t node_idx, uint32_t theta); +// x4 variant (I8): expand 4 sibling parent nodes (node_idx0, +2, +4, +6) in one call. +// extended_seeds = 4 contiguous extended keys, lr_out = 4 contiguous 2-seed outputs. +// Byte-identical to four GGM_EXTSEED_RNG_LR_F calls (KAT-preserving). It is always set: +// the cat1 avx2 build uses a batched kernel (4 keys x 2 blocks = 8 cipher blocks run +// interleaved, saturating the AES-NI port); every other build uses a naive wrapper that +// just does the four single calls, so the loop can always call this with no branch. +typedef void GGM_EXTSEED_RNG_LR_X4_F(void* lr_out, const void* salt, const void* extended_seeds, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2( // batched kernel + void* lr_out, const void* salt128, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_x4_ref( // naive four calls + void* lr_out, const void* salt128, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref( // naive four calls + void* lr_out, const void* salt192, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2( // naive four calls + void* lr_out, const void* salt192, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref( // naive four calls + void* lr_out, const void* salt256, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2( // naive four calls + void* lr_out, const void* salt256, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_ref( // + void* lr_out256, const void* salt128, const void* extkey128, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_avx2( // + void* lr_out256, const void* salt128, const void* extkey128, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_ref( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_avx2( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_ref( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_avx2( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta); + + +/** + * Extended leaf seed: the AES/Rijndael key schedule is run once per leaf, and + * the resulting "extended seed" is shared by both the commit rng and the vole + * rng (saving the second, redundant key schedule). For aes/rijndael the + * extended seed is the expanded round keys; for shake it is just the raw seed. + * + * - EXTEND_LEAF_SEED_F turns a raw node_seed into an extended_seed. + * - EXTENDED_NODE_SEED_BYTES_F returns the byte size of the extended seed. + * - the ggm_commit_rng_ext_* / vole_rng_ext_* variants consume the extended + * seed (key/node_seed points at the round keys instead of the raw seed). + * + * The original ggm_commit_rng_* / vole_rng_* symbols are retained as raw-seed + * shims (extend + ext), so callers passing a raw seed still get identical bytes. + */ +typedef void EXTEND_LEAF_SEED_F(void* extended_seed_out, const void* node_seed); +typedef uint64_t EXTENDED_NODE_SEED_BYTES_F(void); + +/** + * 4x leaf-seed expansion: extend four contiguous node_seeds into four contiguous + * extended_seeds in one call, for the BFS ggm traversal. Inputs and outputs are + * packed at their natural stride (node_seed size in, extended_seed size out). + * Output is byte-identical to calling EXTEND_LEAF_SEED_F four times, so it is + * KAT-preserving. The _ref variants call the 1x function four times; the _avx2 + * variants dispatch to the batched key-schedule kernels (aes128 x4, rijndael x2). + */ +typedef void EXTEND_LEAF_SEED_4X_F(void* extended_seed_out, const void* node_seed); + +EXPORT void extend_leaf_seed_cat1_aes128_ref(void* extended_seed_out, const void* seed128); + +/** When building for liboqs, cat1 aes128 uses the liboqs backend, which requires + * the extended-seed buffer to be prepared/released. See aes_ansi_ref.h for details. */ +typedef void EXTSEED_BUF_F(void* buf, uint64_t nslots, uint64_t slot_bytes); + +EXPORT void prepare_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes); +EXPORT void release_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes); +EXPORT void extseed_buf_noop(void* buf, uint64_t nslots, uint64_t slot_bytes); +EXPORT void extend_leaf_seed_cat1_aes128_avx2(void* extended_seed_out, const void* seed128); +EXPORT void extend_leaf_seed_cat3_rijndael256_ref(void* extended_seed_out, const void* seed192); +EXPORT void extend_leaf_seed_cat3_rijndael256_avx2(void* extended_seed_out, const void* seed192); +EXPORT void extend_leaf_seed_cat5_rijndael256_ref(void* extended_seed_out, const void* seed256); +EXPORT void extend_leaf_seed_cat5_rijndael256_avx2(void* extended_seed_out, const void* seed256); + +EXPORT void extend_leaf_seed_cat1_aes128_4x_ref(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat1_aes128_4x_avx2(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_ref(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_avx2(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_ref(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_avx2(void* extended_seed_out, const void* seeds); + +EXPORT uint64_t extended_node_seed_bytes_cat1_aes128(void); +EXPORT uint64_t extended_node_seed_bytes_cat3_rijndael256(void); +EXPORT uint64_t extended_node_seed_bytes_cat5_rijndael256(void); + +// commit rng, extended-seed variants (key points at the expanded round keys). +// The masked salt produced by compute_tweaked_salts reserves the low +// GGM_TWEAK_BITS bits for the tweak, so theta is that constant and is not an argument. +typedef void GGM_EXTSEED_RNG_COMMIT_F( + void* out, + const void* salt, + const void* extended_seed, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat1_aes128_ref(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat1_aes128_avx2(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_ref(void* output384, const void* salt192, const void* extkey, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_avx2(void* output384, const void* salt192, const void* extkey, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_ref(void* output512, const void* salt256, const void* extkey, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_avx2(void* output512, const void* salt256, const void* extkey, + uint64_t node_idx); + +// vole rng, extended-seed variants (node_seed points at the expanded round keys). +// +// The CTR stream starts at the tweaked salt of the repetition: the lambda-bit +// initial counter is +// vole_masked_salt | (repet_idx << VOLE_RNG_REPET_SHIFT) +// (vole_masked_salt comes from compute_tweaked_salts and has its low +// GGM_TWEAK_BITS bits cleared, so the OR is a plain field write). The block +// counter therefore lives in the low VOLE_RNG_REPET_SHIFT bits, which bounds a +// single call to 2^VOLE_RNG_REPET_SHIFT blocks; debug builds assert it via +// domain_sep_check so the last block can never spill into the next repetition. +typedef void VOLE_EXTSEED_RNG_F(void* out, uint64_t out_bytes, const void* vole_masked_salt, + const void* extended_seed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat1_aes128_ctrle_ref(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx); + +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx); + + +#ifndef SDITH3_FOR_LIBOQS +typedef struct xof_ctx_t { + uint64_t DUMMY[224 / 8]; +} xof_ctx; +#else +typedef struct xof_ctx_t { + uint32_t shake; // 128 or 256, set by Keccak_HashInitialize_SHAKE* + union { + OQS_SHA3_shake128_inc_ctx shake128_state; + OQS_SHA3_shake256_inc_ctx shake256_state; + }; +} xof_ctx; +#endif + +typedef void XOF_INIT_F(xof_ctx* xof); +EXPORT void xof_init_shake128(xof_ctx* xof); +EXPORT void xof_init_shake256(xof_ctx* xof); + +typedef void XOF_SEED_F(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes); + +typedef void XOF_FINALIZE_F(xof_ctx* xof); +EXPORT void xof_finalize_shake128(xof_ctx* xof); +EXPORT void xof_finalize_shake256(xof_ctx* xof); + +typedef void XOF_OUTPUT_F(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes); + +// shortcut combo +typedef void XOF_INIT_AND_SEED_F(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_init_and_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_init_and_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes); + +typedef void XOF_FINALIZE_AND_OUTPUT_F(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_finalize_and_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_finalize_and_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes); + +// liboqs requires context be released. When not using liboqs, context is on the stack and this is a no-op. +typedef void XOF_CTX_RELEASE_F(xof_ctx* xof); +EXPORT void xof_ctx_release_shake128(xof_ctx* xof); +EXPORT void xof_ctx_release_shake256(xof_ctx* xof); + +typedef struct xof_functions_t { + XOF_INIT_F* xof_init; + XOF_SEED_F* xof_seed; + XOF_FINALIZE_F* xof_finalize; + XOF_OUTPUT_F* xof_output; + XOF_INIT_AND_SEED_F* xof_init_and_seed; + XOF_FINALIZE_AND_OUTPUT_F* xof_finalize_and_output; + XOF_CTX_RELEASE_F* xof_ctx_release; +} xof_functions; + +static const xof_functions xof_shake128 = { + xof_init_shake128, // + xof_seed_shake128, // + xof_finalize_shake128, // + xof_output_shake128, // + xof_init_and_seed_shake128, // + xof_finalize_and_output_shake128, // + xof_ctx_release_shake128 // +}; +static const xof_functions xof_shake256 = { + xof_init_shake256, // + xof_seed_shake256, // + xof_finalize_shake256, // + xof_output_shake256, // + xof_init_and_seed_shake256, // + xof_finalize_and_output_shake256, // + xof_ctx_release_shake256 // +}; + +typedef struct xof_vector_ctx_t xof_vector_ctx; + +typedef uint64_t XOF_VECTOR_CTX_BYTES_F(uint64_t num_xofs); +EXPORT uint64_t xof_vector_ctx_bytes_shake128(uint64_t num_xofs); +EXPORT uint64_t xof_vector_ctx_bytes_shake256(uint64_t num_xofs); + +typedef void XOF_VECTOR_INIT_AND_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); +EXPORT void xof_vector_init_and_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); +EXPORT void xof_vector_init_and_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); + +typedef void XOF_VECTOR_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); +EXPORT void xof_vector_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); +EXPORT void xof_vector_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); + +typedef void XOF_VECTOR_FINALIZE_AND_OUTPUT_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); +EXPORT void xof_vector_finalize_and_output_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); +EXPORT void xof_vector_finalize_and_output_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); + +// liboqs requires context be released. When not using liboqs, context is on the stack and this is a no-op. +typedef void XOF_VECTOR_CTX_RELEASE_F(xof_vector_ctx* xof, uint64_t num_xofs); +EXPORT void xof_vector_ctx_release_shake128(xof_vector_ctx* xof, uint64_t num_xofs); +EXPORT void xof_vector_ctx_release_shake256(xof_vector_ctx* xof, uint64_t num_xofs); + +typedef struct xof_vector_functions_t { + XOF_VECTOR_CTX_BYTES_F* ctx_bytes; + XOF_VECTOR_INIT_AND_SEED_F* init_and_seed; + XOF_VECTOR_SEED_F* seed; + XOF_VECTOR_FINALIZE_AND_OUTPUT_F* finalize_and_output; + XOF_VECTOR_CTX_RELEASE_F* ctx_release; +} xof_vector_functions; + +static const xof_vector_functions xof_vector_shake128 = { + xof_vector_ctx_bytes_shake128, // + xof_vector_init_and_seed_shake128, // + xof_vector_seed_shake128, // + xof_vector_finalize_and_output_shake128, // + xof_vector_ctx_release_shake128 // +}; + +static const xof_vector_functions xof_vector_shake256 = { + xof_vector_ctx_bytes_shake256, // + xof_vector_init_and_seed_shake256, // + xof_vector_seed_shake256, // + xof_vector_finalize_and_output_shake256, // + xof_vector_ctx_release_shake256 // +}; + + +typedef struct matrix_rng_t { + uint8_t DUMMY[1024]; // large enough t +} __attribute((aligned(32))) matrix_rng_t; + +typedef void MATRIX_RNG_INIT(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_aes128_cat1_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_aes128_cat1_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat3_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat3_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat5_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat5_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); + +// Releases whatever matrix_rng_init took hold of. +// Only active in the cat1 aes128 ref path when building for liboqs, where key schedules +// are heap-allocated (see aes_ansi_ref.h for details). +// The avx and rijndael256 paths expand in place, so they take matrix_rng_release_noop. +typedef void MATRIX_RNG_RELEASE(matrix_rng_t* rng); +EXPORT void matrix_rng_release_aes128_cat1_ref(matrix_rng_t* rng); +EXPORT void matrix_rng_release_noop(matrix_rng_t* rng); + +typedef void MATRIX_RNG_GET_ROW(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat3_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat5_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); + +// Batched counterpart of MATRIX_RNG_GET_ROW: draws the nrows consecutive rows +// first_row, first_row+1, ..., first_row+nrows-1 and writes them back to back in +// out (no gap: the stride is the natural row size bpr*block_bytes, which is the +// rsd_codim_slice of compute_rsd_codim_slice). Because row i is the bpr cipher +// blocks at counter i*bpr, a run of consecutive rows is one contiguous stretch +// of the CTR keystream, so the whole batch is a single cipher call. Output is +// byte-identical to nrows successive get_row calls (KAT-preserving); the point +// is to amortise the per-row call and counter-setup glue, which costs as much as +// the AES itself at these row sizes. +typedef void MATRIX_RNG_GET_ROWS(const matrix_rng_t* rng, void* out, const uint64_t first_row, const uint64_t nrows); +EXPORT void matrix_rng_get_rows_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat3_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat5_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); + +// Fused row generation + challenge multiplication. +// +// rows_times_chall computes dest[i] = for nrows +// consecutive rows, without ever materialising the rows. Generating a row and +// reducing it against the challenge use disjoint execution ports (the cipher +// rounds vs the carry-less multiplier), so fusing them into one loop hides the +// whole field reduction behind the cipher; splitting it across two calls, as a +// get_rows + flambda_dot_product pair must, makes the two costs additive. +// +// The challenge is passed pre-processed. Writing k = lambda/64 and splitting a +// row into 64-bit words h_j, the definition = sum_i H_i * chall_i +// rearranges into sum_j h_j * prep_chall[j] with +// prep_chall[j] = chall[j / k] * X^(64 * (j % k)), +// which is what preprocess_chall builds (once per challenge, reused for every +// row). Each h_j is then a field element with only its low 64 bits populated, so +// each term is a 64-by-lambda multiply: fewer accumulators than the balanced +// Karatsuba form, and the accumulated high part is only 64 bits, so the final +// reduction is a single carry-less multiply instead of a chained fold. It also +// shortens the vector: prep_chall has ceil(row_bits/64) entries rather than the +// ceil(row_bits/lambda)*k words the limb form has to pad up to. +// +// Both take the row bit size from the rng context (stored by init), so the +// pre-processed challenge and the kernel can never disagree on its length. +// dest holds nrows field elements; prep_chall holds matrix_rng_prep_chall_nelems +// of them. Output is identical to the get_rows + flambda_dot_product pair. +typedef void MATRIX_RNG_PREPROCESS_CHALL(const matrix_rng_t* rng, flambda_t* prep_chall, const flambda_t* chall); +typedef void MATRIX_RNG_ROWS_TIMES_CHALL(const matrix_rng_t* rng, flambda_t* dest, const flambda_t* prep_chall, + const uint64_t first_row, const uint64_t nrows); + +/** number of field elements in the pre-processed challenge, for a given row bit size */ +static inline uint64_t matrix_rng_prep_chall_nelems(const uint64_t row_bit_size) { return (row_bit_size + 63) >> 6; } + +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_avx(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_avx(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_avx(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); + +// A matrix prng: init once from a seed for a fixed row bit size, then draw any +// row independently via get_row (row i = the ceil(row_bits/lambda) cipher blocks +// at counter i*bpr, with bits beyond row_bits masked to zero). +// +// Every entry is mandatory: each category has both a ref and an avx +// implementation of the fused rows_times_chall, so callers use it unconditionally +// rather than falling back to the get_rows + flambda_dot_product pair. +typedef struct matrix_rng_functions_t { + MATRIX_RNG_INIT* matrix_rng_init; + MATRIX_RNG_RELEASE* matrix_rng_release; + MATRIX_RNG_GET_ROW* matrix_rng_get_row; + MATRIX_RNG_GET_ROWS* matrix_rng_get_rows; + MATRIX_RNG_PREPROCESS_CHALL* matrix_rng_preprocess_chall; + MATRIX_RNG_ROWS_TIMES_CHALL* matrix_rng_rows_times_chall; +} matrix_rng_functions; + +static const matrix_rng_functions matrix_rng_cat1_aes128_ref = { + matrix_rng_init_aes128_cat1_ref, // + matrix_rng_release_aes128_cat1_ref, // + matrix_rng_get_row_aes128_cat1_ref, // + matrix_rng_get_rows_aes128_cat1_ref, // + matrix_rng_preprocess_chall_aes128_cat1_ref, // + matrix_rng_rows_times_chall_aes128_cat1_ref, // +}; +static const matrix_rng_functions matrix_rng_cat3_rijndael256_ref = { + matrix_rng_init_rijndael256_cat3_ref, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat3_ref, // + matrix_rng_get_rows_rijndael256_cat3_ref, // + matrix_rng_preprocess_chall_rijndael256_cat3_ref, // + matrix_rng_rows_times_chall_rijndael256_cat3_ref, // +}; +static const matrix_rng_functions matrix_rng_cat5_rijndael256_ref = { + matrix_rng_init_rijndael256_cat5_ref, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat5_ref, // + matrix_rng_get_rows_rijndael256_cat5_ref, // + matrix_rng_preprocess_chall_rijndael256_cat5_ref, // + matrix_rng_rows_times_chall_rijndael256_cat5_ref, // +}; +// ONLY_REF_IMPLEMENTATION drops the *_avx2.c translation units, so these tables +// would hold undefined references: they are only compiled with the avx2 backend. +#if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) +static const matrix_rng_functions matrix_rng_cat1_aes128_avx = { + matrix_rng_init_aes128_cat1_avx, // + matrix_rng_release_noop, // + matrix_rng_get_row_aes128_cat1_avx, // + matrix_rng_get_rows_aes128_cat1_avx, // + matrix_rng_preprocess_chall_aes128_cat1_avx, // + matrix_rng_rows_times_chall_aes128_cat1_avx, // +}; +static const matrix_rng_functions matrix_rng_cat3_rijndael256_avx = { + matrix_rng_init_rijndael256_cat3_avx, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat3_avx, // + matrix_rng_get_rows_rijndael256_cat3_avx, // + matrix_rng_preprocess_chall_rijndael256_cat3_avx, // + matrix_rng_rows_times_chall_rijndael256_cat3_avx, // +}; +static const matrix_rng_functions matrix_rng_cat5_rijndael256_avx = { + matrix_rng_init_rijndael256_cat5_avx, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat5_avx, // + matrix_rng_get_rows_rijndael256_cat5_avx, // + matrix_rng_preprocess_chall_rijndael256_cat5_avx, // + matrix_rng_rows_times_chall_rijndael256_cat5_avx, // +}; +#endif + +// The keygen prng: the secret-key seed expanded into the little-endian uint32 +// stream the rsd position sampler draws from. It is a plain block-cipher CTR +// keystream with a zero IV, nothing more: +// cat1: aes128, key = the 16-byte seed +// cat3: rijndael256, key = the 24-byte seed padded with 64 zero bits in the MSB +// cat5: rijndael256, key = the 32-byte seed +// The counter is little-endian over the low 64 bits (the same no-carry CTR the +// rest of the prngs use), so block i is enc(i) and the stream is the blocks +// concatenated. lambda/8 is a multiple of 4 for every category, so a draw never +// straddles a block boundary. +typedef struct keygen_rng_ctx_t { + uint8_t DUMMY[1024]; // large enough for any category +} __attribute((aligned(32))) keygen_rng_ctx; + +typedef void KEYGEN_RNG_INIT(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_aes128_cat1_ref(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_aes128_cat1_avx(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat3_ref(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat3_avx(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat5_ref(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat5_avx(keygen_rng_ctx* rng, const seed_t* sk_seed); + +typedef uint32_t KEYGEN_RNG_NEXT_U32(keygen_rng_ctx* rng); +EXPORT uint32_t keygen_rng_next_u32_aes128_cat1_ref(keygen_rng_ctx* rng); +EXPORT uint32_t keygen_rng_next_u32_aes128_cat1_avx(keygen_rng_ctx* rng); +// cat3 and cat5 only differ in the key they are initialised with, so they share +// their draw function: the rijndael256 one. +EXPORT uint32_t keygen_rng_next_u32_rijndael256_ref(keygen_rng_ctx* rng); +EXPORT uint32_t keygen_rng_next_u32_rijndael256_avx(keygen_rng_ctx* rng); + +// Releases whatever keygen_rng_init took hold of: as for matrix_rng, only the +// cat1 aes128 ref path owns a schedule. +typedef void KEYGEN_RNG_RELEASE(keygen_rng_ctx* rng); +EXPORT void keygen_rng_release_aes128_cat1_ref(keygen_rng_ctx* rng); +EXPORT void keygen_rng_release_noop(keygen_rng_ctx* rng); + +typedef struct keygen_rng_functions_t { + KEYGEN_RNG_INIT* init; + KEYGEN_RNG_RELEASE* release; + KEYGEN_RNG_NEXT_U32* next_u32; +} keygen_rng_functions; + +static const keygen_rng_functions keygen_rng_cat1_aes128_ref = { + keygen_rng_init_aes128_cat1_ref, // + keygen_rng_release_aes128_cat1_ref, // + keygen_rng_next_u32_aes128_cat1_ref, // +}; +static const keygen_rng_functions keygen_rng_cat3_rijndael256_ref = { + keygen_rng_init_rijndael256_cat3_ref, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_ref, // +}; +static const keygen_rng_functions keygen_rng_cat5_rijndael256_ref = { + keygen_rng_init_rijndael256_cat5_ref, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_ref, // +}; +#if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) +static const keygen_rng_functions keygen_rng_cat1_aes128_avx = { + keygen_rng_init_aes128_cat1_avx, // + keygen_rng_release_noop, // + keygen_rng_next_u32_aes128_cat1_avx, // +}; +static const keygen_rng_functions keygen_rng_cat3_rijndael256_avx = { + keygen_rng_init_rijndael256_cat3_avx, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_avx, // +}; +static const keygen_rng_functions keygen_rng_cat5_rijndael256_avx = { + keygen_rng_init_rijndael256_cat5_avx, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_avx, // +}; +#endif + +#endif // AQ_VOLE_IMPL_RNG_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_prng_private.h b/src/sig/sdith/sdith_sdith_common/sdith_prng_private.h new file mode 100644 index 0000000000..22d5bb8d61 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_prng_private.h @@ -0,0 +1,293 @@ +#ifndef RNG_PRIVATE_H +#define RNG_PRIVATE_H + +#include + +#include "aes128_ctrle.h" // ctr128_t (also pulls in rijndael256_ctrle.h -> ctr256_t) +#include "rijndael256_ctrle.h" +#include "sdith_prng.h" +#include "vole_private.h" + +// union that represents an aes128 little endian counter +typedef union { + __uint128_t u128; + uint64_t v64[2]; +} aesblk; + +/** + * @brief Domain-separated CTR plaintext, low 64 bits (round 3). + * will compute: MapToBitsLE(tweak, theta) || salt[theta:salt_bitsize] + */ +static inline void domain_sep_ptx_lo2( // + uint64_t* const outctr, // aesctr 32-bytes aligned + const void* const masked_salt, const uint64_t salt_bytes, // salt [no specific alignment] + const uint64_t tweak) +{ + memcpy(outctr, masked_salt, salt_bytes); + outctr[0] |= tweak; +} + +#ifdef __x86_64__ +#include + +/** + * @brief avx2 form of domain_sep_ptx_lo2, for a 128-bit CTR block. + * + * Same plaintext, built in a vector register: the caller stores it once with a + * single aligned 16-byte store, which is exactly the width the CTR kernel loads + * it back at. Going through memory in two 8-byte pieces instead (what the + * memcpy + scalar-or pair compiles to) makes the kernel's 16-byte load overlap + * two narrower stores, which costs a store-forwarding stall on every call -- + * about as much as encrypting five extra blocks. + */ +static inline __m128i domain_sep_ptx_lo2_m128( // + const void* const masked_salt, // salt [no specific alignment] + const uint64_t tweak) +{ + return _mm_or_si128(_mm_loadu_si128((const __m128i*)masked_salt), + _mm_cvtsi64_si128((long long)tweak)); +} + +/** + * @brief 256-bit CTR block held as the two halves the rijndael256 kernels read. + * Those kernels take the block as two 16-byte loads, so keeping it in two + * registers lets the caller answer them with two matching 16-byte stores. + */ +typedef struct { + __m128i lo; + __m128i hi; +} ctr256_vec; + +/** @brief 192-bit salt in a 256-bit block: the 8 bytes above the salt stay zero. */ +static inline ctr256_vec domain_sep_ptx_lo2_m256_from192( // + const void* const masked_salt, // 24-byte salt [no specific alignment] + const uint64_t tweak) +{ + const uint8_t* const s = (const uint8_t*)masked_salt; + uint64_t hi64; + memcpy(&hi64, s + 16, 8); + ctr256_vec res = {domain_sep_ptx_lo2_m128(s, tweak), _mm_cvtsi64_si128((long long)hi64)}; + return res; +} + +/** @brief 256-bit salt filling the whole 256-bit block. */ +static inline ctr256_vec domain_sep_ptx_lo2_m256( // + const void* const masked_salt, // 32-byte salt [no specific alignment] + const uint64_t tweak) +{ + const uint8_t* const s = (const uint8_t*)masked_salt; + ctr256_vec res = {domain_sep_ptx_lo2_m128(s, tweak), _mm_loadu_si128((const __m128i*)(s + 16))}; + return res; +} +#endif // __x86_64__ + +/** + * @brief Parameters sanity check: + * ensures that the tweak remains bounded by 2^theta and that the salt has its first + * theta bits to zero. + * These checks are meant to run in DEBUG mode only to catch bugs in the source code or + * in the parametrization of the signature, + * These checks do not need to run in production (calling in CASSERT is ok). + */ +static inline int domain_sep_check( // + const void* salt, + uint64_t tweak, + uint64_t nblocks, + uint64_t theta) +{ + uint64_t THETA_MASK = (UINT64_C(1) << theta) - 1; + uint64_t in_salt; + memcpy(&in_salt, salt, 8); + // check that the input salt and the mask are disjoint + if ((in_salt & THETA_MASK) != 0) return 0; + // check that the tweak won't overflow + if ((tweak & ~THETA_MASK) != 0) return 0; + if (((tweak + nblocks - 1) & ~THETA_MASK) != 0) return 0; + return 1; +} + +// I8: define a naive x4 LR expansion (four single PERNODE calls on parents +// node_idx0, +2, +4, +6). Used where there is no batched kernel (the ref build, +// and cat3/cat5 avx2). Byte-identical to the batched cat1 kernel, so the tree +// loop can always call the x4 pointer with no branch. LR_STRIDE = 2 * seed bytes +// (the 2-seed output per node), EXT_STRIDE = one extended key. +#define GGM_EXTSEED_RNG_LR_X4_NAIVE(NAME, PERNODE, LR_STRIDE, EXT_STRIDE) \ + EXPORT void NAME(void* lr_out, const void* salt, const void* extended_seeds, uint64_t node_idx0, \ + uint32_t theta) { \ + uint8_t* o = (uint8_t*)lr_out; \ + const uint8_t* e = (const uint8_t*)extended_seeds; \ + for (int i = 0; i < 4; i++) { \ + PERNODE(o + (uint64_t)i * (LR_STRIDE), salt, e + (uint64_t)i * (EXT_STRIDE), \ + node_idx0 + 2 * i, theta); \ + } \ + } + + +union proofow_ctr128_t { + uint8_t v8[16]; + uint64_t v64[2]; +} __attribute__((aligned(16))); + +struct proofow_state128_t { + union proofow_ctr128_t p[2]; // aes128 plaintext + union proofow_ctr128_t k[2]; // aes128 key + union proofow_ctr128_t c[2]; // aes128 ciphertext + union proofow_ctr128_t rk[2][11]; // 11 round keys of aes128 + uint8_t h_piop[32]; + uint64_t delta0_out_bytes; + uint64_t mask_w; +} __attribute__((aligned(32))); + +union proofow_ctr256_t { + uint8_t v8[32]; + uint64_t v64[4]; +} __attribute__((aligned(32))); + +struct proofow_state256_t { + union proofow_ctr256_t p[2]; // rijndael256 plaintext + union proofow_ctr256_t k[2]; // rijndael256 key + union proofow_ctr256_t c[2]; // rijndael256 ciphertext + union proofow_ctr256_t rk[2][15]; // 15 round keys of rijndael256 (RIJNDAEL256_RK_BYTES each) + uint8_t h_piop[64]; + uint64_t delta0_out_bytes; + uint64_t mask_w; +} __attribute__((aligned(32))); + +struct proofow_shake_cat1_t { + uint8_t delta0_and_vgrind[32]; // at least 16 + w + uint8_t h_piop[32]; + uint64_t delta0_and_vgrind_bytes; + uint64_t delta0_out_bytes; + uint64_t w; + uint64_t kappa_tau; +} __attribute__((aligned(32))); + +struct proofow_shake_cat3_t { + uint8_t delta0_and_vgrind[32]; // at least 24 + w + uint8_t h_piop[48]; + uint64_t delta0_and_vgrind_bytes; + uint64_t delta0_out_bytes; + uint64_t w; + uint64_t kappa_tau; +} __attribute__((aligned(32))); + +struct proofow_shake_cat5_t { + uint8_t delta0_and_vgrind[64]; // at least 32 + w + uint8_t h_piop[64]; + uint64_t delta0_and_vgrind_bytes; + uint64_t delta0_out_bytes; + uint64_t w; + uint64_t kappa_tau; +} __attribute__((aligned(32))); + +struct matrix_rng_aes128_cat1_t { + ctr128_t rk[11]; // round keys (11 blocks for aes128) + ctr128_t last_blk_mask; // AND mask to apply to the last PRG block + uint64_t blocks_per_row; // number of PRG blocks to generate per row + uint64_t row_bit_size; // bits per row (bits beyond it are masked off) +} __attribute__((aligned(32))); // + +struct matrix_rng_rijndael256_cat3_t { + ctr256_t rk[15]; // round keys (15 blocks for rijndael256) + ctr256_t last_blk_mask; // AND mask to apply to the last (256-bit) PRG block + uint64_t blocks_per_row; // number of PRG blocks to generate per row + uint64_t row_bit_size; // bits per row (bits beyond it are masked off) +} __attribute__((aligned(32))); // + +struct matrix_rng_rijndael256_cat5_t { + ctr256_t rk[15]; // round keys (15 blocks for rijndael256) + ctr256_t last_blk_mask; // AND mask to apply to the last PRG block + uint64_t blocks_per_row; // number of PRG blocks to generate per row + uint64_t row_bit_size; // bits per row (bits beyond it are masked off) +} __attribute__((aligned(32))); // + +// Fills res[0..res_size) with a little-endian bitmask keeping the low b bits. +// Special case: b == 0 means the last PRG block is entirely used (the row bit +// size is a multiple of the block bit size), so every bit is kept (all ones). +// Shared by the ref and avx matrix_rng init (mask setup is scalar either way). +static inline void set_2_b_minus_one(uint64_t* res, uint64_t res_size, uint64_t b) { + if (b == 0) { + for (uint64_t i=0; i= 64) { + res[i] = UINT64_C(-1); + b -= 64; + } else { + res[i] = (UINT64_C(1) << b) - 1; + b = 0; + } + } +} + +// Body of MATRIX_RNG_PREPROCESS_CHALL, parameterised by the field. With +// k = lambda/64, it builds prep_chall[j] = chall[j / k] * X^(64 * (j % k)). +// Shared by the ref and avx matrix_rng so the two tables can never disagree; +// only the product differs (ref bit loop vs pclmul). +static inline void preprocess_chall_generic(flambda_t* prep_chall, const flambda_t* chall, const uint64_t nelems, + const uint64_t lambda_bytes, const uint64_t k, + FLAMBDA_PRODUCT_F* product) { + uint8_t* const out = (uint8_t*) prep_chall; + const uint8_t* const in = (const uint8_t*) chall; + for (uint64_t j = 0; j < nelems; ++j) { + // X^(64*m) as a field element: the single bit at position 64*m + flambda_max_t xpow = {0, 0, 0, 0}; + xpow[j % k] = 1; + product(out + j * lambda_bytes, in + (j / k) * lambda_bytes, xpow); + } +} + +// --- keygen prng (see keygen_rng_ctx in sdith_prng.h) ----------------------- +// +// A pure CTR keystream read as little-endian uint32s. The blocks are produced a +// few at a time rather than one by one: the keystream is contiguous, so a batch +// is a single cipher call and the output is unchanged, but the per-call counter +// setup and (on avx2) the pipeline fill are amortised over the whole batch. The +// leftover of the last batch is simply never read. +#define KEYGEN_RNG_BUF_BLOCKS 4 + +struct keygen_rng_aes128_cat1_t { + ctr128_t buf[KEYGEN_RNG_BUF_BLOCKS]; // keystream buffer + ctr128_t rk[11]; // round keys (11 blocks for aes128) + uint64_t next_block; // counter of the next block to produce + uint64_t off; // read offset in buf (== buf size when empty) +} __attribute__((aligned(32))); + +// cat3 and cat5 share this layout and every function but the init: the only +// difference between them is the key the schedule is run on. +struct keygen_rng_rijndael256_t { + ctr256_t buf[KEYGEN_RNG_BUF_BLOCKS]; // keystream buffer + ctr256_t rk[15]; // round keys (15 blocks for rijndael256) + uint64_t next_block; // counter of the next block to produce + uint64_t off; // read offset in buf (== buf size when empty) +} __attribute__((aligned(32))); + +// Marks the buffer as empty, so that the first draw refills it from block 0. +#define KEYGEN_RNG_INIT_EMPTY(S) \ + do { \ + (S)->next_block = 0; \ + (S)->off = sizeof((S)->buf); \ + } while (0) + +// Body of the draw function, parameterised by the cipher (ref or avx2 kernel): +// refill the buffer when it runs dry, then hand out the next little-endian +// uint32. Shared by the ref and avx paths so the two can only ever differ in +// the cipher call itself. +#define DEFINE_KEYGEN_RNG_NEXT_U32(NAME, STATE_T, CTR_T, CTRLE_NBLOCKS) \ + EXPORT uint32_t NAME(keygen_rng_ctx* rng) { \ + struct STATE_T* const s = (struct STATE_T*)rng; \ + if (s->off == sizeof(s->buf)) { \ + CTR_T ctr = {}; \ + ctr.v64[0] = s->next_block; \ + CTRLE_NBLOCKS(s->buf, s->rk, ctr.v64, KEYGEN_RNG_BUF_BLOCKS); \ + s->next_block += KEYGEN_RNG_BUF_BLOCKS; \ + s->off = 0; \ + } \ + uint32_t out; \ + memcpy(&out, (const uint8_t*)s->buf + s->off, 4); \ + s->off += 4; \ + return out; \ + } + +#endif // RNG_PRIVATE_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_rsd.h b/src/sig/sdith/sdith_sdith_common/sdith_rsd.h new file mode 100644 index 0000000000..f2c2374e1a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_rsd.h @@ -0,0 +1,67 @@ +#ifndef SDITHER_RSD_H +#define SDITHER_RSD_H + +#include "vole_parameters.h" + +/// keygen stuff + +EXPORT uint64_t rsd_generate_random_instance_tmp_bytes( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim); + +/** generate a random rsd instance out of the master key entropy. + * Only the parts of the key that have to be stored are produced: the solution + * (from the sk_seed) and the syndrome y = H.e (from the pk_seed). H itself is + * the public key -- it is recoverable from pk_seed with + * rsd_expand_public_key_ref -- so it is never materialised here: y touches at + * most rsd_w of its rows, and those are drawn one at a time into the scratch. + * Output is identical to expanding H and xoring the selected rows out of it. + * Constant-time in the solution. tmp_space still holds one expanded H row on + * return: the caller must scrub it. */ +EXPORT void rsd_generate_random_instance_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // prng + matrix-prng family + bitvec_t* y, uint64_t y_bytes, // out: syndrome (ceil(rsd_codim/8) bytes are set) + uint32_t* solution, // out: rsd_w integers in [0,n/w-1] + const seed_t* sk_seed, // in: secret key seed (lambda bits) + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + uint8_t* tmp_space // scratch space +); + +/** expand the public key from the pubkey seed (rows via vole_params->matrix_prg). + * Each row occupies rsd_codim_limbs*lambda_bytes bytes; h_slice_bytes must be at + * least that and keep every row aligned to the cipher block (16/8/32 bytes). */ +EXPORT void rsd_expand_public_key_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // matrix-prng family + bitmat_t* h, uint64_t h_slice_bytes, // out: (rsd_n - rsd_codim) x rsd_n matrix + const seed_t* h_seed // in: pubkey seed (lambda bits) +); + +/** unary encoding of the solution (for mux circuits). + * Constant-time in the solution coefficients (mux_arities must be < 32). */ +EXPORT void rsd_encode_solution_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // ct helpers + uint64_t mux_depth, const uint64_t* mux_arities, // mux depth and arities + bitvec_t* encoded_solution, uint64_t encoded_solution_bytes, // encoded solution + const uint32_t* solution // in: solution coefficients +); + +EXPORT uint64_t rsd_public_key_times_challenge_tmp_bytes( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim); + +/** multiply the public key with challenge points */ +EXPORT void rsd_public_key_times_challenge_ref( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + flambda_t* chall_a_H, // out: n elements + flambda_t* chall_a_y, // out: 1 element + const flambda_t* chall_a, // in: rsd_codim_limbs elements + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + const bitvec_t* y, // in: pubkey y (rsd_codim bits padded with zeros) + uint8_t* tmp_space // scratch space +); + +#endif // SDITHER_RSD_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_signature.c b/src/sig/sdith/sdith_sdith_common/sdith_signature.c new file mode 100644 index 0000000000..a7f390003b --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_signature.c @@ -0,0 +1,806 @@ +#include + +#include "ggm.h" +#include "math.h" +#include "vole_private.h" + +const uint8_t HASH_BAVC_PREFIX = 1; +const uint8_t HASH_AUX_PREFIX = 2; +const uint8_t HASH_LINES_PREFIX = 3; +const uint8_t HASH_PIOP_PREFIX = 4; +const uint8_t PROOFOW_H0_PREFIX = 5; +const uint8_t PROOFOW_H1_PREFIX = 6; +const uint64_t PROOFOW_CTR_REVEALED_BYTES = 4; // we reveal this num of bytes of proofow ctr in the signature + +uint64_t compute_rsd_codim(uint64_t rsd_n, uint64_t rsd_w) { + // target density is 1/100 + static const double LOG2_INV_TARGET_DENSITY = 6.64385618977; // log2(100.); + const uint64_t rsd_nsw = rsd_n / rsd_w; // exact division + // smallest codim where density drops below TARGET_DENSITY + const uint64_t rsd_min_codim = ceil(rsd_w * log2(rsd_nsw) + LOG2_INV_TARGET_DENSITY); + // smallest multiple of 8 above that bound + return ((rsd_min_codim + 7) & UINT64_C(-8)); +} + + +EXPORT void compute_rsd_codim_slice( + uint64_t* rsd_codim_limbs, // [out] number of limbs + uint64_t* rsd_codim_slice, // [out] number of slice bytes to hold the prng blocks + const uint64_t lambda, const uint64_t rsd_codim) { + uint64_t prng_blk_bytes = lambda == 128 ? 16 : 32; // cat3 and cat5 use a 256-bit prng + *rsd_codim_limbs = (rsd_codim + lambda - 1) / lambda; + uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + uint64_t rsd_codim_prng_blks = (rsd_codim_bytes + prng_blk_bytes - 1) / prng_blk_bytes; + *rsd_codim_slice = rsd_codim_prng_blks * prng_blk_bytes; + CREQUIRE(*rsd_codim_slice >= *rsd_codim_limbs * (lambda >> 3), + "bug! invalid parameters rsd_codim_slice will not be able to hold all the limbs"); +} + +void compute_extended_parameters(extended_parameters_t* res, const signature_parameters* sig_params) { + // compute extended parameters + res->lambda = sig_params->lambda; + res->kappa = sig_params->kappa; + res->tau = sig_params->tau; + res->target_topen = sig_params->target_topen; + res->rsd_n = sig_params->rsd_n; + res->rsd_w = sig_params->rsd_w; + res->mux_depth = sig_params->mux_depth; + memcpy(res->mux_arities, sig_params->mux_arities, sizeof(uint64_t) * 8); + res->rsd_npw = sig_params->rsd_n / sig_params->rsd_w; // exact division + res->rsd_codim = compute_rsd_codim(res->rsd_n, res->rsd_w); + res->proofow_w = sig_params->proofow_w; + res->delta0_bits = res->kappa * res->tau + sig_params->proofow_w; + res->delta0_dwords = (res->delta0_bits + 63) >> 6; + res->delta0_bytess = (res->delta0_bits + 7) >> 3; + res->delta0_capacity = res->delta0_dwords << 3; + memset(&res->vole_params, 0, sizeof(vole_parameters)); + vole_parameters_init_with_variant(&res->vole_params, res->lambda, res->tau, res->kappa, sig_params->proofow_variant); + uint64_t mux_inputs = 0; + uint64_t chall_unitary_powers = 0; + { + for (uint64_t i = 0; i < res->mux_depth; ++i) { + mux_inputs += res->mux_arities[i] - 1; + if (res->mux_arities[i] > 2) chall_unitary_powers += 32; + } + } + CREQUIRE(chall_unitary_powers <= res->lambda, "Params error: too many non-binary arities"); + res->mux_inputs = mux_inputs; + res->chall_unitary_powers = chall_unitary_powers; + res->degree = res->mux_depth > 2 ? res->mux_depth : 2; + res->num_inputs_pairs = mux_inputs * res->rsd_w; + res->num_cchk_pairs = vole_consistency_check_matrix_nrows(&res->vole_params); + CREQUIRE((res->num_cchk_pairs & 7) == 0, "non mult of 8 cchk is not supported"); + res->num_cz_pairs = res->lambda * (res->degree - 1); + res->real_L = res->num_inputs_pairs + res->num_cchk_pairs + res->num_cz_pairs; + res->L = (res->real_L + 7) & UINT64_C(-8); // L must be an exact mult of 8 + res->Lbyte = res->L >> 3; + res->Lslice = (res->Lbyte + 31 ) & UINT64_C(-32); // Lslice must be an exact mult of 32 + res->lambda_bytes = res->lambda >> 3; + res->cchk_matrix_nrows = vole_consistency_check_matrix_nrows(&res->vole_params); + res->cchk_matrix_ncols = vole_consistency_check_matrix_ncols(&res->vole_params, res->L); + res->rsd_codim_bytes = (res->rsd_codim + 7) >> 3; + compute_rsd_codim_slice(&res->rsd_codim_limbs, &res->rsd_codim_slice, res->lambda, res->rsd_codim); +} + +EXPORT uint64_t sdith_signature_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + uint64_t sig_bytes = 0; + sig_bytes += par.lambda_bytes; // global_salt + sig_bytes += par.target_topen * par.lambda_bytes; // sibling path; + sig_bytes += par.tau * 2 * par.lambda_bytes; // ggm_hidden_leaf_cmt + sig_bytes += par.Lbyte * (par.tau - 1); // corr_u + sig_bytes += par.num_cchk_pairs >> 3; // cchk_u + sig_bytes += (par.num_inputs_pairs + 7) >> 3; // circuit_in_pub + sig_bytes += (par.degree - 1) * par.lambda_bytes; // circuit_cz_pub (alpha_1 omitted) + sig_bytes += 2 * par.lambda_bytes; // hash_piop + sig_bytes += 4; // proofow_ctr_reveal + return sig_bytes; +} + +EXPORT uint64_t sdith_signature_tmp_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(hash_t*, hash_com, 32, 2 * par.lambda_bytes); // commitment of the ggm tree + COMP_SPACE_MAP_ALIGNED(hash_t*, hash_aux, 32, + 2 * par.lambda_bytes); // (round1) ggm_cmt_hash + corr_terms :=> cchk matrix + // (round3) hash_aux + cchk_u + cchk_v + inputs_mask :=> chall + COMP_SPACE_MAP_ALIGNED(hash_t*, hash_lines, 32, 2 * par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(seed_t*, root_seed, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, u, 32, par.Lslice* par.tau); + COMP_SPACE_MAP_ALIGNED(uint8_t*, v, 32, par.Lslice* par.lambda); + COMP_SPACE_MAP_ALIGNED(uint8_t*, v2, 32, par.Lslice* par.lambda); // copy needed during transposition + COMP_SPACE_MAP_ALIGNED(uint8_t*, rvp_f_cz, 32, par.lambda_bytes* par.degree * 2); + COMP_SPACE_MAP_ALIGNED(uint8_t*, res_f, 32, par.lambda_bytes*(par.degree + 1)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_f, 32, par.lambda_bytes*(par.degree + 1)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + COMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_f, 32, par.lambda_bytes * 2 * par.num_inputs_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_unitary, 32, par.lambda_bytes* par.rsd_w); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_H, 32, par.lambda_bytes* par.rsd_n); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_y, 32, par.lambda_bytes); + COMP_SPACE_MAP(uint8_t*, cchk_matrix, par.cchk_matrix_nrows* par.cchk_matrix_ncols >> 3); + COMP_SPACE_MAP_ALIGNED(uint8_t*, cchk_res_v, 32, par.lambda_bytes* par.cchk_matrix_nrows); + COMP_SPACE_MAP(uint8_t*, delta0, par.delta0_capacity); + COMP_SPACE_MAP_ALIGNED(uint8_t*, delta1, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + COMP_SPACE_MAP_CALL( + prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes(&par.vole_params, par.L)); + COMP_SPACE_MAP_CALL( + prover_cst_mux_circuit_ct_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + COMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + COMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + COMP_SPACE_MAP_CALL( + full_ggm_tree_open_sibling_path_from_root_tmp_bytes(&par.vole_params, par.target_topen) + ); + COMP_SPACE_RETURN(); +} + +EXPORT uint64_t sdith_signature_entropy_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + return 2 * lambda_bytes; +} + +EXPORT uint64_t sdith_secret_key_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + const uint64_t mux_depth = sig_params->mux_depth; + const uint64_t* mux_arities = sig_params->mux_arities; + const uint64_t rsd_w = sig_params->rsd_w; + const uint64_t rsd_codim = compute_rsd_codim(sig_params->rsd_n, sig_params->rsd_w); + const uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + uint64_t mux_inputs = 0; + for (uint64_t i = 0; i < mux_depth; ++i) { + mux_inputs += mux_arities[i] - 1; + } + const uint64_t skey_encoded_solution_bytes = (rsd_w * mux_inputs + 7) >> 3; + return lambda_bytes + skey_encoded_solution_bytes + rsd_codim_bytes; +} + +EXPORT uint64_t sdith_public_key_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + const uint64_t rsd_codim = compute_rsd_codim(sig_params->rsd_n, sig_params->rsd_w); + ; + const uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + return lambda_bytes + rsd_codim_bytes; +} +EXPORT uint64_t sdith_keygen_tmp_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint32_t*, skey_solution, 4, par.rsd_w * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, pkey_full_y, 32, par.rsd_codim_limbs* par.lambda_bytes); + COMP_SPACE_MAP_CALL(rsd_generate_random_instance_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + COMP_SPACE_RETURN(); +} + +EXPORT uint64_t sdith_keygen_entropy_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + return 2 * lambda_bytes; +} + +#define MAP_FIELD(POOL_NAME, FIELD_NAME, VAR_BYTES) \ + FIELD_NAME = (__typeof__(FIELD_NAME))POOL_NAME; \ + POOL_NAME += (VAR_BYTES) + +/** secret key mapping */ +typedef struct skey_mapping_t { + uint8_t* pkey_seed; + uint8_t* skey_encoded_solution; + uint8_t* pkey_y; +} skey_mapping_t; + +skey_mapping_t map_secret_key(const extended_parameters_t* par, const void* skey) { + const uint64_t skey_encoded_solution_bytes = (par->rsd_w * par->mux_inputs + 7) >> 3; + skey_mapping_t res; + uint8_t* secret_key = (uint8_t*)skey; + MAP_FIELD(secret_key, res.pkey_seed, par->lambda_bytes); + MAP_FIELD(secret_key, res.pkey_y, par->rsd_codim_bytes); + MAP_FIELD(secret_key, res.skey_encoded_solution, skey_encoded_solution_bytes); // unary encoded + return res; +} + +/** public key mapping */ +typedef struct pkey_mapping_t { + uint8_t* pkey_seed; + uint8_t* pkey_y; +} pkey_mapping_t; + +pkey_mapping_t map_public_key(const extended_parameters_t* par, const void* pkey) { + pkey_mapping_t res; + uint8_t* public_key = (uint8_t*)pkey; + MAP_FIELD(public_key, res.pkey_seed, par->lambda_bytes); + MAP_FIELD(public_key, res.pkey_y, par->rsd_codim_bytes); + return res; +} + +/** signature mapping */ +typedef struct signature_mapping_t { + uint8_t* global_salt; + uint8_t* ggm_sibling_path; + uint8_t* ggm_hidden_leaf_cmt; + uint8_t* corr_u; + uint8_t* cchk_u; + uint8_t* circuit_in_pub; + uint8_t* circuit_cz_pub; + uint8_t* hash_piop; + uint8_t* proofow_ctr_reveal; +} signature_mapping_t; + +signature_mapping_t map_signature(const extended_parameters_t* par, const void* sign) { + signature_mapping_t res; + uint8_t* sign_fields = (uint8_t*)sign; + MAP_FIELD(sign_fields, res.global_salt, par->lambda_bytes); + MAP_FIELD(sign_fields, res.ggm_sibling_path, par->target_topen * par->lambda_bytes); + MAP_FIELD(sign_fields, res.ggm_hidden_leaf_cmt, par->tau * 2 * par->lambda_bytes); + MAP_FIELD(sign_fields, res.corr_u, par->Lbyte * (par->tau - 1)); + MAP_FIELD(sign_fields, res.cchk_u, par->num_cchk_pairs >> 3); + MAP_FIELD(sign_fields, res.circuit_in_pub, (par->num_inputs_pairs + 7) >> 3); + MAP_FIELD(sign_fields, res.circuit_cz_pub, (par->degree - 1) * par->lambda_bytes); + MAP_FIELD(sign_fields, res.hash_piop, 2 * par->lambda_bytes); + MAP_FIELD(sign_fields, res.proofow_ctr_reveal, PROOFOW_CTR_REVEALED_BYTES); + return res; +} + +EXPORT void sdith_keygen(const signature_parameters* sig_params, // + void* skey, // out: secret key + void* pkey, // out: public key + const void* entropy, // in: entropy + uint8_t* tmp_space) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + const uint64_t skey_encoded_solution_bytes = (par.rsd_w * par.mux_inputs + 7) >> 3; + + // local variables + TMP_SPACE_MAP_ALIGNED(uint32_t*, skey_solution, 4, par.rsd_w * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, pkey_full_y, 32, par.rsd_codim_limbs* par.lambda_bytes); + + // secret key + skey_mapping_t sk = map_secret_key(&par, skey); + + // public key + pkey_mapping_t pk = map_public_key(&par, pkey); + + // copy the entropy + memcpy(pk.pkey_seed, entropy, par.lambda_bytes); + const uint8_t* skey_seed = (const uint8_t*)entropy + par.lambda_bytes; + memcpy(sk.pkey_seed, pk.pkey_seed, par.lambda_bytes); + + // H is not materialised: it is the public key, recoverable from pkey_seed. + rsd_generate_random_instance_ref(par.rsd_w, par.rsd_n, par.rsd_codim, // + &par.vole_params, // + pkey_full_y, par.rsd_codim_limbs * par.lambda_bytes, // + skey_solution, // + skey_seed, pk.pkey_seed, // + tmp_space); // + rsd_encode_solution_ref( // + par.rsd_w, par.rsd_n, par.rsd_codim, // + &par.vole_params, // + par.mux_depth, par.mux_arities, // + sk.skey_encoded_solution, skey_encoded_solution_bytes, // + skey_solution); + + memcpy(pk.pkey_y, pkey_full_y, par.rsd_codim_bytes); + memcpy(sk.pkey_y, pkey_full_y, par.rsd_codim_bytes); + // NOTE: on return, tmp_space still holds the raw solution (skey_solution) and + // one expanded H row. The caller must scrub it -- the constant-time work above + // is pointless if the secret is simply left behind in the scratch buffer. +} + +EXPORT void sdith_sign(const signature_parameters* sig_params, // + void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* skey, // secret key + const void* entropy, // in: entropy + uint8_t* tmp_space) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + // secret key + const skey_mapping_t sk = map_secret_key(&par, skey); + + // signature fields + const signature_mapping_t sign = map_signature(&par, signature); + + // local variables + TMP_SPACE_MAP_ALIGNED(hash_t*, hash_com, 32, 2 * par.lambda_bytes); // commitment of the ggm tree + TMP_SPACE_MAP_ALIGNED(hash_t*, hash_aux, 32, + 2 * par.lambda_bytes); // (round1) ggm_cmt_hash + corr_terms :=> cchk matrix + // (round3) hash_aux + cchk_u + cchk_v + inputs_mask :=> chall + TMP_SPACE_MAP_ALIGNED(hash_t*, hash_lines, 32, 2 * par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(seed_t*, root_seed, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, u, 32, par.Lslice * par.tau); + TMP_SPACE_MAP_ALIGNED(uint8_t*, v, 32, par.Lslice * par.lambda); + TMP_SPACE_MAP_ALIGNED(uint8_t*, v2, 32, par.Lslice * par.lambda); // copy needed during transposition + TMP_SPACE_MAP_ALIGNED(uint8_t*, rvp_f_cz, 32, par.lambda_bytes* par.degree * 2); + TMP_SPACE_MAP_ALIGNED(uint8_t*, res_f, 32, par.lambda_bytes*(par.degree + 1)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_f, 32, par.lambda_bytes*(par.degree + 1)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + TMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_f, 32, par.lambda_bytes * 2 * par.num_inputs_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_unitary, 32, par.lambda_bytes* par.rsd_w); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_H, 32, par.lambda_bytes* par.rsd_n); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_y, 32, par.lambda_bytes); + TMP_SPACE_MAP(uint8_t*, cchk_matrix, par.cchk_matrix_nrows* par.cchk_matrix_ncols >> 3); + TMP_SPACE_MAP_ALIGNED(uint8_t*, cchk_res_v, 32, par.lambda_bytes* par.cchk_matrix_nrows); + TMP_SPACE_MAP(uint8_t*, delta0, par.delta0_capacity); + TMP_SPACE_MAP_ALIGNED(uint8_t*, delta1, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + TMP_SPACE_MAP_CALL( + prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes(&par.vole_params, par.L)) + TMP_SPACE_MAP_CALL( + prover_cst_mux_circuit_ct_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + TMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + TMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + TMP_SPACE_MAP_CALL( + full_ggm_tree_open_sibling_path_from_root_tmp_bytes(&par.vole_params, par.target_topen) + ); + + // draw a random root seed and global salt (entropy) + memcpy(sign.global_salt, entropy, par.lambda_bytes); + memcpy(root_seed, ((uint8_t*)entropy) + par.lambda_bytes, par.lambda_bytes); + + // -------------------------------------- + // Phase 0: generation of the Vole pairs + // -------------------------------------- + + // generate vole pairs + prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + &par.vole_params, par.L, hash_com, u, v, sign.global_salt, root_seed, tmp_space); + + // transpose vole + // set the last lambda - kappa.tau rows to zero + memset(v + par.kappa * par.tau * par.Lslice, 0, (par.lambda - par.kappa * par.tau) * par.Lslice); + prover_midsize_to_fullsize_std_vole_ct_ref(&par.vole_params, par.L, u, u + par.Lslice, v2, u, v); + // copy the corrective terms to the signature + for (uint64_t i=0; i cchk matrix. + xof_ctx hash_aux_ctx; + par.vole_params.xof.xof_init_and_seed(&hash_aux_ctx, &HASH_AUX_PREFIX, 1); + par.vole_params.xof.xof_seed(&hash_aux_ctx, hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_aux_ctx, sign.corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&hash_aux_ctx, hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&hash_aux_ctx); + + uint8_t* const rvp_u_cchk = u; + uint8_t* const rvp_v_cchk = v2; + const uint64_t num_inputs_padded = (par.num_inputs_pairs + 7) & UINT64_C(-8); + uint8_t* const rvp_u_in = rvp_u_cchk + (par.num_cchk_pairs >> 3); + uint8_t* const rvp_v_in = rvp_v_cchk + (par.num_cchk_pairs * par.lambda_bytes); + uint8_t* const rvp_u_cz = rvp_u_cchk + ((par.num_cchk_pairs + num_inputs_padded) >> 3); + uint8_t* const rvp_v_cz = rvp_v_cchk + ((par.num_cchk_pairs + num_inputs_padded) * par.lambda_bytes); + + // vole consistency check + both_vole_consistency_check_matrix(&par.vole_params, par.L, cchk_matrix, hash_aux, 2 * par.lambda_bytes); + prover_vole_consistency_check(&par.vole_params, par.L, sign.cchk_u, cchk_res_v, u, v2, cchk_matrix); + + // -------------------------------------- + // Phase 1: Build and Commit Witness/Masking polynomials + // -------------------------------------- + + // f2 to flambda + prover_f2_to_flambda_deg1_std_vole_ct_ref(&par.vole_params, par.degree - 1, rvp_f_cz, rvp_u_cz, rvp_v_cz); + // deg1 to degd [in place] + prover_flambda_deg1_to_degd_vole_ref(&par.vole_params, par.degree - 1, rvp_f_cz, rvp_f_cz); + // std to cst: deg d [in place] + prover_flambda_degd_std_to_cst_vole_ct_ref(&par.vole_params, par.degree - 1, rvp_f_cz, rvp_f_cz); + // std to cst: deg 1 [in place] + prover_f2_std_to_cst_vole_ct_ref(&par.vole_params, par.num_inputs_pairs, rvp_u_in, rvp_v_in, rvp_u_in, rvp_v_in); + + // ----- circuit evaluation ------ + // inputs + commit to it + prover_cst_vole_packed_secret_input_ct_ref( // + &par.vole_params, // + par.num_inputs_pairs, // + sign.circuit_in_pub, // publications -> signature + inputs_f, // output vole + sk.skey_encoded_solution, // input secret key bits + rvp_u_in, rvp_v_in); // rvp + + xof_ctx hash_lines_ctx; // round1 + cchk_u + cchk_v + inputs_mask :=> chall + par.vole_params.xof.xof_init_and_seed(&hash_lines_ctx, &HASH_LINES_PREFIX, 1); + par.vole_params.xof.xof_seed(&hash_lines_ctx, hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_lines_ctx, sign.cchk_u, (par.num_cchk_pairs + 7) >> 3); + par.vole_params.xof.xof_seed(&hash_lines_ctx, cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_lines_ctx, sign.circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&hash_lines_ctx, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&hash_lines_ctx); + + // -------------------------------------- + // Phase 3: PIOP protocol (prover side) + // -------------------------------------- + + // generate the batching challenge points + xof_ctx chall_rng; + par.vole_params.xof.xof_init_and_seed(&chall_rng, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_finalize_and_output(&chall_rng, chall_a, par.lambda_bytes * par.rsd_codim_limbs); + par.vole_params.xof.xof_output(&chall_rng, chall_unitary, par.lambda_bytes * par.rsd_w); + par.vole_params.xof.xof_ctx_release(&chall_rng); + + rsd_public_key_times_challenge_ref( // + &par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // + chall_a_H, chall_a_y, // + chall_a, sk.pkey_seed, // + sk.pkey_y, tmp_space); // + + // evaluate the mux trees + memset(res_f, 0, (par.degree + 1) * par.lambda_bytes); + par.vole_params.flambda_set(res_f, chall_a_y); + for (uint64_t i = 0; i < par.rsd_w; i++) { + prover_cst_mux_circuit_ct_ref( // + &par.vole_params, // + par.mux_depth, par.mux_arities, par.rsd_npw, // circuit parameters + mux_f, // mux output + inputs_f + 2 * par.lambda_bytes * par.mux_inputs * i, // secret input bits (bin, deg 1) + chall_a_H + par.lambda_bytes * par.rsd_npw * i, // challenge points (mul by H) + chall_unitary + par.lambda_bytes * i, // check_unitary challenge (depth coeffs) + tmp_space); + prover_cst_vole_xor_gate_ct_ref( // + &par.vole_params, // + res_f, // result + res_f, par.degree, // lhs + mux_f, par.degree); // rhs + } +#ifdef PARANOIA_CHECK + { + // manual verification that res_f is zero + for (uint64_t i = 0; i < par.lambda_bytes; i++) { + CREQUIRE(res_f[i] == 0, "bug! res_f cst term is not zero!"); + } + } +#endif // PARANOIA_CHECK + // checkzero + prover_cst_vole_check_zero_gate_ct_ref( // + &par.vole_params, // + par.degree, // + cz_pub_full, // + res_f, // + rvp_f_cz); // rvp + memcpy(sign.circuit_cz_pub, cz_pub_full + par.lambda_bytes, (par.degree - 1) * par.lambda_bytes); + + xof_ctx hash_piop_ctx; // round3 + check_zero + message :=> delta + par.vole_params.xof.xof_init_and_seed(&hash_piop_ctx, &HASH_PIOP_PREFIX, 1); + par.vole_params.xof.xof_seed(&hash_piop_ctx, sk.pkey_seed, par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, sk.pkey_y, par.rsd_codim_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&hash_piop_ctx, sign.hash_piop, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&hash_piop_ctx); + + // -------------------------------------- + // Phase 3: Open one random evaluation + // -------------------------------------- + + // ----- open delta ------ + // generate delta0 != 0 s.t. topen is good (POW) + uint64_t topen = 1e9; + memset(delta0, 0, par.delta0_capacity); + uint64_t pow_ctr = 0; + par.vole_params.proofow_init(pow_ctx, par.lambda, par.kappa, par.tau, par.proofow_w, sign.hash_piop); + while (1) { + int r = par.vole_params.proofow_grind_w(pow_ctx, delta0, &pow_ctr); + if (!r) abort(); // SIGNATURE FAILED: impossible to do the proofow // TODO return code? + if (bitvec_is_zero_nonct(delta0, par.tau * par.kappa)) continue; // retry + hidden_leaves_indexes2(par.kappa, par.tau, hidden_leaves_idx, delta0); + topen = estimate_topen(par.tau, par.kappa, par.target_topen, hidden_leaves_idx, tmp_space); + if (topen <= par.target_topen) break; // success! + ++pow_ctr; + } + par.vole_params.proofow_release(pow_ctx); + memcpy(sign.proofow_ctr_reveal, &pow_ctr, PROOFOW_CTR_REVEALED_BYTES); + + // generate delta1 + delta1_from_delta0_ref(&par.vole_params, delta1, delta0); + + // generate ggm_opening_data + full_ggm_tree_open_sibling_path_from_root( + &par.vole_params, // params + sign.ggm_sibling_path, // -> signature + sign.ggm_hidden_leaf_cmt, // -> signature + root_seed, sign.global_salt, // salt + hidden_leaves_idx, // indexes of the hidden leaves + topen, // exact size + tmp_space); + // zero-out the unused ggm path + uint8_t* ggm_sibling_path_zero_start = (uint8_t*)sign.ggm_sibling_path + topen * par.lambda_bytes; + memset(ggm_sibling_path_zero_start, 0, (par.target_topen - topen) * par.lambda_bytes); +} + +EXPORT uint64_t sdith_verify_tmp_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_aux, 32, + 2 * par.lambda_bytes); // ggm_cmt_hash + corr_terms :=> cchk matrix + COMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_lines, 32, + 2 * par.lambda_bytes); // round1 + cchk_u + cchk_v + inputs_mask :=> chall + COMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_piop, 32, + 2 * par.lambda_bytes); // round3 + check_zero + message :=> delta + COMP_SPACE_MAP_ALIGNED(uint32_t*, verif_hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + COMP_SPACE_MAP(uint8_t*, verif_delta0, par.delta0_capacity); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta1, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2_dm1, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_corr, 32, par.Lslice* par.tau); + COMP_SPACE_MAP_ALIGNED(uint8_t*, q, 32, par.Lslice* par.lambda); + COMP_SPACE_MAP_ALIGNED(uint8_t*, q2, 32, par.Lslice* par.lambda); // copy needed during transposition + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_hash_com, 32, + 2 * par.lambda_bytes); // ggm commitment hash (verify against the signature) + COMP_SPACE_MAP(uint8_t*, verif_cchk_matrix, par.Lbyte* par.num_cchk_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_cchk_res_v, 32, par.lambda_bytes* par.num_cchk_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_q, 32, par.lambda_bytes* par.num_inputs_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_unitary, 32, par.lambda_bytes* par.rsd_w); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_H, 32, par.lambda_bytes* par.rsd_n); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_y, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_q, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, res_q, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + COMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + COMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + COMP_SPACE_MAP_CALL(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( + &par.vole_params, par.L, par.target_topen) // number of pairs to generate + ); + COMP_SPACE_MAP_CALL( + verifier_cst_mux_circuit_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + COMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + COMP_SPACE_RETURN(); +} + +#define VERIFY_OR_FAIL(condition, error_message) \ + if (!(condition)) { \ + return 0; \ + } +#define VERIFY_SUCCESS() return 1 + +EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + const void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* pkey, // secret key + uint8_t* tmp_space) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + // public key + const pkey_mapping_t pk = map_public_key(&par, pkey); + + // signature fields + const signature_mapping_t sign = map_signature(&par, signature); + + // local variables + TMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_aux, 32, + 2 * par.lambda_bytes); // ggm_cmt_hash + corr_terms :=> cchk matrix + TMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_lines, 32, + 2 * par.lambda_bytes); // round1 + cchk_u + cchk_v + inputs_mask :=> chall + TMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_piop, 32, 2 * par.lambda_bytes); // round3 + check_zero + message :=> delta + TMP_SPACE_MAP_ALIGNED(uint32_t*, verif_hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + TMP_SPACE_MAP(uint8_t*, verif_delta0, par.delta0_capacity); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta1, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2_dm1, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_corr, 32, par.Lslice* par.tau); + TMP_SPACE_MAP_ALIGNED(uint8_t*, q, 32, par.Lslice* par.lambda); + TMP_SPACE_MAP_ALIGNED(uint8_t*, q2, 32, par.Lslice* par.lambda); // copy needed during transposition + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_hash_com, 32, + 2 * par.lambda_bytes); // ggm commitment hash (verify against the signature) + TMP_SPACE_MAP(uint8_t*, verif_cchk_matrix, par.Lbyte* par.num_cchk_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_cchk_res_v, 32, par.lambda_bytes* par.num_cchk_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_q, 32, par.lambda_bytes* par.num_inputs_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_unitary, 32, par.lambda_bytes* par.rsd_w); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_H, 32, par.lambda_bytes* par.rsd_n); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_y, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_q, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, res_q, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + TMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + TMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + TMP_SPACE_MAP_CALL(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( + &par.vole_params, par.L, par.target_topen) // number of pairs to generate + ); + TMP_SPACE_MAP_CALL( + verifier_cst_mux_circuit_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + TMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)) + + // verifier side + uint64_t leftover_bits = par.num_inputs_pairs & 7; + if (leftover_bits) { + uint64_t mask = ((1 << (8 - leftover_bits)) - 1) << leftover_bits; + uint64_t idx = ((par.num_inputs_pairs + 7) >> 3) - 1; + VERIFY_OR_FAIL((sign.circuit_in_pub[idx] & mask) == 0, "in_publications does not have trailing zeros"); + } + + // -------------------------------------- + // Phase 1: Recompute and check the evaluation + // -------------------------------------- + + // ----- open delta ------ + // generate delta0 != 0 s.t. topen is good (POW) + uint64_t topen = 1e9; + uint64_t proof_of_work_counter = 0; + memset(verif_delta0, 0, par.delta0_capacity); + memcpy(&proof_of_work_counter, sign.proofow_ctr_reveal, PROOFOW_CTR_REVEALED_BYTES); // load the golden counter + par.vole_params.proofow_init(pow_ctx, par.lambda, par.kappa, par.tau, par.proofow_w, sign.hash_piop); + int r = par.vole_params.proofow_verify_w(pow_ctx, verif_delta0, proof_of_work_counter); + par.vole_params.proofow_release(pow_ctx); + VERIFY_OR_FAIL(r, "invalid proof of work: vgrind"); + VERIFY_OR_FAIL(!bitvec_is_zero_nonct(verif_delta0, par.tau * par.kappa), "invalid proof of work: zero"); + hidden_leaves_indexes2(par.kappa, par.tau, verif_hidden_leaves_idx, verif_delta0); + topen = estimate_topen(par.tau, par.kappa, par.target_topen, verif_hidden_leaves_idx, tmp_space); + VERIFY_OR_FAIL(topen <= par.target_topen, "invalid proof of work: topen"); + + // check that the sibling path has trailing zeroes (if needed) + { + uint64_t zero_values = par.target_topen - topen; + uint8_t* ggm_sibling_path_zero_start = (uint8_t*)sign.ggm_sibling_path + topen * par.lambda_bytes; + // bitvec_is_zero_nonct counts BITS, so scale the byte length by 8. Without the + // *8 only 1/8 of the zeroed tail was checked, leaving the rest malleable. + VERIFY_OR_FAIL(bitvec_is_zero_nonct(ggm_sibling_path_zero_start, zero_values * par.lambda_bytes * 8), + "sibling path cleanliness"); + } + // generate delta1 and delta2 + delta1_from_delta0_ref(&par.vole_params, verif_delta1, verif_delta0); + delta2_from_delta1_ref(&par.vole_params, verif_delta2, verif_delta1); + + // From Vole perspective, the evaluation point is Delta1 (Delta0 is blockwise, the Grey code of Delta1) + // Vole protocol reconstructs pairs evaluated in Delta1. + + // generate vole pairs + memset(verif_corr, 0, par.Lslice * par.tau); + for (uint64_t i = 0; i < par.tau - 1; i++) { + memcpy(verif_corr + (i+1) * par.Lslice, sign.corr_u + i * par.Lbyte, par.Lbyte); + } + verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + &par.vole_params, par.L, // dimensions + verif_hash_com, // [out] hash of the leaves commits + q, // [out] TAU x KAPPA x L row major + verif_corr, // [in/out] TAU x L bits + verif_hidden_leaves_idx, // [in] TAU indices of the hidden (node) leaves + sign.ggm_hidden_leaf_cmt, // [in] TAU commits of the hidden (node) leaves + sign.ggm_sibling_path, // [in] Topen sibling seeds + topen, // [in] number of sibling seeds + sign.global_salt, // [in] global salt for the GGM tree + verif_delta1, // verifier's point delta1 + tmp_space); + + // then we reconvert these vole pairs into PIOP material. + // From PIOP perspective, the verifier gets the evaluation in Delta2 (qhich is the inverse of Delta1) + + // ----- vole preprocessing ------ + // transpose vole + memset(q + par.kappa * par.tau * par.Lslice, 0, (par.lambda - par.kappa * par.tau) * par.Lslice); + verifier_midsize_to_fullsize_std_vole_ref(&par.vole_params, par.L, q2, q); + + uint8_t* const rvp_q_cchk = q2; + const uint64_t num_inputs_padded_v = (par.num_inputs_pairs + 7) & UINT64_C(-8); + uint8_t* const rvp_q_in = rvp_q_cchk + (par.num_cchk_pairs * par.lambda_bytes); + uint8_t* const rvp_q_cz = rvp_q_cchk + ((par.num_cchk_pairs + num_inputs_padded_v) * par.lambda_bytes); + + // round 1 hash: prefix, hash_com(ggm), corr_terms :=> cchk matrix. + xof_ctx verif_hash_aux_ctx; + par.vole_params.xof.xof_init_and_seed(&verif_hash_aux_ctx, &HASH_AUX_PREFIX, 1); + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, verif_hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, sign.corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_aux_ctx, verif_hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&verif_hash_aux_ctx); + + // vole consistency check + both_vole_consistency_check_matrix(&par.vole_params, par.L, verif_cchk_matrix, verif_hash_aux, 2 * par.lambda_bytes); + verifier_vole_consistency_check(&par.vole_params, par.L, verif_cchk_res_v, sign.cchk_u, q2, verif_cchk_matrix, + verif_delta1); + + xof_ctx verif_hash_lines_ctx; // round1 + cchk_u + cchk_v + inputs_mask :=> chall + par.vole_params.xof.xof_init_and_seed(&verif_hash_lines_ctx, &HASH_LINES_PREFIX, 1); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, verif_hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, sign.cchk_u, (par.num_cchk_pairs + 7) >> 3); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, verif_cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, sign.circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_lines_ctx, verif_hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&verif_hash_lines_ctx); + + // -------------------------------------- + // PIOP Protocol (verifier's side) + // -------------------------------------- + // At this point, delta2 is the only point that matters: the verifier will check + // the PIOP circuit evaluated on delta2. + + // f2 to flambda + verifier_f2_to_flambda_deg1_std_vole_ref(&par.vole_params, par.degree - 1, rvp_q_cz, rvp_q_cz); + // deg1 to degd [in place] + verifier_flambda_deg1_to_degd_vole_ref(&par.vole_params, par.degree - 1, rvp_q_cz, rvp_q_cz, verif_delta1); + // std to cst: deg d [in place] + flambda_power(&par.vole_params, verif_delta2_dm1, verif_delta2, par.degree - 1); + verifier_flambda_degd_std_to_cst_vole_ref(&par.vole_params, par.degree - 1, rvp_q_cz, rvp_q_cz, verif_delta2_dm1); + // std to cst: deg 1 [in place] + verifier_f2_std_to_cst_vole_ref(&par.vole_params, par.num_inputs_pairs, rvp_q_in, rvp_q_in, verif_delta2); + + // ----- circuit evaluation ------ + // inputs + commit to it + verifier_cst_vole_packed_secret_input_ref( // + &par.vole_params, // + par.num_inputs_pairs, // + inputs_q, + sign.circuit_in_pub, // publications -> signature + rvp_q_in, + verif_delta2); // rvp + + // reconstruct the batching challenge points + xof_ctx verif_chall_rng; + par.vole_params.xof.xof_init_and_seed(&verif_chall_rng, verif_hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_finalize_and_output(&verif_chall_rng, verif_chall_a, par.lambda_bytes * par.rsd_codim_limbs); + // note: the chall unitary are only needed if the mux tree contains one non-binary arity + par.vole_params.xof.xof_output(&verif_chall_rng, verif_chall_unitary, par.lambda_bytes * par.rsd_w); + par.vole_params.xof.xof_ctx_release(&verif_chall_rng); + + rsd_public_key_times_challenge_ref(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // + verif_chall_a_H, verif_chall_a_y, // + verif_chall_a, pk.pkey_seed, pk.pkey_y, tmp_space); + par.vole_params.flambda_set(res_q, verif_chall_a_y); + for (uint64_t i = 0; i < par.rsd_w; i++) { + verifier_cst_mux_circuit_ref( // + &par.vole_params, // + par.mux_depth, par.mux_arities, par.rsd_npw, // circuit parameters + mux_q, // mux output + inputs_q + par.lambda_bytes * par.mux_inputs * i, // secret input bits (bin, deg 1) + verif_chall_a_H + par.lambda_bytes * par.rsd_npw * i, // challenge points (mul by H) + verif_chall_unitary + par.lambda_bytes * i, // check_unitary challenge (depth coeffs) + verif_delta2, tmp_space); + verifier_cst_vole_xor_gate_ref( // + &par.vole_params, // + res_q, // result + res_q, par.degree, // lhs + mux_q, par.degree, // rhs + verif_delta2); + } + + // checkzero: reconstruct alpha_1 from alpha_2..alpha_d + VOLE evaluations + { + const uint64_t lb = par.lambda_bytes; + // partial is an operand of flambda_product/flambda_sum, so it needs the 32-byte + // alignment the gf256 backend loads it with (flambda_max_t provides it). + flambda_max_t partial; + memcpy(partial, sign.circuit_cz_pub + (par.degree - 2) * lb, lb); + for (int64_t i = par.degree - 3; i >= 0; i--) { + par.vole_params.flambda_product(partial, partial, verif_delta2); + flambda_max_t tmp; + memcpy(tmp, sign.circuit_cz_pub + i * lb, lb); + par.vole_params.flambda_sum(partial, partial, tmp); + } + par.vole_params.flambda_product(partial, partial, verif_delta2); + par.vole_params.flambda_sum(partial, partial, rvp_q_cz); + flambda_max_t rq_dinv; + par.vole_params.flambda_product(rq_dinv, res_q, verif_delta1); + par.vole_params.flambda_sum(partial, partial, rq_dinv); + memcpy(cz_pub_full, partial, lb); + memcpy(cz_pub_full + lb, sign.circuit_cz_pub, (par.degree - 1) * lb); + + // alpha_1 is not transmitted: hash the reconstructed alpha_1..alpha_d into + // h_piop and compare against the signature. This is the only acceptance test. + xof_ctx verif_hash_piop_ctx; + par.vole_params.xof.xof_init_and_seed(&verif_hash_piop_ctx, &HASH_PIOP_PREFIX, 1); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, pk.pkey_seed, par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, pk.pkey_y, par.rsd_codim_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, verif_hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_piop_ctx, verif_hash_piop, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&verif_hash_piop_ctx); + VERIFY_OR_FAIL(memcmp(verif_hash_piop, sign.hash_piop, 2 * par.lambda_bytes) == 0, "invalid hash_piop"); + } + + VERIFY_SUCCESS(); +} diff --git a/src/sig/sdith/sdith_sdith_common/sdith_signature.h b/src/sig/sdith/sdith_sdith_common/sdith_signature.h new file mode 100644 index 0000000000..59b6e51801 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_signature.h @@ -0,0 +1,132 @@ +#ifndef SDITH_SIGNATURE_H +#define SDITH_SIGNATURE_H + +// This header contains the main SDiTH signature + +#include "commons.h" + +/** signature main parameters */ +typedef struct signature_parameters_t { + uint64_t lambda; + uint64_t kappa; + uint64_t tau; + uint64_t target_topen; + uint64_t proofow_w; + uint64_t rsd_w; + uint64_t rsd_n; + uint64_t mux_depth; + uint64_t mux_arities[8]; + proofow_variant_t proofow_variant; +} signature_parameters; + +/** Default parameter sets */ +EXPORT_DECL const signature_parameters CAT1_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT1_FAST_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_FAST_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_FAST_PARAMETERS; +/** Default parameter sets for official variants */ +EXPORT_DECL const signature_parameters CAT1_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT1_FAST_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_FAST_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_FAST_CIPHERPOW_PARAMETERS; + +/** @brief Number of bytes of the secret key (in the sense keypair) */ +EXPORT uint64_t sdith_secret_key_bytes(const signature_parameters* sig_params); +/** @brief Number of bytes of the public key */ +EXPORT uint64_t sdith_public_key_bytes(const signature_parameters* sig_params); +/** @brief Number of bytes of a sdith signature */ +EXPORT uint64_t sdith_signature_bytes(const signature_parameters* sig_params); + +/** + * @brief Number of pure entropy bytes to provide to the keygen algorithm + * These bytes should be generated using a secure random generator, a random device, or something like /dev/urandom. + * During tests purposes, fixing the entropy makes the algorithm deterministic + */ +EXPORT uint64_t sdith_keygen_entropy_bytes(const signature_parameters* sig_params); + +/** + * @brief size of the scratch space to pass to the keygen function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_keygen_tmp_bytes(const signature_parameters* sig_params); + +/** + * @brief SDiTH Key generator + * @param sig_params parameter set + * @param skey [out] secret key (i.e. keypair) + * @param pkey [out] public key (i.e. keypair) + * @param entropy [in] entropy bytes + * @param tmp_space [tmp] scratch space -- holds secret key material on + * return (the raw solution): the caller must scrub it. + * + * Constant-time with respect to the generated secret key, save for the + * rejection loop of the position sampler (whose trip count is independent of + * the accepted positions). This holds only for the avx parameter table: the ref + * ct helpers are the readable definitions, not hardened ones. + */ +EXPORT void sdith_keygen(const signature_parameters* sig_params, // + void* skey, // out: secret key + void* pkey, // out: public key + const void* entropy, // in: entropy + uint8_t* tmp_space); + +/** + * @brief Number of pure entropy bytes to provide to the signature algorithm + * These bytes should be generated using a secure random generator, a random device, or something like /dev/urandom. + * During tests purposes, fixing the entropy makes the algorithm deterministic + */ +EXPORT uint64_t sdith_signature_entropy_bytes(const signature_parameters* sig_params); + +/** + * @brief size of the scratch space to pass to the signature function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_signature_tmp_bytes(const signature_parameters* sig_params); + +/** + * SDiTH signature + * @param sig_params parameter set + * @param signature [out] digital signature + * @param message [in] message to sign + * @param message_bytes [in] number of bytes of the message + * @param skey [in] secret key + * @param entropy [in] entropy bytes + * @param tmp_space [tmp] scratch space + */ +EXPORT void sdith_sign(const signature_parameters* sig_params, // + void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* skey, // secret key + const void* entropy, // in: entropy + uint8_t* tmp_space); + +/** + * @brief size of the scratch space to pass to the signature function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_verify_tmp_bytes(const signature_parameters* sig_params); + +/** + * Signature verification function + * @param sig_params SDiTH parameter set + * @param signature [in] signature to verify + * @param message [in] message that was signed + * @param message_bytes [in] size of the message + * @param pkey [in] public key + * @param tmp_space [tmp] scratch space + * @return + */ +EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + const void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* pkey, // secret key + uint8_t* tmp_space); + +#endif // SDITH_SIGNATURE_H diff --git a/src/sig/sdith/sdith_sdith_common/sdith_signature_parameters.c b/src/sig/sdith/sdith_sdith_common/sdith_signature_parameters.c new file mode 100644 index 0000000000..e0b59ce299 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_signature_parameters.c @@ -0,0 +1,176 @@ +#include "sdith_signature.h" + +const signature_parameters CAT1_SHORT_PARAMETERS = { + // + .lambda = 128, // + .kappa = 11, // + .tau = 11, // + .target_topen = 109, // + .proofow_w = 9, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT3_SHORT_PARAMETERS = { + // + .lambda = 192, // + .kappa = 11, // + .tau = 17, // + .target_topen = 169, // + .proofow_w = 7, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // + }; + +const signature_parameters CAT5_SHORT_PARAMETERS = { + // + .lambda = 256, // + .kappa = 11, // + .tau = 23, // + .target_topen = 228, // + .proofow_w = 5, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT1_FAST_PARAMETERS = { + // + .lambda = 128, // + .kappa = 7, // + .tau = 18, // + .target_topen = 107, // + .proofow_w = 4, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT3_FAST_PARAMETERS = { + // + .lambda = 192, // + .kappa = 7, // + .tau = 27, // + .target_topen = 161, // + .proofow_w = 5, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT5_FAST_PARAMETERS = { + // + .lambda = 256, // + .kappa = 7, // + .tau = 36, // + .target_topen = 216, // + .proofow_w = 6, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +// The cipher-grinding variants. kappa and the RSD parameters are shared with +// the base set (so pk and sk are identical), but do NOT just copy the base set +// and flip the variant: in round 3, cat1-fast and cat3-fast use their own tau, +// target_topen and proofow_w (see the specs, tab:params-voleith-aespow). The +// short sets and cat5-fast keep the base values, so only the variant differs +// for those. + +const signature_parameters CAT1_SHORT_CIPHERPOW_PARAMETERS = { + // + .lambda = 128, // + .kappa = 11, // + .tau = 11, // + .target_topen = 109, // + .proofow_w = 9, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT3_SHORT_CIPHERPOW_PARAMETERS = { + // + .lambda = 192, // + .kappa = 11, // + .tau = 17, // + .target_topen = 169, // + .proofow_w = 7, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // + }; + +const signature_parameters CAT5_SHORT_CIPHERPOW_PARAMETERS = { + // + .lambda = 256, // + .kappa = 11, // + .tau = 23, // + .target_topen = 228, // + .proofow_w = 5, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT1_FAST_CIPHERPOW_PARAMETERS = { + // + .lambda = 128, // + .kappa = 7, // + .tau = 17, // + .target_topen = 101, // + .proofow_w = 11, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT3_FAST_CIPHERPOW_PARAMETERS = { + // + .lambda = 192, // + .kappa = 7, // + .tau = 26, // + .target_topen = 155, // + .proofow_w = 12, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT5_FAST_CIPHERPOW_PARAMETERS = { + // + .lambda = 256, // + .kappa = 7, // + .tau = 36, // + .target_topen = 216, // + .proofow_w = 6, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; diff --git a/src/sig/sdith/sdith_sdith_common/sdith_vole_to_piop.h b/src/sig/sdith/sdith_sdith_common/sdith_vole_to_piop.h new file mode 100644 index 0000000000..7f5d6b60bd --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/sdith_vole_to_piop.h @@ -0,0 +1,88 @@ +#ifndef SDITH_VOLE_TO_PIOP_H +#define SDITH_VOLE_TO_PIOP_H + +// This header contains the functions used to convert vole pairs into piop pairs +// For each step of the conversion, there is a prover side and a verifier's side function. + +#include "vole_parameters.h" + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void prover_f2_to_flambda_deg1_std_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + fpoly_t* out_f, // [out] deg-1 fpoly[num_pairs] + const bitvec_t* in_u, // [in] in_L bits where in_L = num_pairs * LAMBDA + const flambda_t* in_v); // [in] flambda[in_L] + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void verifier_f2_to_flambda_deg1_std_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + flambda_t* out_q, // [out] gflambda[num_pairs] + const flambda_t* in_q); // [in] gflambda in_q[in_L] where in_L = num_pairs * LAMBDA + +/** + * @brief convert packed degree 1 std-vole to packed cst-vole + * (Prover side is just the identity function) + */ +EXPORT void prover_f2_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + bitvec_t* out_u, flambda_t* out_v, // [out] bit[num_pairs], flambda[num_pairs] + const bitvec_t* in_u, const flambda_t* in_v); // [in] bit[num_pairs], flambda[num_pairs] + +/** + * @brief convert packed degree 1 std-vole to packed cst-vole + */ +EXPORT void verifier_f2_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + flambda_t* out_q, // [in] gflambda[num_pairs] + const flambda_t* in_q, // [in] gflambda[num_pairs] + const flambda_t* delta2); // [in] verifier's point + +/** + * convert d degree 1 std-vole over flambda to one degree-d vole + */ +EXPORT void prover_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + fpoly_t* out_f, // single poly_t of degree out_degree + const fpoly_t* in_f); // out_degree poly[out_degree] + +/** + * convert d degree 1 std-vole to one degree-d vole + */ +EXPORT void verifier_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + flambda_t* out_q, // [out] single gflambda + const flambda_t* in_q, // [in] gflambda[out_deg] + const flambda_t* delta_powers); // verifier's point powers + +/** + * convert a degree-d vole from std to cst + */ +EXPORT void prover_flambda_degd_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // degree d of of the pair to process + fpoly_t* out_f, // [out] single poly of degree d + const fpoly_t* in_f); // [in] single poly of degree d + +/** + * convert a degree-d vole from std to cst + */ +EXPORT void verifier_flambda_degd_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // output degree + flambda_t* out_q, // [out] single evaluation + const flambda_t* in_q, // [in] single evaluation + const flambda_t* delta_pow_d); // [in] verifier's point to the power d + +#endif // SDITH_VOLE_TO_PIOP_H diff --git a/src/sig/sdith/sdith_sdith_common/vole_expansion.c b/src/sig/sdith/sdith_sdith_common/vole_expansion.c new file mode 100644 index 0000000000..eb49506cef --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/vole_expansion.c @@ -0,0 +1,873 @@ +#include +#include + +#include "ggm.h" +#include "sdith_prng.h" +#include "vole_private.h" + +#ifndef SDITH3_FOR_LIBOQS +#include "KeccakSpongetimes4.h" +#endif + +#ifndef NDEBUG +#define MSTACK_DEF(bytelen) \ + uint8_t stack_var[bytelen] __attribute((aligned(32))); \ + uint8_t* stack_cur = stack_var; \ + uint8_t* const stack_end = stack_var + bytelen + +#define MSTACK_ALLOC(bytelen) \ + (void*)stack_cur; \ + stack_cur += bytelen; \ + CREQUIRE(stack_cur <= stack_end, "manual stack overflow!!") +#else +#define MSTACK_DEF(bytelen) \ + uint8_t stack_var[bytelen] __attribute((aligned(32))); \ + uint8_t* stack_cur = stack_var + +#define MSTACK_ALLOC(bytelen) \ + (void*)stack_cur; \ + stack_cur += bytelen +#endif + +#ifndef SDITH3_FOR_LIBOQS +// these don't appear to be used here at all, so no corresponding liboqs implimentaion is added +#define BATCH_XOF_STRIDE (((sizeof(KeccakWidth1600times4_SpongeInstance) + 31) / 32) * 32) +#define BATCH_XOF(base, idx) ((KeccakWidth1600times4_SpongeInstance*)((uint8_t*)(base) + (idx) * BATCH_XOF_STRIDE)) +#endif + +/** @brief converts delta0 to delta1 + * delta0 has kappa*tau bits, encoding tau grey code encodings + * delta1 has lambda bits, only the lowest kappa*tau are used, the rest is zero. + */ +EXPORT void delta1_from_delta0_ref(const vole_parameters* vole_params, flambda_t* delta1, const bitvec_t* delta0) { + // bit_vector delta1_from_delta0(uint64_t kappa, uint64_t tau, uint64_t lambda, const bit_vector& delta0) { + const uint64_t kappa = vole_params->KAPPA; + const uint64_t tau = vole_params->TAU; + CASSERT(vole_params->LAMBDA >= tau * kappa, "invalid lambda"); + CASSERT(tau * kappa > 0, "invalid kappa, tau"); + CASSERT(delta0 != delta1, "in_place not supported"); + memset(delta1, 0, vole_params->lambda_bytes); + for (uint64_t i = 0; i < tau; i++) { + uint64_t pos = extract_kappabit_uint(kappa, i * kappa, delta0); + xorto_kappabit_uint(kappa, i * kappa, delta1, pos ^ (pos >> 1)); + } +} + +/** + * number of tmp bytes needed by the function + */ +EXPORT uint64_t prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L // number of pairs to generate [Lslice next mult of 32] +) { + const uint64_t Lbytesx = L >> 3; + const uint64_t Lslice = (Lbytesx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + //const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + //const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + //const uint64_t nleaves = UINT64_C(1) << KAPPA; + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + // tree representation + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + COMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + COMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + COMP_SPACE_MAP_ALIGNED(bitvec_t**, uu, 8, TAU * sizeof(bitvec_t*)); + COMP_SPACE_MAP_ALIGNED(bitmat_t**, vv, 8, TAU * sizeof(bitmat_t*)); + COMP_SPACE_RETURN(); +} + + +/** + * Generate L vole pairs over (F2,F2^KAPPA) (grey code + BFS version) + * @param u (output): L bits: Xor of all ri's, + * @param v (output): matrix KAPPA x L bits: Xor of ri.grey(i) + */ +EXPORT void prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate [Lslice next mult of 32] + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* u, // [out] TAU x (L bits on Lslice bytes) + bitmat_t* v, // [out] TAU x KAPPA x (L bits on Lslice bytes) row major + const salt_t* global_salt, // [in] global salt for the GGM tree + const seed_t* ggm_root_seed, // [in] root seed for the GGM tree + uint8_t* tmp_space) // [tmp] scratch space +{ + const uint64_t Lbytesx = L >> 3; + const uint64_t Lslice = (Lbytesx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t nleaves = UINT64_C(1) << KAPPA; + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + // tree representation + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + TMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + TMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + TMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + TMP_SPACE_MAP_ALIGNED(bitvec_t**, uu, 8, TAU * sizeof(bitvec_t*)); + TMP_SPACE_MAP_ALIGNED(bitmat_t**, vv, 8, TAU * sizeof(bitmat_t*)); + // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) + vole_params->prepare_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + // the two domain-separated salts: one for the GGM tree, one for the vole rng + uint64_t* const ggm_masked_salt = masked_salts; + uint64_t* const vole_masked_salt = masked_salts + (SEED_BYTES >> 3); + compute_tweaked_salts(vole_params, ggm_masked_salt, vole_masked_salt, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); + for (uint64_t i = 0; i < TAU; ++i) { // some handy double pointers for vole + uu[i] = u + i * Lslice; + vv[i] = v + i * KAPPA * Lslice; + } + for (uint64_t i = 0; i < TAU; ++i) { // some handy double pointers for xofs + commit_ptrs[i] = commit_buffer + i * COMMIT_BYTES; + } + uint8_t* const subhashes = commit_buffer; // we will share that space since the subhash size is 2lambda + uint8_t** const subhashes_ptrs = commit_ptrs; + + // memcpy the root of the tree + memcpy(seeds + SEED_BYTES, ggm_root_seed, SEED_BYTES); + + // expand all the seeds using the seed_rng + uint64_t next_node_idx = 2; // also equal to the num leaves to write at that depth + const uint8_t* rd_ptr = seeds + SEED_BYTES; // root position (node_id = 1) + uint8_t* wr_ptr = seeds + 2 * SEED_BYTES; // left child (node_id=2) + // expand the first two depths of the tree one by one + while (next_node_idx < 8) { + vole_params->extend_leaf_seed(ext_seeds, rd_ptr); + vole_params->ggm_extseed_rng_lr(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 2 * SEED_BYTES; + rd_ptr += SEED_BYTES; + next_node_idx += 2; + } + // expand the rest of the depths 4x by 4x + while (next_node_idx <= TOTAL_NODES) { + vole_params->extend_leaf_seed_4x(ext_seeds, rd_ptr); + // I8: expand the 4 sibling parents (node_idx, +2, +4, +6) in one call. The cat1 avx2 + // build batches them into one 8-block encrypt; the other builds do four single calls. + vole_params->ggm_extseed_rng_lr_x4(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 8 * SEED_BYTES; + rd_ptr += 4 * SEED_BYTES; + next_node_idx += 8; + } + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have filled the tree"); + + // expand all the leaf seeds into commit and vole randomness + memset(u, 0, TAU * Lslice); + memset(v, 0, TAU * KAPPA * Lslice); + vole_params->xof_vector.init_and_seed(commit_xofs, TAU, &HASH_BAVC_PREFIX, 1); + + uint64_t l = 0; + next_node_idx = TOTAL_LEAVES; + const uint8_t* next_leaf_seed = seeds + TOTAL_LEAVES * SEED_BYTES; // ptr of the first leaf seed + const uint8_t* const end_leaf_seed = seeds + (TOTAL_NODES + 1) * SEED_BYTES; + while (next_leaf_seed < end_leaf_seed) { + // expand 4 * TAU leaf seeds and advance the read pointer + uint8_t* out_ext_seed = ext_seeds; + for (uint64_t i = 0; i < TAU; ++i) { + // expand the leaf seed -> expanded buffer + vole_params->extend_leaf_seed_4x(out_ext_seed, // output + next_leaf_seed // leaf seed + ); + next_leaf_seed += 4 * LAMBDA_BYTES; + out_ext_seed += 4 * EXT_BYTES; + } + CASSERT(out_ext_seed == ext_seeds + 4 * TAU * EXT_BYTES, "out_ext_seed should be at the end of the buffer"); + + // process the 4 * TAU expanded leaves (it corresponds to 4 positions) + const uint8_t* in_expanded_seed = ext_seeds; + for (uint64_t nb = 0; nb < 4; ++nb) { + const uint64_t loc = (l + 1 < nleaves) ? binval_of(l + 1) : KAPPA - 1; + const uint64_t loc_offset = loc * Lslice; + uint8_t* out_commit = commit_buffer; + for (uint64_t i = 0; i < TAU; ++i) { + // compute the commit and add it to the commit buffer + vole_params->ggm_extseed_rng_commit(out_commit, // out + ggm_masked_salt, // salt + in_expanded_seed, // expanded_seed + next_node_idx // node_idx + ); + // compute the vole_rng and process it + vole_params->vole_extseed_rng(tmp_r, Lslice, // out (only Lbytes would suffice here) + vole_masked_salt, // salt + in_expanded_seed, // expanded_seed + i); // repetition index + vole_params->bitvec_cascade_xor_to(Lslice, vv[i] + loc_offset, uu[i], tmp_r); + // advance pointers + in_expanded_seed += EXT_BYTES; + out_commit += COMMIT_BYTES; + next_node_idx += 1; + } + // hash the commits + vole_params->xof_vector.seed(commit_xofs, TAU, commit_ptrs, COMMIT_BYTES); + // advance the pointers + ++l; + } + CASSERT(in_expanded_seed == ext_seeds + 4 * TAU * EXT_BYTES, "we should have consumed all the expanded seeds"); + } + CASSERT(l == nleaves, "we should have processed all the leaves"); + CASSERT(next_leaf_seed == end_leaf_seed, "we should have processed all the leaves"); + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have processed all the leaves"); + + // now, hash the per-rep subhashes into the final commits hash: + // commits_hash = H(HASH_BAVC_PREFIX, global_salt, subhashes). the full salt is + // bound first (it commits all lambda bits, whereas the tweaked salts drop the + // low GGM_TWEAK_BITS and the top prefix bits), then the per-rep subhashes. + vole_params->xof_vector.finalize_and_output(commit_xofs, TAU, subhashes_ptrs, 2 * LAMBDA_BYTES); + vole_params->xof_vector.ctx_release(commit_xofs, TAU); + xof_ctx commits_xof; + vole_params->xof.xof_init_and_seed(&commits_xof, &HASH_BAVC_PREFIX, 1); + vole_params->xof.xof_seed(&commits_xof, global_salt, LAMBDA_BYTES); + vole_params->xof.xof_seed(&commits_xof, subhashes, 2 * TAU * LAMBDA_BYTES); + vole_params->xof.xof_finalize_and_output(&commits_xof, commits_hash, 2 * LAMBDA_BYTES); + vole_params->xof.xof_ctx_release(&commits_xof); + + // release any per-slot state the ext_seed backend cached (no-op unless the + // liboqs aes128 backend is in use) + vole_params->release_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); +} + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) -- tmp bytes needed + */ +EXPORT uint64_t verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + uint64_t topen // (max) size of the sibling path + ) { + const uint64_t Lbytesxx = L >> 3; + const uint64_t Lslice = (Lbytesxx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + COMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + COMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + COMP_SPACE_MAP_ALIGNED(bitvec_t**, ss, 8, TAU * sizeof(bitvec_t*)); + COMP_SPACE_MAP_ALIGNED(bitmat_t**, qq, 8, TAU * sizeof(bitmat_t*)); + COMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_nodes_idx, 8, (2 * TAU + topen + 1) * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(uint32_t*, sibling_nodes_idx, 8, (topen + 1) * sizeof(uint32_t)); + COMP_SPACE_RETURN(); +} + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) + */ +EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* q, // [out] TAU x KAPPA x L row major + bitmat_t* coor_terms, // [in/out] TAU x L bits + const uint32_t* hidden_leaves_idx, // [in] TAU indices of the hidden (node) leaves + const commit_t* hidden_leaves_commit, // [in] TAU commits of the hidden (node) leaves + const seed_t* sibling_seeds, // [in] Topen sibling seeds + const uint64_t topen, // [in] number of sibling seeds + const salt_t* global_salt, // [in] global salt for the GGM tree + const flambda_t* delta1, // verifier's point delta1 + uint8_t* tmp_space) { + const uint64_t Lbytesxx = L >> 3; + const uint64_t Lslice = (Lbytesxx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + const uint64_t nleaves = UINT64_C(1) << KAPPA; + + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + TMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + TMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + TMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + TMP_SPACE_MAP_ALIGNED(bitvec_t**, ss, 8, TAU * sizeof(bitvec_t*)); + TMP_SPACE_MAP_ALIGNED(bitmat_t**, qq, 8, TAU * sizeof(bitmat_t*)); + TMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_nodes_idx, 8, (2 * TAU + topen + 1) * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint32_t*, sibling_nodes_idx, 8, (topen + 1) * sizeof(uint32_t)); + // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) + vole_params->prepare_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + // the two domain-separated salts: one for the GGM tree, one for the vole rng + uint64_t* const ggm_masked_salt = masked_salts; + uint64_t* const vole_masked_salt = masked_salts + (SEED_BYTES >> 3); + compute_tweaked_salts(vole_params, ggm_masked_salt, vole_masked_salt, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); + for (uint64_t i = 0; i < TAU; ++i) { + qq[i] = ((uint8_t*)q) + i * KAPPA * Lslice; + ss[i] = ((uint8_t*)coor_terms) + i * Lslice; + } + for (uint64_t i = 0; i < TAU; ++i) { // some handy double pointers for xofs + commit_ptrs[i] = commit_buffer + i * COMMIT_BYTES; + } + uint8_t* const subhashes = commit_buffer; // we will share that space since the subhash size is 2lambda + uint8_t** const subhashes_ptrs = commit_ptrs; + + // step 1: compute the sibling node indexes +#ifndef NDEBUG + uint32_t num_leaves = TAU << KAPPA; + for (uint32_t i = 0; i < TAU - 1; ++i) { + CREQUIRE(hidden_leaves_idx[i] < hidden_leaves_idx[i + 1], "leave nodes not ordered"); + } + CREQUIRE(hidden_leaves_idx[0] >= num_leaves, "incorrect leave node index"); + CREQUIRE(hidden_leaves_idx[TAU - 1] < 2 * num_leaves, "incorrect leave node index"); +#endif + // copy the leaf indexes in reversed order + hidden_nodes_idx[0] = -1; // arbitrary large delimiter + for (uint32_t i = 0; i < TAU; ++i) { + hidden_nodes_idx[TAU - i] = hidden_leaves_idx[i]; + } + uint64_t istart = 1; + uint64_t iend = TAU + 1; + uint64_t isibling = 0; + sibling_nodes_idx[isibling++] = -1; // arbitrary large delimiter + while (iend - istart >= 2) { + const uint32_t first_idx = hidden_nodes_idx[istart]; + const uint32_t second_idx = hidden_nodes_idx[istart + 1]; + const uint32_t next_idx = first_idx >> 1; + CASSERT(first_idx > 1, "bug1"); + CASSERT(hidden_nodes_idx[iend - 1] > next_idx, "bug2"); + if ((first_idx ^ second_idx) == 1) { + // two hidden nodes with the same parent: no sibling + istart += 2; + } else { + // single child out of at least 2: one sibling + sibling_nodes_idx[isibling++] = first_idx ^ UINT32_C(1); + istart += 1; + } + hidden_nodes_idx[iend++] = next_idx; + } + for (uint32_t hidden_idx = hidden_nodes_idx[istart]; hidden_idx != 1; hidden_idx >>= 1) { + sibling_nodes_idx[isibling++] = hidden_idx ^ UINT32_C(1); + } + CREQUIRE(isibling == topen + 1, "we should have found all the siblings (+ delim )"); +#ifndef NDEBUG + for (uint32_t i = 0; i < topen; ++i) { + CREQUIRE(sibling_nodes_idx[i] > sibling_nodes_idx[i + 1], "sibling nodes not ordered"); + } +#endif + + // step 2: expand all the seeds (replacing siblings) + CASSERT(topen >= 1, "BUG! invalid parameter"); + uint64_t next_node_idx = 2; // also equal to the num leaves to write at that depth + const uint8_t* rd_ptr = seeds + SEED_BYTES; // root position (node_id = 1) + uint8_t* wr_ptr = seeds + 2 * SEED_BYTES; // left child (node_id=2) + const uint32_t* next_sibling = sibling_nodes_idx + topen; + const uint8_t* next_sibling_seed = ((uint8_t*)sibling_seeds) + (topen - 1) * SEED_BYTES; + + // pretend that the root is zero (we know it is hidden!) + CASSERT(*next_sibling > 1, "the root is necessarily hidden"); + memset(seeds + SEED_BYTES, 0, SEED_BYTES); + + // expand the first two depths of the tree one by one + while (next_node_idx < 8) { + vole_params->extend_leaf_seed(ext_seeds, rd_ptr); + vole_params->ggm_extseed_rng_lr(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 2 * SEED_BYTES; + rd_ptr += SEED_BYTES; + next_node_idx += 2; + // replace the sibling seeds + while (*next_sibling < next_node_idx) { + memcpy(seeds + (*next_sibling) * SEED_BYTES, next_sibling_seed, SEED_BYTES); + next_sibling_seed -= SEED_BYTES; + --next_sibling; + } + } + // expand the rest of the depths 4x by 4x + while (next_node_idx <= TOTAL_NODES) { + vole_params->extend_leaf_seed_4x(ext_seeds, rd_ptr); + // I8: expand the 4 sibling parents (node_idx, +2, +4, +6) in one call. The cat1 avx2 + // build batches them into one 8-block encrypt; the other builds do four single calls. + vole_params->ggm_extseed_rng_lr_x4(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 8 * SEED_BYTES; + rd_ptr += 4 * SEED_BYTES; + next_node_idx += 8; + // replace the sibling seeds + while (*next_sibling < next_node_idx) { + memcpy(seeds + (*next_sibling) * SEED_BYTES, next_sibling_seed, SEED_BYTES); + next_sibling_seed -= SEED_BYTES; + --next_sibling; + } + } + CASSERT(next_sibling == sibling_nodes_idx, "we should have exhausted the siblings"); + CASSERT(next_sibling_seed == sibling_seeds - SEED_BYTES, "we should have exhausted the siblings"); + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have expanded the tree"); + + // step 3: expand all the leaf seeds into commit and vole randomness + memset(q, 0, TAU * KAPPA * Lslice); + vole_params->xof_vector.init_and_seed(commit_xofs, TAU, &HASH_BAVC_PREFIX, 1); + + uint64_t l = 0; + next_node_idx = TOTAL_LEAVES; + const uint8_t* next_leaf_seed = seeds + TOTAL_LEAVES * SEED_BYTES; // ptr of the first leaf seed + const uint8_t* const end_leaf_seed = seeds + (TOTAL_NODES + 1) * SEED_BYTES; + const uint32_t* next_hidden_leaf_idx = hidden_nodes_idx + TAU; + const uint8_t* next_hidden_leaf_commit = hidden_leaves_commit; + CASSERT(*next_hidden_leaf_idx >= TOTAL_LEAVES, "BUG! the first hidden leaf is necessarily a leaf"); + CASSERT(*(next_hidden_leaf_idx + 1) < TOTAL_NODES, "BUG! the 'first' hidden leaf is not the first"); + while (next_leaf_seed < end_leaf_seed) { + // expand 4 * TAU leaf seeds and advance the read pointer + uint8_t* out_ext_seed = ext_seeds; + for (uint64_t i = 0; i < TAU; ++i) { + // expand the leaf seed -> expanded buffer + vole_params->extend_leaf_seed_4x(out_ext_seed, // output + next_leaf_seed // leaf seed + ); + next_leaf_seed += 4 * LAMBDA_BYTES; + out_ext_seed += 4 * EXT_BYTES; + } + CASSERT(out_ext_seed == ext_seeds + 4 * TAU * EXT_BYTES, "out_ext_seed should be at the end of the buffer"); + + // process the 4 * TAU expanded leaves (it corresponds to 4 positions) + const uint8_t* in_expanded_seed = ext_seeds; + for (uint64_t nb = 0; nb < 4; ++nb) { + const uint64_t loc = (l + 1 < nleaves) ? binval_of(l + 1) : KAPPA - 1; + const uint64_t loc_offset = loc * Lslice; + uint8_t* out_commit = commit_buffer; + for (uint64_t i = 0; i < TAU; ++i) { + // compute the commit and add it to the commit buffer + if (next_node_idx == *next_hidden_leaf_idx) { + // copy the commit + memcpy(out_commit, next_hidden_leaf_commit, COMMIT_BYTES); + // and process hidden vole + vole_params->bitvec_xor_to(Lslice, qq[i] + loc_offset, ss[i]); + // advance hidden leaf ptr + --next_hidden_leaf_idx; + next_hidden_leaf_commit += COMMIT_BYTES; + } else { + // otherwise derive it from the seed + vole_params->ggm_extseed_rng_commit(out_commit, // out + ggm_masked_salt, // salt + in_expanded_seed, // expanded_seed + next_node_idx // node_idx + ); + // and process vole with seed + vole_params->vole_extseed_rng(tmp_r, Lslice, // out (only Lbytes would suffice here) + vole_masked_salt, // salt + in_expanded_seed, // expanded_seed + i); // repetition index + vole_params->bitvec_cascade_xor_to(Lslice, qq[i] + loc_offset, ss[i], tmp_r); + } + // advance pointers + in_expanded_seed += EXT_BYTES; + out_commit += COMMIT_BYTES; + next_node_idx += 1; + } + // hash the commits + vole_params->xof_vector.seed(commit_xofs, TAU, commit_ptrs, COMMIT_BYTES); + // advance the pointers + ++l; + } + CASSERT(in_expanded_seed == ext_seeds + 4 * TAU * EXT_BYTES, "we should have consumed all the expanded seeds"); + } + CASSERT(l == nleaves, "we should have processed all the leaves"); + CASSERT(next_leaf_seed == end_leaf_seed, "we should have processed all the leaves"); + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have processed all the leaves"); + CASSERT(next_hidden_leaf_idx == hidden_nodes_idx, "BUG! we should have consumed all the hidden leaves"); + CASSERT(next_hidden_leaf_commit == hidden_leaves_commit + TAU * COMMIT_BYTES, + "BUG! we should have consumed all the hidden leaves"); + + // now, hash the per-rep subhashes into the final commits hash (same layout as + // the prover's): commits_hash = H(HASH_BAVC_PREFIX, global_salt, subhashes). + vole_params->xof_vector.finalize_and_output(commit_xofs, TAU, subhashes_ptrs, 2 * LAMBDA_BYTES); + vole_params->xof_vector.ctx_release(commit_xofs, TAU); + xof_ctx commits_xof; + vole_params->xof.xof_init_and_seed(&commits_xof, &HASH_BAVC_PREFIX, 1); + vole_params->xof.xof_seed(&commits_xof, global_salt, LAMBDA_BYTES); + vole_params->xof.xof_seed(&commits_xof, subhashes, 2 * TAU * LAMBDA_BYTES); + vole_params->xof.xof_finalize_and_output(&commits_xof, commits_hash, 2 * LAMBDA_BYTES); + vole_params->xof.xof_ctx_release(&commits_xof); + + // postprocess q using delta + const uint64_t* deltap64 = delta1; + for (uint64_t i = 0; i < TAU; ++i) { + uint32_t delta_i = extract_kappabit_uint(KAPPA, i * KAPPA, deltap64); + for (uint64_t j = 0; j < KAPPA; ++j) { + if ((delta_i >> j) & 1) { + vole_params->bitvec_xor_to(Lslice, qq[i] + j * Lslice, ss[i]); + } + } + } + + // release any per-slot state the ext_seed backend cached (no-op unless the + // liboqs aes128 backend is in use) + vole_params->release_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); +} + + +enum node_action_t { + NODE_ACTION_NONE = 0, + NODE_ACTION_HIDDEN_RIGHT = 1, + NODE_ACTION_HIDDEN_LEFT = 2, + NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT = 3, + NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT = 4 +}; + +EXPORT void compute_tweaked_salts( // + const vole_parameters* vole_params, // params + uint64_t* ggm_masked_salt, // [out] masked salt for the GGM tree + uint64_t* vole_masked_salt, // [out] masked salt for the vole RNG (if not nullptr) + const salt_t* global_salt // [in] +) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t msb_idx = (lambda_bytes >> 3) - 1; + memcpy(ggm_masked_salt, global_salt, lambda_bytes); + // clear the GGM_TWEAK_BITS least significant bits (used for the actual tweak/ctr) + ggm_masked_salt[0] &= (UINT64_C(-1) << GGM_TWEAK_BITS); + if (vole_params->proofow_variant == PROOFOW_VARIANT_CIPHER) { + // cipher PoW uses the 2-bits domain separation prefix "01" + ggm_masked_salt[msb_idx] &= UINT64_C(-1) >> 2; + ggm_masked_salt[msb_idx] |= UINT64_C(1) << 62; + } else { + // shake PoW uses the 1-bit domain separation prefix "1" + ggm_masked_salt[msb_idx] |= UINT64_C(1) << 63; + } + if (vole_masked_salt) { + // same algorithm but different prefixes + memcpy(vole_masked_salt, global_salt, lambda_bytes); + // clear the GGM_TWEAK_BITS least significant bits (used for the actual tweak/ctr) + vole_masked_salt[0] &= (UINT64_C(-1) << GGM_TWEAK_BITS); + if (vole_params->proofow_variant == PROOFOW_VARIANT_CIPHER) { + // cipher PoW uses the 2-bits domain separation prefix "00" + vole_masked_salt[msb_idx] &= UINT64_C(-1) >> 2; + } else { + // shake PoW uses the 1-bit domain separation prefix "0" + vole_masked_salt[msb_idx] &= UINT64_C(-1) >> 1; + } + } +} + +EXPORT uint64_t full_ggm_tree_open_sibling_path_from_root_tmp_bytes( // + const vole_parameters* vole_params, // + const uint64_t sibling_path_size // number of sibling seeds +) { + const uint64_t TAU = vole_params->TAU; + // const uint64_t KAPPA = vole_params->KAPPA; + // const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + // const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t BUF_SIZE_MAX = (2 * TAU - 1) + sibling_path_size; + const uint64_t SEED_BYTES = vole_params->lambda_bytes; + // const uint64_t COMMIT_BYTES = 2 * SEED_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint64_t*, ggm_masked_salt, 32, SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seed, 32, EXT_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, lr_seeds, 32, 2 * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, 2 * BUF_SIZE_MAX * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint32_t*, node_indexes, 8, BUF_SIZE_MAX * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, node_actions, 8, BUF_SIZE_MAX * sizeof(uint8_t)); + COMP_SPACE_RETURN(); +} + +EXPORT void full_ggm_tree_open_sibling_path_from_root( // + const vole_parameters* vole_params, // + seed_t* sibling_seeds, // sibling seeds (in decreasing node index order) + commit_t* hidden_leaves_commits, // hidden leaves commits (in increasing leaf order) + const seed_t* root_seed, // the ggm root seed + const salt_t* global_salt, // the global salt + const uint32_t* hidden_leaves_idx, // index of hidden leaves (node index) + const uint64_t sibling_path_size, // number of sibling seeds + uint8_t* tmp_space) { + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t BUF_SIZE_MAX = (2 * TAU - 1) + sibling_path_size; + const uint64_t SEED_BYTES = vole_params->lambda_bytes; + const uint64_t COMMIT_BYTES = 2 * SEED_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + TMP_SPACE_MAP_ALIGNED(uint64_t*, ggm_masked_salt, 32, SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seed, 32, EXT_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, lr_seeds, 32, 2 * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, 2 * BUF_SIZE_MAX * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint32_t*, node_indexes, 8, BUF_SIZE_MAX * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, node_actions, 8, BUF_SIZE_MAX * sizeof(uint8_t)); + // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) + vole_params->prepare_extseed_buf(ext_seed, 1, EXT_BYTES); + // only the GGM salt is needed here: this path does not draw any vole randomness + compute_tweaked_salts(vole_params, ggm_masked_salt, NULL, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); +#ifndef NDEBUG + const uint64_t TOTAL_LEAVES = (TAU << KAPPA); + for (uint64_t i = 0; i < TAU - 1; ++i) { + CREQUIRE(hidden_leaves_idx[i] < hidden_leaves_idx[i + 1], "incorrect leave order"); + } + CREQUIRE(hidden_leaves_idx[0] >= TOTAL_LEAVES, "incorrect leave node index"); + CREQUIRE(hidden_leaves_idx[TAU - 1] < 2 * TOTAL_LEAVES, "incorrect leave node index"); +#endif + // copy the leaf indexes in reversed order + uint32_t istart = 0; + uint32_t iend = TAU; + for (uint32_t i = 0; i < TAU; ++i) { + node_indexes[TAU - i - 1] = hidden_leaves_idx[i]; + } + uint32_t first_idx; + while (iend - istart >= 2) { + first_idx = node_indexes[istart]; // *(bstart++); + const uint32_t second_idx = node_indexes[istart + 1]; + const uint32_t next_idx = first_idx >> 1; + CASSERT(first_idx > 1, "bug1"); + CASSERT(node_indexes[iend - 1] > next_idx, "bug2"); + if ((first_idx ^ second_idx) == 1) { + // two hidden nodes with the same parent + node_actions[istart] = NODE_ACTION_HIDDEN_RIGHT; + node_actions[istart + 1] = NODE_ACTION_HIDDEN_LEFT; + istart += 2; + } else { + // single child out of at least 2 + if (first_idx & 1) { + node_actions[istart] = NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT; + } else { + node_actions[istart] = NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT; + } + istart += 1; + } + node_indexes[iend++] = next_idx; + } + while ((first_idx = node_indexes[istart]) != 1) { + if (first_idx & 1) { + node_actions[istart] = NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT; + } else { + node_actions[istart] = NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT; + } + istart += 1; + node_indexes[iend++] = first_idx >> 1; + } +#ifndef NDEBUG + CREQUIRE(iend == BUF_SIZE_MAX, "we should have processed all the nodes"); + for (uint64_t i = 0; i < BUF_SIZE_MAX - 1; i++) { + CREQUIRE(node_indexes[i] > node_indexes[i + 1], "incorrect node index"); + } + CREQUIRE(node_indexes[BUF_SIZE_MAX - 1] == 1, "the last node should be the root"); +#endif + // second pass in decreasing order: fill-in the seeds + int64_t dend = BUF_SIZE_MAX - 1; + int64_t spath_idx = sibling_path_size - 1; + memcpy(seeds + dend * SEED_BYTES, root_seed, SEED_BYTES); + for (int64_t dstart = BUF_SIZE_MAX - 2; dstart >= 0; --dstart) { + switch (node_actions[dstart]) { + case NODE_ACTION_HIDDEN_LEFT: { + CASSERT(dstart > 0 && node_actions[dstart - 1] == NODE_ACTION_HIDDEN_RIGHT, "incorrect node action"); + // and continue + } + case NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT: + case NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT: { + // expand the seed and store left + CASSERT(dend >= TAU, "incorrect node action"); + vole_params->extend_leaf_seed(ext_seed, seeds + dend * SEED_BYTES); + vole_params->ggm_extseed_rng_lr(lr_seeds, ggm_masked_salt, ext_seed, node_indexes[dstart] & UINT32_C(-2), THETA); + --dend; + break; + } + case NODE_ACTION_HIDDEN_RIGHT: + break; + default: + abort(); // unknown case + } + switch (node_actions[dstart]) { + case NODE_ACTION_HIDDEN_LEFT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds, SEED_BYTES); + break; + } + case NODE_ACTION_HIDDEN_RIGHT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds + SEED_BYTES, SEED_BYTES); + break; + } + case NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds, SEED_BYTES); + memcpy(sibling_seeds + spath_idx * SEED_BYTES, lr_seeds + SEED_BYTES, SEED_BYTES); + --spath_idx; + break; + } + case NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds + SEED_BYTES, SEED_BYTES); + memcpy(sibling_seeds + spath_idx * SEED_BYTES, lr_seeds, SEED_BYTES); + --spath_idx; + break; + } + default: + abort(); // unknown case + } + } + CASSERT(spath_idx == -1, "we should have processed all the sibling seeds"); + CASSERT(dend == TAU - 1, "we should have processed all the nodes"); + // final pass: compute the hidden leaves commits + for (uint64_t i = 0; i < TAU; ++i) { + vole_params->extend_leaf_seed(ext_seed, seeds + (TAU - i - 1) * SEED_BYTES); + vole_params->ggm_extseed_rng_commit(hidden_leaves_commits + i * COMMIT_BYTES, ggm_masked_salt, ext_seed, + node_indexes[TAU - i - 1]); + } + + // release any per-slot state the ext_seed backend cached (no-op unless the + // liboqs aes128 backend is in use) + vole_params->release_extseed_buf(ext_seed, 1, EXT_BYTES); +} + +EXPORT void prover_midsize_to_fullsize_std_vole_ct_ref(const vole_parameters* vole_params, uint64_t L, bitvec_t* out_u, + bitmat_t* out_corr, flambda_t* out_v, const bitmat_t* in_u, + const bitmat_t* in_v) { + // in_v points to a lambda x L_byte region, and the last lambda - tau.kappa rows are set to zero + + const uint64_t Lbytesx = (L + 7) / 8; + const uint64_t Lslice = (Lbytesx + 31) & UINT64_C(-32); + + // out_v = transpose(in_v) + (*vole_params->matrix_lambda_transpose)(out_v, in_v, L, Lslice); + + // out_u = first L bits of in_u + memcpy(out_u, in_u, Lbytesx); + + // out_corr = in_u[i+1] ^ in_u[0] + // attention: out_corr has an LByte slice, whereas in_u has a Lslice slice + for (uint64_t i = 0; i < vole_params->TAU - 1; i++) { + vole_params->bitvec_xor(Lslice, out_corr + i * Lslice, in_u + (i + 1) * Lslice, in_u); + } +} + +EXPORT void verifier_midsize_to_fullsize_std_vole_ref(const vole_parameters* vole_params, uint64_t L, flambda_t* out_q, + const bitmat_t* in_q) { + const uint64_t Lbytes = (L + 7) / 8; + const uint64_t Lslice = (Lbytes + 31) & UINT64_C(-32); + // out_q = transpose(in_q) + (*vole_params->matrix_lambda_transpose)(out_q, in_q, L, Lslice); +} + +EXPORT uint64_t vole_consistency_check_matrix_nrows( // + const vole_parameters* vole_params) // dimensions // number of pairs to treat +{ + // num_cchk_pairs = LAMBDA + B, B = 16 (Thibauld Feneuil / FAEST spec): the consistency-check matrix + // size for the claimed soundness level (LAMBDA+16 is already a multiple of 8). Value-identical to the + // old ceil8(KAPPA*TAU+16) for every shipped set, but the authoritative form -- KAPPA*TAU only + // coincided with LAMBDA and would UNDER-size the check for faster params where KAPPA*TAU < LAMBDA. + return vole_params->LAMBDA + 16; +} + +EXPORT uint64_t vole_consistency_check_matrix_ncols( // + const vole_parameters* vole_params, // dimensions + uint64_t L) { + return L - vole_consistency_check_matrix_nrows(vole_params); +} + +EXPORT void both_vole_consistency_check_matrix( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitmat_t* chk_matrix, // [out] cst_check_dim x (L - cst_check_dim) + const hash_t* chk_seed1, uint64_t chk_seed1_bytes) // [in] rng seed and tweak +{ + const uint64_t cchk_nrows = vole_consistency_check_matrix_nrows(vole_params); + const uint64_t cchk_ncols = vole_consistency_check_matrix_ncols(vole_params, L); + const uint64_t cchk_col_bytes = (cchk_ncols + 7) >> 3; + xof_ctx cchk_matrix_rng; + vole_params->xof.xof_init_and_seed(&cchk_matrix_rng, chk_seed1, chk_seed1_bytes); + vole_params->xof.xof_finalize_and_output(&cchk_matrix_rng, chk_matrix, cchk_nrows * cchk_col_bytes); + vole_params->xof.xof_ctx_release(&cchk_matrix_rng); + // mask last columns with zeroes if needed + uint8_t cchk_last_mask = 0xFF >> ((-cchk_ncols) & 7); + uint8_t* const cm = (uint8_t*)chk_matrix; + for (uint64_t i = 0; i < cchk_nrows; i++) { + cm[i * cchk_col_bytes + cchk_col_bytes - 1] &= cchk_last_mask; + } +} + +EXPORT void prover_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitvec_t* chk_u, // [out] cst check of size KAPPA.TAU+B + flambda_t* chk_v, // [out] chk_v + const bitvec_t* u, // [in] vector of length L + const flambda_t* v, // [in] vector of length L + const bitvec_t* chk_matrix) // [in] cst check matrix +{ + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t cchk_nrows = vole_consistency_check_matrix_nrows(vole_params); + const uint64_t cchk_ncols = vole_consistency_check_matrix_ncols(vole_params, L); + const uint64_t cchk_nrows_bytes = cchk_nrows >> 3; + const uint8_t* const uu = (const uint8_t*)u; + const uint8_t* const vv = (const uint8_t*)v; + vole_params->matrix_vector_product_f2(cchk_nrows, cchk_ncols, chk_u, chk_matrix, uu + cchk_nrows_bytes); + vole_params->bitvec_xor_to(cchk_nrows_bytes, chk_u, uu); + vole_params->matrix_f2_times_vector_flambda(lambda, cchk_nrows, cchk_ncols, chk_v, chk_matrix, + vv + cchk_nrows * lambda_bytes); + vole_params->bitvec_xor_to(cchk_nrows * lambda_bytes, chk_v, vv); +} + +EXPORT void verifier_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + flambda_t* chk_v, // [out] chk_v + const bitvec_t* chk_u, // [in] cst check of size KAPPA.TAU+B + const flambda_t* q, // [in] vector of length L + const bitvec_t* chk_matrix, // [in] cst check matrix (L-cst_check_dim) x L + const bitvec_t* delta1) // [in] delta1 (kappa.tau bits) +{ + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t cchk_nrows = vole_consistency_check_matrix_nrows(vole_params); + const uint64_t cchk_ncols = vole_consistency_check_matrix_ncols(vole_params, L); + const uint8_t* const qq = (const uint8_t*)q; + vole_params->matrix_f2_times_vector_flambda(lambda, cchk_nrows, cchk_ncols, chk_v, chk_matrix, + qq + cchk_nrows * lambda_bytes); + vole_params->bitvec_xor_to(cchk_nrows * lambda_bytes, chk_v, qq); + const uint8_t* const cu = (uint8_t*)chk_u; + uint8_t* const cv = (uint8_t*)chk_v; + for (uint64_t i = 0; i < cchk_nrows; ++i) { + if ((cu[i >> 3] >> (i & 7)) & 1) { + vole_params->flambda_sum(cv + i * lambda_bytes, cv + i * lambda_bytes, delta1); + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common/vole_generation.h b/src/sig/sdith/sdith_sdith_common/vole_generation.h new file mode 100644 index 0000000000..951ee7256d --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/vole_generation.h @@ -0,0 +1,168 @@ +#ifndef VOLE_GENERATION_H +#define VOLE_GENERATION_H + +/// This header declares the functions needed to generate vole pairs securely + +#include "vole_parameters.h" + +/** @brief converts delta0 to delta1 + * delta0 has kappa*tau bits, encoding tau grey code encodings + * delta1 has lambda bits, only the lowest kappa*tau are used, the rest is zero. + */ +EXPORT void delta1_from_delta0_ref(const vole_parameters* vole_params, flambda_t* delta1, const bitvec_t* delta0); + +/** @brief converts delta1 to delta2 + * delta2 is the field inverse of delta1 + */ +EXPORT void delta2_from_delta1_ref(const vole_parameters* vole_params, flambda_t* delta2, const flambda_t* delta1); + +EXPORT uint64_t prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L // number of pairs to generate [Lslice next mult of 32] +); + +/** + * Compute the tweaked base salts that are used in GGM seed-expand, seed-commit, and vole-rng + */ +EXPORT void compute_tweaked_salts( // + const vole_parameters* vole_params, // params + uint64_t* ggm_masked_salt, // [out] masked salt for the GGM tree + uint64_t* vole_masked_salt, // [out] masked salt for the vole RNG (if not nullptr) + const salt_t* global_salt // [in] +); + +/** + * tmp space needed to open the sibling path that corresponds to the provided hidden leaves indexes + */ +EXPORT uint64_t full_ggm_tree_open_sibling_path_from_root_tmp_bytes( // + const vole_parameters* vole_params, // + const uint64_t sibling_path_size // number of sibling seeds + ); + +/** + * Opens the sibling path that corresponds to the provided hidden leaves indexes + */ +EXPORT void full_ggm_tree_open_sibling_path_from_root( // + const vole_parameters* vole_params, // + seed_t* sibling_seeds, // sibling seeds (in decreasing node index order) + commit_t* hidden_leaves_commits, // hidden leaves commits (in increasing leaf order) + const seed_t* root_seed, // the ggm root seed + const salt_t* global_salt, // the global salt + const uint32_t* hidden_leaves_idx, // index of hidden leaves (node index) + const uint64_t sibling_path_size, // number of sibling seeds + uint8_t* tmp_space); + +/** + * Generate L vole pairs over (F2,F2^KAPPA) (grey code + BFS version) + * @param commits_hash (output): 2.lambda bytes: + * H(HASH_BAVC_PREFIX, global_salt, per-rep subhashes) + * @param u (output): L bits: Xor of all ri's, + * @param v (output): matrix KAPPA x L bits: Xor of ri.grey(i) + */ +EXPORT void prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate [Lslice next mult of 32] + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* u, // [out] TAU x (L bits on Lslice bytes) + bitmat_t* v, // [out] TAU x KAPPA x (L bits on Lslice bytes) row major + const salt_t* ggm_salt, // [in] global salt for the GGM tree + const seed_t* ggm_root_seed, // [in] root seed for the GGM tree + uint8_t* tmp_space); // [tmp] scratch space + + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) -- tmp bytes needed + */ +EXPORT uint64_t verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + uint64_t topen // (max) size of the sibling path +); + + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) + * @param commits_hash (output): 2.lambda bytes, same layout as the prover's: + * H(HASH_BAVC_PREFIX, global_salt, per-rep subhashes) + */ +EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* q, // [out] TAU x KAPPA x L row major + bitmat_t* coor_terms, // [in/out] TAU x L bits + const uint32_t* hidden_leaves_idx, // [in] TAU indices of the hidden (node) leaves + const commit_t* hidden_leaves_commit, // [in] TAU commits of the hidden (node) leaves + const seed_t* sibling_seeds, // [in] Topen sibling seeds + const uint64_t topen, // [in] number of sibling seeds + const salt_t* ggm_salt, // [in] global salt for the GGM tree + const flambda_t* delta1, // verifier's point delta1 + uint8_t* tmp_space); + + +/** + * Concatenate and transpose L mid-size std vole pairs over (F2,F2^KAPPA) + * To form L full-size std vole pairs over (F2,F2^LAMBDA) + * // acceptable in_place mode: + * // either + * // out_u == in_u and out_corr == in_u[1] + * // otherwise, out_u, out_corr, in_u shall be completely disjoint + * // also: either + * // out_v == in_v + * // or otherwise, out_v, in_v must be completely disjoint + */ +EXPORT void prover_midsize_to_fullsize_std_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitvec_t* out_u, // [out] L bits + bitmat_t* out_corr, // [out] (TAU-1 x L) row major + flambda_t* out_v, // [out] gflambda[L] contiguous + const bitmat_t* in_u, // [in] TAU x L row major + const bitmat_t* in_v); // [in] (TAU*KAPPA) x L row major + +/** + * Concatenate and transpose L mid-size std vole pairs over (F2,F2^KAPPA) + * To form L full-size std vole pairs over (F2,F2^LAMBDA) + * // acceptable in_place mode: + * // also: either + * // out_q == in_a + * // or otherwise, out_q, in_q must be completely disjoint + */ +EXPORT void verifier_midsize_to_fullsize_std_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + flambda_t* out_q, // [out] gflambda[L] + const bitmat_t* in_q); // [in] TAU*KAPPA x L row major + +EXPORT uint64_t vole_consistency_check_matrix_nrows( // + const vole_parameters* vole_params); // dimensions + +EXPORT uint64_t vole_consistency_check_matrix_ncols( // + const vole_parameters* vole_params, // dimensions + uint64_t L); // number of pairs to treat + +EXPORT void both_vole_consistency_check_matrix( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitmat_t* chk_matrix, // [out] cst_check_dim x (L - cst_check_dim) + const hash_t* chk_seed1, uint64_t chk_seed1_bytes); // [in] rng seed and tweak + +EXPORT void prover_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitvec_t* chk_u, // [out] cst check of size KAPPA.TAU+B + flambda_t* chk_v, // [out] chk_v + const bitvec_t* u, // [in] vector of length L + const flambda_t* v, // [in] vector of length L + const bitvec_t* chk_matrix); // [in] cst check matrix + +EXPORT void verifier_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + flambda_t* chk_v, // [out] chk_v + const bitvec_t* chk_u, // [in] cst check of size KAPPA.TAU+B + const flambda_t* q, // [in] vector of length L + const bitvec_t* chk_matrix, // [in] cst check matrix (L-cst_check_dim) x L + const bitvec_t* delta1); // [in] delta1 (kappa.tau bits) + +#endif // VOLE_GENERATION_H diff --git a/src/sig/sdith/sdith_sdith_common/vole_parameters.c b/src/sig/sdith/sdith_sdith_common/vole_parameters.c new file mode 100644 index 0000000000..f1c6fb5795 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/vole_parameters.c @@ -0,0 +1,182 @@ +#include "vole_private.h" + +void vole_parameters_init_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa) { + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, PROOFOW_VARIANT_SHAKE); +} + +EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant) { + CASSERT(lambda > 0 && lambda >= tau * kappa, "bug? lambda is not larger than tau*kappa (check parameter order)"); + vole_params->proofow_variant = proofow_variant; + vole_params->KAPPA = kappa; + vole_params->TAU = tau; + vole_params->LAMBDA = lambda; + vole_params->lambda_bytes = (lambda + 7) >> 3; + vole_params->bitvec_xor = bitvec_xor_ref; + vole_params->bitvec_xor_to = bitvec_xor_to_ref; + vole_params->bitvec_cascade_xor_to = bitvec_cascade_xor_to_ref; + vole_params->matrix_f2_times_vector_flambda = matrix_f2_times_vector_flambda_ref; + vole_params->matrix_vector_product_f2 = matrix_vector_product_f2_ref; + vole_params->ct = ct_utils_ref; + switch (lambda) { + case 128: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat1; + vole_params->proofow_init = proofow_init_shake_cat1; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat1; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat1; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat1; + vole_params->proofow_init = proofow_init_cipher_cat1_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat1_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat1_ref; + vole_params->proofow_release = proofow_release_cipher_cat1_ref; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat1_aes128_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat1_aes128_4x_ref; + vole_params->prepare_extseed_buf = prepare_extseed_buf_cat1_aes128_ref; + vole_params->release_extseed_buf = release_extseed_buf_cat1_aes128_ref; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat1_aes128; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat1_aes128_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat1_aes128_x4_ref; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat1_aes128_ref; + vole_params->vole_extseed_rng = vole_rng_ext_cat1_aes128_ctrle_ref; + vole_params->xof = xof_shake128; + vole_params->xof_vector = xof_vector_shake128; + vole_params->matrix_prg = matrix_rng_cat1_aes128_ref; + vole_params->keygen_rng = keygen_rng_cat1_aes128_ref; + // arithmetic + vole_params->flambda_set = gf128_flambda_set_ref; + vole_params->flambda_inverse = gf128_flambda_inverse_ref; + vole_params->flambda_sum_pow2 = gf128_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf128_flambda_sum_ref; + vole_params->flambda_product = gf128_flambda_product_ref; + vole_params->flambda_product_f2 = gf128_flambda_product_f2_ref; + vole_params->flambda_dot_product = gf128_flambda_dot_product_ref; + vole_params->flambda_dot_product_acc = gf128_flambda_dot_product_acc_ref; + vole_params->flambda_dot_product_f2_acc = gf128_flambda_dot_product_f2_acc_ref; + vole_params->flambda_echelon_pow2 = gf128_flambda_echelon_pow2_ref; + vole_params->matrix_lambda_transpose = transpose_128_L_ref; + break; + case 192: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat3; + vole_params->proofow_init = proofow_init_shake_cat3; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat3; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat3; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat3; + vole_params->proofow_init = proofow_init_cipher_cat3_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat3_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat3_ref; + vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat3_rijndael256_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat3_rijndael256_4x_ref; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat3_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat3_rijndael256_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat3_rijndael256_ref; + vole_params->vole_extseed_rng = vole_rng_ext_cat3_rijndael256_ctrle_ref; + vole_params->xof = xof_shake256; + vole_params->xof_vector = xof_vector_shake256; + vole_params->matrix_prg = matrix_rng_cat3_rijndael256_ref; + vole_params->keygen_rng = keygen_rng_cat3_rijndael256_ref; + // arithmetic + vole_params->flambda_set = gf192_flambda_set_ref; + vole_params->flambda_inverse = gf192_flambda_inverse_ref; + vole_params->flambda_sum_pow2 = gf192_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf192_flambda_sum_ref; + vole_params->flambda_product = gf192_flambda_product_ref; + vole_params->flambda_product_f2 = gf192_flambda_product_f2_ref; + vole_params->flambda_dot_product = gf192_flambda_dot_product_ref; + vole_params->flambda_dot_product_acc = gf192_flambda_dot_product_acc_ref; + vole_params->flambda_dot_product_f2_acc = gf192_flambda_dot_product_f2_acc_ref; + vole_params->flambda_echelon_pow2 = gf192_flambda_echelon_pow2_ref; + vole_params->matrix_lambda_transpose = transpose_192_L_ref; + break; + case 256: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat5; + vole_params->proofow_init = proofow_init_shake_cat5; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat5; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat5; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat5; + vole_params->proofow_init = proofow_init_cipher_cat5_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat5_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat5_ref; + vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat5_rijndael256_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat5_rijndael256_4x_ref; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat5_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat5_rijndael256_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat5_rijndael256_ref; + vole_params->vole_extseed_rng = vole_rng_ext_cat5_rijndael256_ctrle_ref; + vole_params->xof = xof_shake256; + vole_params->xof_vector = xof_vector_shake256; + vole_params->matrix_prg = matrix_rng_cat5_rijndael256_ref; + vole_params->keygen_rng = keygen_rng_cat5_rijndael256_ref; + // arithmetic + vole_params->flambda_set = gf256_flambda_set_ref; + vole_params->flambda_inverse = gf256_flambda_inverse_ref; + vole_params->flambda_sum_pow2 = gf256_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf256_flambda_sum_ref; + vole_params->flambda_product = gf256_flambda_product_ref; + vole_params->flambda_product_f2 = gf256_flambda_product_f2_ref; + vole_params->flambda_dot_product = gf256_flambda_dot_product_ref; + vole_params->flambda_dot_product_acc = gf256_flambda_dot_product_acc_ref; + vole_params->flambda_dot_product_f2_acc = gf256_flambda_dot_product_f2_acc_ref; + vole_params->flambda_echelon_pow2 = gf256_flambda_echelon_pow2_ref; + vole_params->matrix_lambda_transpose = transpose_256_L_ref; + break; + default: + CREQUIRE(0, "lambda not supported"); + } +} + +void vole_parameters_init(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa) { + vole_parameters_init_with_variant(vole_params, lambda, tau, kappa, PROOFOW_VARIANT_SHAKE); +} + +EXPORT void vole_parameters_init_with_variant(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant) { +#ifndef ONLY_REF_IMPLEMENTATION +#ifdef __x86_64__ + if (CPU_SUPPORTS("avx2") && CPU_SUPPORTS("aes") && CPU_SUPPORTS("pclmul") && CPU_SUPPORTS("sse")) { + vole_parameters_init_with_variant_avx(vole_params, lambda, tau, kappa, proofow_variant); + } else { + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, proofow_variant); + } +#else + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, proofow_variant); +#endif +#else + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, proofow_variant); +#endif +} diff --git a/src/sig/sdith/sdith_sdith_common/vole_parameters.h b/src/sig/sdith/sdith_sdith_common/vole_parameters.h new file mode 100644 index 0000000000..6fa831b4ba --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/vole_parameters.h @@ -0,0 +1,97 @@ +#ifndef VOLE_PARAMETERS_H +#define VOLE_PARAMETERS_H + +#include "sdith_ct_utils.h" +#include "sdith_prng.h" + +typedef void BITVEC_XOR_TO_F(uint64_t bytelen, bitvec_t* res, const bitvec_t* b); +typedef void BITVEC_XOR_F(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b); +typedef void BITVEC_CASCADE_XOR_TO_F(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a); +typedef void FLAMBDA_PRODUCT_F(flambda_t* res, const flambda_t* a, const flambda_t* b); +typedef void FLAMBDA_PRODUCT_F2_F(flambda_t* res, const flambda_t* a, const flambda_t* b_f2); +typedef void FLAMBDA_DOT_PRODUCT_F(flambda_t* res, const flambda_t* x, const flambda_t* y, uint64_t size); +// res += sum_i x[i . x_byte_slice] . y[i]: x is strided (byte stride, multiple of lambda_bytes), y is contiguous +typedef void FLAMBDA_DOT_PRODUCT_ACC_F(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, const flambda_t* y, + uint64_t size); +// same, with every y_f2[i] restricted to 0 or 1 (the products are plain bit-masks) +typedef void FLAMBDA_DOT_PRODUCT_F2_ACC_F(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +typedef void FLAMBDA_SUM_F(flambda_t* res, const flambda_t* a, const flambda_t* b); +typedef void FLAMBDA_SUM_POW2_F(flambda_t* res, const flambda_t* a); +typedef void FLAMBDA_ECHELON_POW2_F(uint64_t k, flambda_t* res, const flambda_t* a, uint64_t a_size, + uint64_t a_byte_slice); +typedef void FLAMBDA_SET_F(flambda_t* res, const flambda_t* a); +typedef void FLAMBDA_INVERSE_F(flambda_t* res, const flambda_t* a); +typedef void MATRIX_LAMBDA_TRANSPOSE_F(bitmat_t* out, const bitmat_t* in, uint64_t L, uint64_t Lslice); +typedef void MATRIX_VECTOR_PRODUCT_F2( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b); // bit vector of size ncols +typedef void MATRIX_F2_TIMES_VECTOR_FLAMBDA( // + uint64_t lambda, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b); + +typedef struct vole_parameters_t vole_parameters; +struct vole_parameters_t { + uint64_t TAU; + uint64_t KAPPA; + uint64_t LAMBDA; + uint64_t lambda_bytes; + // ptr to the prng function? + BITVEC_XOR_TO_F* bitvec_xor_to; + BITVEC_XOR_F* bitvec_xor; + BITVEC_CASCADE_XOR_TO_F* bitvec_cascade_xor_to; + FLAMBDA_SET_F* flambda_set; + FLAMBDA_INVERSE_F* flambda_inverse; + FLAMBDA_PRODUCT_F* flambda_product; + FLAMBDA_PRODUCT_F* flambda_product_f2; + FLAMBDA_DOT_PRODUCT_F* flambda_dot_product; + FLAMBDA_DOT_PRODUCT_ACC_F* flambda_dot_product_acc; + FLAMBDA_DOT_PRODUCT_F2_ACC_F* flambda_dot_product_f2_acc; + FLAMBDA_SUM_F* flambda_sum; + FLAMBDA_SUM_POW2_F* flambda_sum_pow2; + FLAMBDA_ECHELON_POW2_F* flambda_echelon_pow2; + MATRIX_LAMBDA_TRANSPOSE_F* matrix_lambda_transpose; + MATRIX_VECTOR_PRODUCT_F2* matrix_vector_product_f2; + MATRIX_F2_TIMES_VECTOR_FLAMBDA* matrix_f2_times_vector_flambda; + // rng functions + BYTES_OF_PROOFOW_CTX_F* bytes_of_proofow_ctx; + PROOFOW_INIT_F* proofow_init; + PROOFOW_GRIND_W_F* proofow_grind_w; + PROOFOW_VERIFY_W_F* proofow_verify_w; + PROOFOW_RELEASE_F* proofow_release; + EXTEND_LEAF_SEED_F* extend_leaf_seed; + EXTEND_LEAF_SEED_4X_F* extend_leaf_seed_4x; + EXTSEED_BUF_F* prepare_extseed_buf; + EXTSEED_BUF_F* release_extseed_buf; + EXTENDED_NODE_SEED_BYTES_F* extended_node_seed_bytes; + GGM_EXTSEED_RNG_LR_F* ggm_extseed_rng_lr; + GGM_EXTSEED_RNG_LR_X4_F* ggm_extseed_rng_lr_x4; // I8: batched 4-node variant; NULL => four ggm_extseed_rng_lr calls + GGM_EXTSEED_RNG_COMMIT_F* ggm_extseed_rng_commit; + VOLE_EXTSEED_RNG_F* vole_extseed_rng; + xof_functions xof; + xof_vector_functions xof_vector; + matrix_rng_functions matrix_prg; // row-wise prng for public-key (H) expansion + keygen_rng_functions keygen_rng; // secret-key seed prng (solution sampling) + ct_utils ct; // constant-time helpers (prover/keygen side only) + // variants + proofow_variant_t proofow_variant; +}; + +EXPORT void vole_parameters_init_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa); + +EXPORT void vole_parameters_init_avx(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa); + +EXPORT void vole_parameters_init(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa); + +EXPORT void vole_parameters_init_with_variant(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant); + +EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant); + +EXPORT void vole_parameters_init_with_variant_avx(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant); + + +#endif // VOLE_PARAMETERS_H diff --git a/src/sig/sdith/sdith_sdith_common/vole_private.h b/src/sig/sdith/sdith_sdith_common/vole_private.h new file mode 100644 index 0000000000..e0957854c4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/vole_private.h @@ -0,0 +1,255 @@ +#ifndef AQ_VOLE_IMPL_VOLE_PRIVATE_H +#define AQ_VOLE_IMPL_VOLE_PRIVATE_H + +#include +#include + +#include "commons.h" +#include "sdith_inline.h" +#include "ggm.h" +#include "sdith_algebra.h" +#include "sdith_arithmetic.h" +#include "sdith_vole_to_piop.h" +#include "sdith_piop_circuits.h" +#include "sdith_prng.h" +#include "sdith_rsd.h" +#include "sdith_signature.h" +#include "vole_parameters.h" +#include "vole_generation.h" + +#define CREQUIRE(condition, error_printf...) \ + do { \ + if (!(condition)) { \ + fprintf(stderr, "ERROR!! :" error_printf); \ + abort(); \ + } \ + } while (0) + +#define CREQUIRE_ALIGNMENT(variable, alignment) \ + CREQUIRE(((uint64_t)(variable) & ((alignment) - 1)) == 0, "alignment problem:" __FILE__ " : %d", __LINE__); + +#ifdef NDEBUG +#define CASSERT(condition, error_printf...) +#define CASSERT_ALIGNMENT(variable, alignment) +#else +#define CASSERT CREQUIRE +#define CASSERT_ALIGNMENT CREQUIRE_ALIGNMENT +#endif + +SDITH_ALWAYS_INLINE uint64_t alignment_of(uint64_t x) { return (x ^ (x - 1)) >> 1; } + +// irreducible polynomial constant for GF128 +#define GF128_PV 0b10000111 +#define GF192_PV 0b10000111 +#define GF256_PV 0b10000100101 +static const __uint128_t GF128_P = GF128_PV; +static const uint64_t GF256_P = GF256_PV; +static const uint64_t GF192_P = GF192_PV; +static const uint64_t GF121_P = 0b100100011; + +// in the public API, the layout of the fields is OPAQUE +// here, we only provide possible instantiations. +// it is also possible to cast these types to __m128i for instance + +union gf128_t { + uint8_t v[16]; + __uint128_t v128; +}; +union gf121_t { + uint8_t v[16]; + __uint128_t v128; +}; +union gf192_t { + uint8_t v[24]; + uint64_t v64[3]; +}; +union gf256_t { + uint8_t v[32]; + uint64_t v64[4]; +}; + +// Constant-time carryless (GF(2)[x]) multiply helpers used by the reference +// field multiplies. gf_bmul32 is BearSSL's branchless 32x32->64 carryless +// product: only integer multiply, mask and xor, so it has no data-dependent +// branch or memory access and runs in time independent of its operands (the +// integer multiplier is constant-time on the targets we care about, incl. +// Cortex-M4 UMULL). gf_clmul64 combines three gf_bmul32 (Karatsuba) into a +// full 64x64->128 carryless product. +SDITH_ALWAYS_INLINE uint64_t gf_bmul32(uint32_t x, uint32_t y) { + uint32_t x0 = x & 0x11111111u, x1 = x & 0x22222222u, x2 = x & 0x44444444u, x3 = x & 0x88888888u; + uint32_t y0 = y & 0x11111111u, y1 = y & 0x22222222u, y2 = y & 0x44444444u, y3 = y & 0x88888888u; + uint64_t z0 = (uint64_t)x0 * y0 ^ (uint64_t)x1 * y3 ^ (uint64_t)x2 * y2 ^ (uint64_t)x3 * y1; + uint64_t z1 = (uint64_t)x0 * y1 ^ (uint64_t)x1 * y0 ^ (uint64_t)x2 * y3 ^ (uint64_t)x3 * y2; + uint64_t z2 = (uint64_t)x0 * y2 ^ (uint64_t)x1 * y1 ^ (uint64_t)x2 * y0 ^ (uint64_t)x3 * y3; + uint64_t z3 = (uint64_t)x0 * y3 ^ (uint64_t)x1 * y2 ^ (uint64_t)x2 * y1 ^ (uint64_t)x3 * y0; + z0 &= 0x1111111111111111ull; z1 &= 0x2222222222222222ull; + z2 &= 0x4444444444444444ull; z3 &= 0x8888888888888888ull; + return z0 | z1 | z2 | z3; +} +SDITH_ALWAYS_INLINE void gf_clmul64(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) { + uint32_t a0 = (uint32_t)a, a1 = (uint32_t)(a >> 32), b0 = (uint32_t)b, b1 = (uint32_t)(b >> 32); + uint64_t z0 = gf_bmul32(a0, b0); + uint64_t z2 = gf_bmul32(a1, b1); + uint64_t z1 = gf_bmul32(a0 ^ a1, b0 ^ b1) ^ z0 ^ z2; + *lo = z0 ^ (z1 << 32); + *hi = z2 ^ (z1 >> 32); +} + +extern const gf256 GF256_ONE; +extern const gf256 GF256_ZERO; +// functions by value should are for test and assertions purposes only +EXPORT uint8_t gf256v_equals(const gf256 a, const gf256 b); +EXPORT uint8_t gf256v_bitof(const gf256 a, const uint64_t position); +EXPORT gf256 gf256v_sum(const gf256 a, const gf256 b); +EXPORT gf256 gf256v_lsh(const gf256 a, const uint64_t amount); +EXPORT gf256 gf256v_rsh(const gf256 a, const uint64_t amount); +EXPORT gf256 gf256v_mul(const gf256 a, const gf256 b); +// left and right shift by pointer are not part of the private API +EXPORT void gf256p_lsh(gf256* const res, const gf256* const a, const uint64_t amount); +EXPORT void gf256p_rsh(gf256* const res, const gf256* const a, const uint64_t amount); + +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b); + +extern const gf192 GF192_ONE; +extern const gf192 GF192_ZERO; +// functions by value should are for test and assertions purposes only +EXPORT uint8_t gf192v_equals(const gf192 a, const gf192 b); +EXPORT uint8_t gf192v_bitof(const gf192 a, const uint64_t position); +EXPORT gf192 gf192v_sum(const gf192 a, const gf192 b); +EXPORT gf192 gf192v_lsh(const gf192 a, const uint64_t amount); +EXPORT gf192 gf192v_rsh(const gf192 a, const uint64_t amount); +EXPORT gf192 gf192v_mul(const gf192 a, const gf192 b); +// left and right shift by pointer are not part of the private API +EXPORT void gf192p_lsh(gf192* const res, const gf192* const a, const uint64_t amount); +EXPORT void gf192p_rsh(gf192* const res, const gf192* const a, const uint64_t amount); + +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b); + +extern const gf128 GF128_ONE; +extern const gf128 GF128_ZERO; +// functions by value should are for test and assertions purposes only +EXPORT uint8_t gf128v_equals(const gf128 a, const gf128 b); +EXPORT uint8_t gf128v_bitof(const gf128 a, const uint64_t position); +EXPORT gf128 gf128v_sum(const gf128 a, const gf128 b); +EXPORT gf128 gf128v_lsh(const gf128 a, const uint64_t amount); +EXPORT gf128 gf128v_rsh(const gf128 a, const uint64_t amount); +EXPORT gf128 gf128v_mul(const gf128 a, const gf128 b); +// left and right shift by pointer are not part of the private API +EXPORT void gf128p_lsh(gf128* const res, const gf128* const a, const uint64_t amount); +EXPORT void gf128p_rsh(gf128* const res, const gf128* const a, const uint64_t amount); +EXPORT void gf128p_sum(gf128* const res, const gf128* const a, const gf128* const b); +EXPORT void gf128p_mul(gf128* const res, const gf128* const a, const gf128* const b); + +EXPORT void gf128_sum_ref(gf128* res, const gf128* a, const gf128* b); + +// binary valuation +uint16_t binval_of(uint16_t i); +uint16_t grey_of(uint16_t x); +uint16_t inv_grey_of(uint16_t x); + +/** @brief extract/xorto a kappa-bit uint from a bit array. + * data must be 8-byte aligned and its size must be a multiple of 8. */ +EXPORT uint32_t extract_kappabit_uint(uint64_t kappa, uint64_t bitpos, const void* data); +EXPORT void xorto_kappabit_uint(uint64_t kappa, uint64_t bitpos, void* data, uint64_t value); + +/** raise to the power p */ +EXPORT void flambda_power(const vole_parameters* vole_params, flambda_t* res, const flambda_t* x, uint64_t p); + +/** test if a field element is zero (non-ct version) */ +EXPORT uint8_t flambda_is_zero_nonct(const vole_parameters* vole_params, const flambda_t* x); +/** test if a bit vector is zero (non-ct version) */ +EXPORT uint8_t bitvec_is_zero_nonct(const uint8_t* x, uint64_t num_bits); + +#define TMP_SPACE_MAP_ALIGNED(VARTYPE, VARNAME, VARALIGN, BYTE_SIZE) \ + tmp_space = (uint8_t*)(((uint64_t)tmp_space + (VARALIGN - 1)) & (uint64_t)(-(VARALIGN))); \ + VARTYPE VARNAME = (VARTYPE)tmp_space; \ + tmp_space += (BYTE_SIZE) + +#define TMP_SPACE_MAP(VARTYPE, VARNAME, BYTE_SIZE) \ + VARTYPE VARNAME = (VARTYPE)tmp_space; \ + tmp_space += (BYTE_SIZE) + +// this one is empty +#define TMP_SPACE_MAP_CALL(BYTE_SIZE) + +#define COMP_SPACE_INIT() \ + struct tmp_bytes_comp_t ts; \ + tmp_bytes_init(&ts) + +#define COMP_SPACE_MAP_ALIGNED(VARTYPE, VARNAME, VARALIGN, BYTE_SIZE) \ + tmp_bytes_reserve_local_var_aligned(&ts, (VARALIGN), (BYTE_SIZE)) + +#define COMP_SPACE_MAP(VARTYPE, VARNAME, BYTE_SIZE) tmp_bytes_reserve_local_var(&ts, (BYTE_SIZE)) + +#define COMP_SPACE_MAP_CALL(BYTE_SIZE) tmp_bytes_reserve_call(&ts, (BYTE_SIZE)) + +#define COMP_SPACE_RETURN() return ts.max_size + +/** helper structure to compute the tmp space required for functions */ +typedef struct tmp_bytes_comp_t { + uint64_t local_size; // size of local variables + uint64_t max_size; // local variables + calls + uint64_t last_alignment; // last requested local alignment +} tmp_bytes_comp_t; + +EXPORT void tmp_bytes_init(tmp_bytes_comp_t* tmp_bytes_comp); +EXPORT void tmp_bytes_reserve_local_var(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_bytes); +EXPORT void tmp_bytes_reserve_local_var_aligned(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_align, + uint64_t var_bytes); +EXPORT void tmp_bytes_reserve_call(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t call_tmp_bytes); + +EXPORT_DECL const uint8_t HASH_BAVC_PREFIX; +EXPORT_DECL const uint8_t HASH_AUX_PREFIX; +EXPORT_DECL const uint8_t HASH_LINES_PREFIX; +EXPORT_DECL const uint8_t HASH_PIOP_PREFIX; +EXPORT_DECL const uint8_t PROOFOW_H0_PREFIX; +EXPORT_DECL const uint8_t PROOFOW_H1_PREFIX; +EXPORT_DECL const uint64_t PROOFOW_CTR_REVEALED_BYTES; + +// sdith parameters: deduced parameter set +typedef struct extended_parameters_t { + uint64_t lambda; + uint64_t kappa; + uint64_t tau; + uint64_t target_topen; + uint64_t rsd_n; + uint64_t rsd_w; + uint64_t mux_arities[8]; + uint64_t mux_depth; + uint64_t rsd_npw; + uint64_t rsd_codim; + uint64_t proofow_w; + uint64_t delta0_bits; + uint64_t delta0_dwords; + uint64_t delta0_bytess; + uint64_t delta0_capacity; + vole_parameters vole_params; + uint64_t mux_inputs; + uint64_t chall_unitary_powers; + uint64_t degree; + uint64_t num_inputs_pairs; + uint64_t num_cchk_pairs; + uint64_t num_cz_pairs; + uint64_t real_L; + uint64_t L; + uint64_t Lbyte; + uint64_t Lslice; + uint64_t lambda_bytes; + uint64_t cchk_matrix_nrows; + uint64_t cchk_matrix_ncols; + uint64_t rsd_codim_bytes; + uint64_t rsd_codim_limbs; + uint64_t rsd_codim_slice; // byte slice if we store the full matrix H (multiple of the rng block) +} extended_parameters_t; + +/** compute the rsd codim slice (bytes), accounting for the prng block size and the actual bitsize */ +EXPORT void compute_rsd_codim_slice( + uint64_t* rsd_codim_limbs, // [out] number of limbs + uint64_t* rsd_codim_slice, // [out] number of slice bytes to hold the prng blocks + const uint64_t lambda, const uint64_t rsd_codim); + +EXPORT void compute_extended_parameters(extended_parameters_t* res, const signature_parameters* sig_params); + +EXPORT uint32_t ceil_log2i(uint32_t x); + +#endif // AQ_VOLE_IMPL_VOLE_PRIVATE_H diff --git a/src/sig/sdith/sdith_sdith_common/vole_to_piop.c b/src/sig/sdith/sdith_sdith_common/vole_to_piop.c new file mode 100644 index 0000000000..ac936b613e --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common/vole_to_piop.c @@ -0,0 +1,208 @@ +#include + +#include "vole_private.h" + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void prover_f2_to_flambda_deg1_std_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + fpoly_t* out_f, // [out] deg-1 fpoly[num_pairs] + const bitvec_t* in_u, // [in] in_L bits where in_L = num_pairs * LAMBDA + const flambda_t* in_v) // [in] flambda[in_L] +{ + uint8_t* out = (uint8_t*)out_f; + const uint8_t* u = (uint8_t*)in_u; + const uint8_t* v = (uint8_t*)in_v; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t lambda = vole_params->LAMBDA; + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_v, alignment_of(lambda_bytes)); + + for (size_t i = 0; i < num_pairs; i++) { + (*vole_params->flambda_sum_pow2)(out + lambda_bytes * 2 * i, v + lambda_bytes * lambda * i); + memcpy(out + lambda_bytes * (2 * i + 1), u + lambda_bytes * i, lambda_bytes); + } +} + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void verifier_f2_to_flambda_deg1_std_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + flambda_t* out_q, // [out] gflambda[num_pairs] + const flambda_t* in_q) // [in] gflambda in_q[in_L] where in_L = num_pairs * LAMBDA +{ + uint8_t* out = (uint8_t*)out_q; + const uint8_t* in = (uint8_t*)in_q; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t lambda = vole_params->LAMBDA; + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + + for (size_t i = 0; i < num_pairs; i++) { + (*vole_params->flambda_sum_pow2)(out + lambda_bytes * i, in + lambda_bytes * lambda * i); + } +} + +/** + * convert d degree 1 std-vole over flambda to one degree-d vole + */ +EXPORT void prover_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + fpoly_t* out_f, // single poly_t of degree out_degree + const fpoly_t* in_f) // out_degree poly[out_degree] +{ + CASSERT(out_degree > 0, "degree 0 is not supported"); + // this function can work in place + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_f, alignment_of(lambda_bytes)); + const uint8_t* const in = (uint8_t*)in_f; + uint8_t* const out = (uint8_t*)out_f; + + // copy first coefficient of first polynomial to out_f + vole_params->flambda_set(out, in); + + for (size_t i = 1; i < out_degree; i++) { + (*vole_params->flambda_sum)(out + lambda_bytes * i, // result + in + lambda_bytes * (2 * i), // low coefficient of i-th in_f poly + in + lambda_bytes * (2 * i - 1) // high coefficient of (i-1)-th in_f poly + ); + } + + // copy second coefficient of last polynomial to out_f + vole_params->flambda_set(out + out_degree * lambda_bytes, in + (2 * out_degree - 1) * lambda_bytes); +} + +/** + * convert d degree 1 std-vole to one degree-d vole + */ +EXPORT void verifier_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + flambda_t* out_q, // [out] single gflambda + const flambda_t* in_q, // [in] gflambda[out_deg] + const flambda_t* delta) // verifier's point powers +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(delta, alignment_of(lambda_bytes)); + const uint8_t* const in = (uint8_t*)in_q; + uint8_t* const out = (uint8_t*)out_q; + // we use a temporary so that the function works in place + flambda_max_t tmp; + + (*vole_params->flambda_set)(tmp, in + (out_degree - 1) * lambda_bytes); + for (int64_t i = out_degree - 2; i >= 0; i--) { + (*vole_params->flambda_product)(tmp, tmp, delta); + (*vole_params->flambda_sum)(tmp, tmp, in + i * lambda_bytes); + } + (*vole_params->flambda_set)(out, tmp); +} + +/** + * convert a degree-d vole from std to cst + */ +EXPORT void prover_flambda_degd_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // degree d of of the pair to process + fpoly_t* out_f, // [out] single poly of degree d + const fpoly_t* in_f) // [in] single poly of degree d +{ + // mirror f + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_f, alignment_of(lambda_bytes)); + uint8_t* res = (uint8_t*)out_f; + const uint8_t* in = (const uint8_t*)in_f; + if (in_f == out_f) { + // in place variant + uint64_t half_d = (degree + 1) >> 1; + for (uint64_t i = 0; i < half_d; i++) { + uint8_t* r1 = res + i * lambda_bytes; + uint8_t* r2 = res + (degree - i) * lambda_bytes; + // swap r1 <-> r2 + vole_params->flambda_sum(r1, r1, r2); + vole_params->flambda_sum(r2, r2, r1); + vole_params->flambda_sum(r1, r1, r2); + } + } else { + // out of place variant + for (uint64_t i = 0; i <= degree; i++) { + memcpy(res + i * lambda_bytes, in + (degree - i) * lambda_bytes, lambda_bytes); + } + } +} + +/** + * convert d degree 1 std-vole to one degree-d cst-vole + */ +EXPORT void verifier_flambda_degd_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // output degree + flambda_t* out_q, // [out] single evaluation + const flambda_t* in_q, // [in] single evaluation + const flambda_t* delta_pow_d) // [in] verifier's point to the power d +{ +#ifndef NDEBUG + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CREQUIRE_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CREQUIRE_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + CREQUIRE_ALIGNMENT(delta_pow_d, alignment_of(lambda_bytes)); +#endif + vole_params->flambda_product(out_q, in_q, delta_pow_d); +} + +/** + * convert packed degree 1 std-vole to packed cst-vole + */ +EXPORT void prover_f2_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + bitvec_t* out_u, flambda_t* out_v, // [out] bit[num_pairs], flambda[num_pairs] + const bitvec_t* in_u, const flambda_t* in_v) // [in] bit[num_pairs], flambda[num_pairs] +{ +#ifndef NDEBUG + uint64_t lambda_bytes = vole_params->lambda_bytes; + CREQUIRE_ALIGNMENT(in_v, alignment_of(lambda_bytes)); + CREQUIRE_ALIGNMENT(out_v, alignment_of(lambda_bytes)); +#endif + if (in_u == out_u && in_v == out_v) return; + memcpy(out_u, in_u, (num_pairs + 7) >> 3); + memcpy(out_v, in_v, vole_params->lambda_bytes * num_pairs); +} + +/** + * convert packed degree 1 std-vole to packed cst-vole + */ +EXPORT void verifier_f2_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + flambda_t* out_q, // [out] gflambda[num_pairs] + const flambda_t* in_q, // [in] gflambda[num_pairs] + const flambda_t* delta2) // [in] verifier's point +{ + const uint8_t* in = (uint8_t*)in_q; + uint8_t* out = (uint8_t*)out_q; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + + for (size_t i = 0; i < num_pairs; i++) { + (*vole_params->flambda_product)(out + lambda_bytes * i, in + lambda_bytes * i, delta2); + } +} + +/** @brief converts delta1 to delta2 + * delta2 is the field inverse of delta1 + */ +EXPORT void delta2_from_delta1_ref(const vole_parameters* vole_params, flambda_t* delta2, const flambda_t* delta1) { + vole_params->flambda_inverse(delta2, delta1); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/LICENSE.txt b/src/sig/sdith/sdith_sdith_common_avx2/LICENSE.txt new file mode 100644 index 0000000000..599479c32a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/LICENSE.txt @@ -0,0 +1,235 @@ +======================================================================== +Apache 2.0 License +======================================================================== + 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. + +======================================================================== +Third-Party Components & Subcomponent Licenses +======================================================================== +This software includes the following third-party components under distinct licenses: + +lib/sha3: + copied from The eXtended Keccak Code Package (XKCP) (multiple licenses) + https://github.com/XKCP/XKCP + only build files have been edited (CMakeLists.txt) + +lib/aes/aes_ansi_ref.c/.h: + ANSI C Rijndael code by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto -- public domain + A little-endian version of the algorithm is provided in aes_ansi_littleendian_ref.c + the avx implementation via the aes-ni instructions are new, and covered by the main repository license. + +lib/aes/rijndael256_avx.c/.h: + The following part is adapted from a work by Nir Drucker and Shay Gueron: + Software optimization of Rijndael for Modern x86_64 platforms, + in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) + Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. + (SPDX-License-Identifier: Apache-2.0) + +kat/*/PQCgenKAT_sign.c, rng.c, rng.h: + NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the + software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative + works of the software or any portion of the software, and you may copy and distribute such modifications or works. + Modified works should carry a notice stating that you changed the software and should note the date and nature of any + such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the + software. + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/NOTICE b/src/sig/sdith/sdith_sdith_common_avx2/NOTICE new file mode 100644 index 0000000000..f372dc9e28 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/NOTICE @@ -0,0 +1,28 @@ +Copyright 2026 The SDitH Consortium + +This product includes software developed by: + +lib/sha3: + copied from The eXtended Keccak Code Package (XKCP) (multiple licenses) + https://github.com/XKCP/XKCP + only build files have been edited (CMakeLists.txt) + +lib/aes/aes_ansi_ref.c/.h: + ANSI C Rijndael code by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto -- public domain + A little-endian version of the algorithm is provided in aes_ansi_littleendian_ref.c + the avx implementation via the aes-ni instructions are new, and covered by the main repository license. + +lib/aes/rijndael256_avx.c/.h: + The following part is adapted from a work by Nir Drucker and Shay Gueron: + Software optimization of Rijndael for Modern x86_64 platforms, + in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) + Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. + (SPDX-License-Identifier: Apache-2.0) + +kat/*/PQCgenKAT_sign.c, rng.c, rng.h: + NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the + software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative + works of the software or any portion of the software, and you may copy and distribute such modifications or works. + Modified works should carry a notice stating that you changed the software and should note the date and nature of any + such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the + software. diff --git a/src/sig/sdith/sdith_sdith_common_avx2/aes128_ctrle.h b/src/sig/sdith/sdith_sdith_common_avx2/aes128_ctrle.h new file mode 100644 index 0000000000..49c95440e1 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/aes128_ctrle.h @@ -0,0 +1,79 @@ +#ifndef AES128_CTRLE_H +#define AES128_CTRLE_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif +#include "rijndael256_ctrle.h" + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +/** (special API) batched key schedule: expand 1..4 independent aes128 keys into + * 1..4 round-key buffers (each 16*11 bytes). Output is bit-identical to + * aes128_ctrle_set_key, so these are KAT-preserving. The x2/x3/x4 avx2 variants + * interleave the expansions to hide latency; the ref variants just loop. */ +EXPORT void aes128_key_schedule_x1_ref(void* rk0, const void* k0); +EXPORT void aes128_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void aes128_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, const void* k2); +EXPORT void aes128_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); +EXPORT void aes128_key_schedule_x1_avx2(void* rk0, const void* k0); +EXPORT void aes128_key_schedule_x2_avx2(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void aes128_key_schedule_x3_avx2(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, const void* k2); +EXPORT void aes128_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); + +/** (special API) no-carry CTR encryption. Encrypts N consecutive blocks: + * out[i] = AES(round_keys, ctr_block with its low 64 bits += i), for i in 0..N-1. + * Only the low 64 bits of the counter are incremented (no carry into the upper + * 64 bits). Stateless: ctr_block (16 bytes) is not modified. The fixed-size + * building blocks chain into aes128_ctrle_nocarry_nblocks (advance the low-64 + * counter by the group size between calls). */ +EXPORT void aes128_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_3blocks_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_4blocks_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, uint64_t nblocks); +EXPORT void aes128_ctrle_nocarry_1block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_2block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_3blocks_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_4blocks_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void aes128_ctrle_nocarry_nblocks_avx2(void* out, const void* round_keys, const void* ctr_block, uint64_t nblocks); +// 4 keys x 2 counter blocks (8 blocks) interleaved: for key i (round keys at round_keys4 + i*176, +// base counter at ctr4blk + i*16) writes enc(ctr_i) || enc(ctr_i+1) to out + i*32. Byte-identical +// to four aes128_ctrle_nocarry_2block_avx2 calls (KAT-preserving); keeps 8 aesenc in flight. +EXPORT void aes128_ctrle_nocarry_2blk_x4keys_avx2(void* out, const void* round_keys4, const void* ctr4blk); + +/** + * (special API) AES proof-of-work grind over two independent keys. + * Encrypts the two plaintext blocks in_pt256 (p0 || p1, 32 bytes) under the two round-key sets + * rk128 (rk[2][11], 352 bytes), + * If the ciphertexts satisfy the grinding condition: ((c0.lo64 ^ c1.lo64) & mask_w) == 0, success: + * return store the counter and the ciphertexts and return 1. + * Otherwise, increment the counter and the plaintexts by 1 (no carry into the high 64 bits) and restart. + * If the counter reaches 2^32 with no hit, stores 2^32 in *in_out_counter and returns 0. + * The winning counter is the smallest one in [initial, 2^32). + */ +EXPORT int aes128_proofow_grind_avx2( // + void* out_ct256, // [out] c0 || c1 (32 bytes) satisfying low64(c0 ^ c1) & mask_w == 0 + uint64_t* in_out_counter, // [in/out] starting counter (< 2^32) + const void* in_pt256, // [in] p0 || p1 (32 bytes) the initial plaintexts + const void* rk128, // [in] matrix of round keys v128[2][11] + uint64_t mask_w // [in] the grinding condition +); + +typedef union { + __uint128_t u128; + uint64_t v64[2]; + uint8_t v8[16]; +} ctr128_t; + +#endif // AES128_CTRLE_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/aes128_ctrle_special_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/aes128_ctrle_special_avx2.c new file mode 100644 index 0000000000..d443de8bd9 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/aes128_ctrle_special_avx2.c @@ -0,0 +1,280 @@ +/* Batched AES-128 key schedule for SDitH — lossless drop-in for aes128_ctrle_set_key_avx2. + * + * Produces round keys BIT-IDENTICAL to aes128_ctrle_set_key_avx2 (verified 0/4096 random keys), + * so it is KAT-preserving (no spec change). Uses aesenclast for the SubWord instead of the serial, + * call-per-round aeskeygenassist chain, and expands 4 independent keys at once to hide latency. + * + * Measured on Intel Xeon 8259CL @2.5GHz, AVX2/AES-NI (no VAES), taskset -c0, min-over-4000 reps: + * aes128_ctrle_set_key_avx2 (current): ~142 cyc/key + * aes128_keyexp_x4_enclast (this): ~36 cyc/key (3.9x faster) + * aes128_keyexp_x1_enclast (1-key): faster than set_key too (drops the 10 helper calls) + * (FAEST's 8-way + transposed cascade reaches ~16 cyc/key; the last 36->16 is a transposed cascade.) + * + * Round-key layout is unchanged: 11 round keys x 16 B = 176 B per key, contiguous (same as set_key). + * Build: gcc/clang -O3 -mavx2 -maes -mpclmul. cat1 AES-128 only. + * + * Usage in the GGM/VOLE loops: process independent seeds in groups of 4 with the x4 function + * (leaf commit + VOLE-PRG are all independent -> trivially batchable); for the <4 remainder use the + * x1 function (or the existing set_key). seed_rng batching needs level-order tree traversal (follow-up). + */ +#include +#include + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +/* new round key = g ^ w ^ (w<<4) ^ (w<<8) ^ (w<<12), with g broadcast to all 4 words. + * The w-terms are a byte-word prefix-XOR of w, which factors into log steps: + * a = w ^ (w<<4) -> [w0, w0^w1, w1^w2, w2^w3] + * t = a ^ (a<<8) -> [w0, w0^w1, w0^w1^w2, w0^w1^w2^w3] + * so the whole cascade is t ^ g. This drops one pslldq and one xor per key per + * round (the key schedule is port-5 bound: pslldq/pshufb both issue only on p5). + * Byte-identical output -> KAT-preserving. */ +static inline __m128i sdith_aes_cascade(__m128i w, __m128i g){ + __m128i a = _mm_xor_si128(w, _mm_slli_si128(w, 4)); + __m128i t = _mm_xor_si128(a, _mm_slli_si128(a, 8)); + return _mm_xor_si128(t, g); +} + +/* g = SubWord(RotWord(w3)) ^ (rcon in byte0), broadcast to all 4 words. + * RWBC broadcasts RotWord(w3) to every 32-bit word, so aesenclast's ShiftRows is the identity + * (all 4 state columns equal) => aesenclast == pure SubBytes; set1_epi32(rcon) injects Rcon in byte0. */ +#define SDITH_ENC_G(w, rc, RWBC) \ + _mm_aesenclast_si128(_mm_shuffle_epi8((w), (RWBC)), _mm_set1_epi32(rc)) + +/* 4-way: expand 4 independent AES-128 keys, each into a 16*11-byte round_keys buffer. */ +void aes128_keyexp_x4_enclast(uint8_t* rk0, uint8_t* rk1, uint8_t* rk2, uint8_t* rk3, + const uint8_t* k0, const uint8_t* k1, + const uint8_t* k2, const uint8_t* k3){ + const __m128i RWBC = _mm_setr_epi8(13,14,15,12, 13,14,15,12, 13,14,15,12, 13,14,15,12); + __m128i w0=_mm_loadu_si128((const __m128i*)k0), w1=_mm_loadu_si128((const __m128i*)k1); + __m128i w2=_mm_loadu_si128((const __m128i*)k2), w3=_mm_loadu_si128((const __m128i*)k3); + _mm_storeu_si128((__m128i*)rk0,w0); _mm_storeu_si128((__m128i*)rk1,w1); + _mm_storeu_si128((__m128i*)rk2,w2); _mm_storeu_si128((__m128i*)rk3,w3); + int off = 16; + static const int RC[10] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36}; + for (int r=0; r<10; r++){ + w0=sdith_aes_cascade(w0, SDITH_ENC_G(w0,RC[r],RWBC)); + w1=sdith_aes_cascade(w1, SDITH_ENC_G(w1,RC[r],RWBC)); + w2=sdith_aes_cascade(w2, SDITH_ENC_G(w2,RC[r],RWBC)); + w3=sdith_aes_cascade(w3, SDITH_ENC_G(w3,RC[r],RWBC)); + _mm_storeu_si128((__m128i*)(rk0+off),w0); _mm_storeu_si128((__m128i*)(rk1+off),w1); + _mm_storeu_si128((__m128i*)(rk2+off),w2); _mm_storeu_si128((__m128i*)(rk3+off),w3); + off += 16; + } +} + +/* 1-way: same signature as aes128_ctrle_set_key_avx2, for the <4 remainder. */ +//void aes128_keyexp_x1_enclast(void* round_keys, const void* aes128key){ +void aes128_ctrle_set_key_avx2(void* round_keys, const void* aes128key){ + const __m128i RWBC = _mm_setr_epi8(13,14,15,12, 13,14,15,12, 13,14,15,12, 13,14,15,12); + uint8_t* rk = (uint8_t*)round_keys; + __m128i w = _mm_loadu_si128((const __m128i*)aes128key); + _mm_storeu_si128((__m128i*)rk, w); + int off = 16; + static const int RC[10] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36}; + for (int r=0; r<10; r++){ + w = sdith_aes_cascade(w, SDITH_ENC_G(w,RC[r],RWBC)); + _mm_storeu_si128((__m128i*)(rk+off), w); + off += 16; + } +} + +/* ================================================================================================ + * Canonical batched key schedule (x1..x4) + no-carry CTR encryption. + * Same round-key layout as aes128_ctrle_set_key_avx2 (KAT-preserving). The x2/x3 + * expansions interleave independent keys to hide the aesenclast latency (like x4). + * ============================================================================================== */ +static const int SDITH_RC10[10] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36}; + +void aes128_key_schedule_x1_avx2(void* rk0, const void* k0) { aes128_ctrle_set_key_avx2(rk0, k0); } + +void aes128_key_schedule_x2_avx2(void* rk0, void* rk1, const void* k0, const void* k1) { + const __m128i RWBC = _mm_setr_epi8(13,14,15,12, 13,14,15,12, 13,14,15,12, 13,14,15,12); + uint8_t *r0=(uint8_t*)rk0, *r1=(uint8_t*)rk1; + __m128i w0=_mm_loadu_si128((const __m128i*)k0), w1=_mm_loadu_si128((const __m128i*)k1); + _mm_storeu_si128((__m128i*)r0,w0); _mm_storeu_si128((__m128i*)r1,w1); + int off=16; + for (int r=0;r<10;r++){ + w0=sdith_aes_cascade(w0, SDITH_ENC_G(w0,SDITH_RC10[r],RWBC)); + w1=sdith_aes_cascade(w1, SDITH_ENC_G(w1,SDITH_RC10[r],RWBC)); + _mm_storeu_si128((__m128i*)(r0+off),w0); _mm_storeu_si128((__m128i*)(r1+off),w1); + off+=16; + } +} + +void aes128_key_schedule_x3_avx2(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, const void* k2) { + const __m128i RWBC = _mm_setr_epi8(13,14,15,12, 13,14,15,12, 13,14,15,12, 13,14,15,12); + uint8_t *r0=(uint8_t*)rk0, *r1=(uint8_t*)rk1, *r2=(uint8_t*)rk2; + __m128i w0=_mm_loadu_si128((const __m128i*)k0), w1=_mm_loadu_si128((const __m128i*)k1), + w2=_mm_loadu_si128((const __m128i*)k2); + _mm_storeu_si128((__m128i*)r0,w0); _mm_storeu_si128((__m128i*)r1,w1); _mm_storeu_si128((__m128i*)r2,w2); + int off=16; + for (int r=0;r<10;r++){ + w0=sdith_aes_cascade(w0, SDITH_ENC_G(w0,SDITH_RC10[r],RWBC)); + w1=sdith_aes_cascade(w1, SDITH_ENC_G(w1,SDITH_RC10[r],RWBC)); + w2=sdith_aes_cascade(w2, SDITH_ENC_G(w2,SDITH_RC10[r],RWBC)); + _mm_storeu_si128((__m128i*)(r0+off),w0); _mm_storeu_si128((__m128i*)(r1+off),w1); + _mm_storeu_si128((__m128i*)(r2+off),w2); + off+=16; + } +} + +void aes128_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + aes128_keyexp_x4_enclast((uint8_t*)rk0,(uint8_t*)rk1,(uint8_t*)rk2,(uint8_t*)rk3, + (const uint8_t*)k0,(const uint8_t*)k1,(const uint8_t*)k2,(const uint8_t*)k3); +} + +/* encrypt n (1..4) independent counter blocks under one expanded key, interleaved. */ +static inline void sdith_aes_encN(uint8_t* out, const uint8_t* rk, __m128i* s, int n) { + __m128i k = _mm_loadu_si128((const __m128i*)rk); + for (int j=0;j0) { + __m128i s[4]; + for (int j=0;j + +#include "aes128_ctrle.h" +#include "aes_ansi_ref.h" + +#ifdef SDITH3_FOR_LIBOQS +#include +#endif + +/* -------- batched key schedule (ref: just loop the scalar x1) -------- */ +EXPORT void aes128_key_schedule_x1_ref(void* rk0, const void* k0) { aes128_set_key_ref(rk0, k0); } +EXPORT void aes128_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1) { + aes128_set_key_ref(rk0, k0); + aes128_set_key_ref(rk1, k1); +} +EXPORT void aes128_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, const void* k0, const void* k1, + const void* k2) { + aes128_set_key_ref(rk0, k0); + aes128_set_key_ref(rk1, k1); + aes128_set_key_ref(rk2, k2); +} +EXPORT void aes128_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + aes128_set_key_ref(rk0, k0); + aes128_set_key_ref(rk1, k1); + aes128_set_key_ref(rk2, k2); + aes128_set_key_ref(rk3, k3); +} + +/* -------- no-carry CTR encryption (ref) -------- + * block i uses the counter with only its low 64 bits incremented by i; there is + * no carry into the upper 64 bits (that is the caller's guarantee). */ +static inline void aes128_nocarry_ref_impl(void* out, const void* round_keys, const void* ctr_block, uint64_t nblocks) { + ctr128_t ctr; + uint8_t* oo = (uint8_t*)out; + memcpy(ctr.v8, ctr_block, 16); +#ifndef SDITH3_FOR_LIBOQS + /* reference implementation */ + for (uint64_t i = 0; i < nblocks; ++i) { + aes128_encrypt_1block_ref(oo + 16 * i, ctr.v8, round_keys); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } +#else + /* LIBOQS implementation: round_keys caches a schedule pointer (see aes_glue.c), + * it is not a raw key. ECB over nblocks*16 bytes is nblocks independent block + * encryptions, so the whole counter run goes out in a single call. */ + void* schedule = NULL; + memcpy(&schedule, round_keys, sizeof(void*)); + for (uint64_t i = 0; i < nblocks; ++i) { + memcpy(oo + 16 * i, ctr.v8, 16); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } + OQS_AES128_ECB_enc_sch(oo, 16 * nblocks, schedule, oo); +#endif +} +EXPORT void aes128_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 1); +} +EXPORT void aes128_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 2); +} +EXPORT void aes128_ctrle_nocarry_3blocks_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 3); +} +EXPORT void aes128_ctrle_nocarry_4blocks_ref(void* out, const void* round_keys, const void* ctr_block) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, 4); +} +EXPORT void aes128_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + aes128_nocarry_ref_impl(out, round_keys, ctr_block, nblocks); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/aes_ansi_ref.h b/src/sig/sdith/sdith_sdith_common_avx2/aes_ansi_ref.h new file mode 100644 index 0000000000..5032734aed --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/aes_ansi_ref.h @@ -0,0 +1,56 @@ +#ifndef AES_ANSI_REF_H +#define AES_ANSI_REF_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +/* References implimentations */ + +/* aes128 reference implementation of the key scheduling (warning:big endian round keys) */ +EXPORT void aes128_set_key_ref(void* rk, const void* key128); +/* aes128 reference implementation of the encryption (1 single block) */ +EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk); + + +/* LIBOQS integration glue */ + +/* The below functions are either no-ops or just call the above functions when + * not building for liboqs. When building for liboqs,`integration/liboqs/aes_glue.c` + * impliments these to dispatch to liboqs' AES. + * + * LIBOQS uses a heap-allocated schedule for each key, so a single schedule + * pointer is written into each round-key buffer instead of the round keys + * themselves, and that schedule is replaced when the buffer is reused. The + * following functions help to prepare, reuse, and release the round-key + * buffers. + */ + +/* Prepare an nslots x slot_bytes array of round-key buffers. + * + * Marks every slot empty, so that the first aes128_set_key_reuse_ref call on a + * slot loads a schedule and every later one replaces it. + */ +EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes); + +/* Replace the key of the schedule held by a prepared buffer. + * + * @warning The buffer MUST have been prepared with aes128_prepare_rk_buffer first. + */ +EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128); + +/* Release a key schedule created by aes128_set_key_ref or aes128_set_key_reuse_ref. + * A no-op on a prepared buffer whose slot was never keyed. */ +EXPORT void aes128_release_key(void *rk); + +#endif // AES_ANSI_REF_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/aes_glue.c b/src/sig/sdith/sdith_sdith_common_avx2/aes_glue.c new file mode 100644 index 0000000000..6b80b56ee7 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/aes_glue.c @@ -0,0 +1,48 @@ +#include + +#include "aes_ansi_ref.h" + +#include +#include + + +EXPORT void aes128_set_key_ref(void* rk, const void* key128) { + // Allocates a schedule via liboqs and writes the pointer to the schedule into the rk buffer + void* schedule = NULL; + OQS_AES128_ECB_load_schedule(key128, &schedule); + memcpy(rk, &schedule, sizeof(void*)); +} + +EXPORT void aes128_encrypt_1block_ref(void* out_ct128, const void* in_pt128, const void* rk) { + // Interprets first sizeof(void *) bytes of rk as a schedule pointer for liboqs ctx + void* schedule = NULL; + memcpy(&schedule, rk, sizeof(void*)); + OQS_AES128_ECB_enc_sch(in_pt128, 16, schedule, out_ct128); +} + +EXPORT void aes128_prepare_rk_buffer(void* rk, uint64_t nslots, uint64_t slot_bytes) { + // Marks every slot empty by zeroing its schedule pointer. + // No schedule is allocated here: `aes128_set_key_reuse_ref` does this in a later call + uint8_t* p = (uint8_t*) rk; + for (uint64_t i = 0; i < nslots; ++i) { + memset(p + i * slot_bytes, 0, sizeof(void*)); + } +} + +EXPORT void aes128_set_key_reuse_ref(void* rk, const void* key128) { + // The slot holds a schedule rather than round keys, so replacing the key means + // freeing any schedule already there and loading a new one in its place. + aes128_release_key(rk); + aes128_set_key_ref(rk, key128); +} + + +EXPORT void aes128_release_key(void* rk) { + // Interprets first sizeof(void *) bytes of rk as a schedule pointer for liboqs ctx + void* schedule = NULL; + memcpy(&schedule, rk, sizeof(void*)); + // An empty slot has nothing to free. + if (schedule == NULL) return; + OQS_AES128_free_schedule(schedule); + OQS_MEM_cleanse(rk, sizeof(void*)); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/commons.c b/src/sig/sdith/sdith_sdith_common_avx2/commons.c new file mode 100644 index 0000000000..bcc761f001 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/commons.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include + +#include "sdith_prng.h" +#include "vole_private.h" + +/** binary valuation of i (also known as hamming weight of i ^ (i - 1) - 1) */ +uint16_t binval_of(uint16_t i) { + CASSERT(i != 0, "binval_of(0) is undefined"); + return __builtin_ctz(i); +} + +// compat function, to use in case of the builtin above does not exist +uint16_t binval_of_compat(uint16_t i) { + uint16_t u = i ^ (i - 1) ^ 1; + // return _mm_popcnt_u32(u); + u = (u & 0x5555) + ((u >> 1) & 0x5555); + u = (u & 0x3333) + ((u >> 2) & 0x3333); + u = (u & 0x0f0f) + ((u >> 4) & 0x0f0f); + u = (u & 0x00ff) + ((u >> 8) & 0x00ff); + return u; +} + +/** grey encoding of x */ +uint16_t grey_of(uint16_t x) { return x ^ (x >> 1); } + +/** inverse o grey encoding of x */ +uint16_t inv_grey_of(uint16_t x) { + uint16_t u = x; + for (uint16_t i = 1; i < 16; ++i) { + u ^= (x >> i); + } + return u; +} + +/** value of the pos-th bit of x (little endian index) */ +uint8_t bit_of(uint16_t x, uint16_t pos) { return (x >> pos) & 1; } + + +/** raise to the power p */ +EXPORT void flambda_power(const vole_parameters* vole_params, flambda_t* res, const flambda_t* x, uint64_t p) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + flambda_max_t tx; + memcpy(tx, x, lambda_bytes); + memset(res, 0, lambda_bytes); + *((uint8_t*)res) = 1; + // invariant: res * tx^p = cst + while (p > 0) { + if (p & 1) { + vole_params->flambda_product(res, res, tx); + --p; + } + if (p == 0) break; + vole_params->flambda_product(tx, tx, tx); + p >>= 1; + } +} + +/** test if a field element is zero (non-ct version) */ +EXPORT uint8_t flambda_is_zero_nonct(const vole_parameters* vole_params, const flambda_t* x) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint8_t* const xx = (const uint8_t*)x; + for (uint64_t i = 0; i < lambda_bytes; ++i) { + if (xx[i]) return 0; + } + return 1; +} + +/** test if a bit vector is zero (non-ct version) */ +EXPORT uint8_t bitvec_is_zero_nonct(const uint8_t* x, uint64_t num_bits) { + while (num_bits >= 8) { + if (*x) return 0; + ++x; + num_bits -= 8; + } + if (num_bits > 0) { + uint8_t mask = ((uint8_t)(1) << num_bits) - 1; + if ((*x) & mask) return 0; + } + return 1; +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/commons.h b/src/sig/sdith/sdith_sdith_common_avx2/commons.h new file mode 100644 index 0000000000..d30521b080 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/commons.h @@ -0,0 +1,55 @@ +#ifndef COMMONS_H +#define COMMONS_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#define EXPORT_DECL extern "C" +#include +#else +#define EXPORT +#define EXPORT_DECL extern +#include "stdint.h" +#endif + +#ifdef __x86_64__ +#define CPU_SUPPORTS(feature) __builtin_cpu_supports(feature) +#endif + +/* Namespacing with the appropriate prefix */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +typedef void bitvec_t; // vector of bits row major (dimensions provided at runtime) +typedef void bitmat_t; // matrix of bits row major (dimensions provided at runtime) +typedef void flambda_t; // at runtime, the size of a big fielf elem is lam (i.e. lambda/8) +typedef void fpoly_t; // at runtime, the size of a degree d is (d+1).lam +typedef void seed_t; // at runtime, the size of a commit is 1.lam +typedef void salt_t; // at runtime, the size of a commit is 1.lam +typedef void hash_t; // at runtime, the size of a hash is 2.lam +typedef void commit_t; // at runtime, the size of a commit is 2.lam +typedef void hash_ctx_t; + +// type large enough to hold one field element +typedef uint64_t flambda_max_t[4] __attribute((aligned(32))); // usable as data type for temporary variables + +typedef enum proofow_variant_t { + PROOFOW_VARIANT_SHAKE = 0, + PROOFOW_VARIANT_CIPHER = 1 +} proofow_variant_t; + +#endif // COMMONS_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/ct_utils.c b/src/sig/sdith/sdith_sdith_common_avx2/ct_utils.c new file mode 100644 index 0000000000..950f4a6164 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/ct_utils.c @@ -0,0 +1,89 @@ +#include "sdith_ct_utils.h" + +#include + +#include "vole_private.h" + +// Reference constant-time helpers. +// +// As stated in sdith_ct_utils.h, these are the readable definitions, not the +// hardened implementations: they say what each function computes, and the _avx +// ones in ct_utils_avx2.c say how to compute it without giving the compiler +// room to reintroduce a branch. A C compiler may legally turn any of the masks +// below back into a conditional jump, so a build that must actually be +// constant-time has to use the _avx table. + +EXPORT uint64_t mask_lt_ct_ref(uint64_t secret_a, uint64_t secret_b) { + return -(uint64_t)(secret_a < secret_b); +} + +EXPORT uint64_t mask_eq_ct_ref(uint64_t secret_a, uint64_t secret_b) { + return -(uint64_t)(secret_a == secret_b); +} + +// Schoolbook restoring division, most significant bit first: bring one bit of n +// down into the remainder, and subtract d whenever the remainder has grown past +// it. rem stays below 2*d < 2^33, hence the 64-bit accumulator. +EXPORT void div_rem_u32_ct_ref(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d) { + CREQUIRE(public_d != 0, "division by zero"); + uint64_t rem = 0; + uint32_t quo = 0; + for (int64_t i = 31; i >= 0; --i) { + rem = (rem << 1) | ((secret_n >> i) & 1); + if (rem >= public_d) { + rem -= public_d; + quo |= (uint32_t)1 << i; + } + } + *q = quo; + *r = (uint32_t)rem; +} + +// res ^= b, or res unchanged, depending on the mask: a whole-vector select +// written as an AND so that both outcomes run the same instructions. +EXPORT void bitvec_xor_to_masked_ct_ref(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask) { + uint8_t* const r = (uint8_t*)res; + const uint8_t* const b = (const uint8_t*)secret_b; + const uint8_t m8 = (uint8_t)secret_mask; + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] ^= b[i] & m8; + } +} + +// The field lands at a position known to the attacker, so the bytes it touches +// can be addressed directly: only the bits being written are secret. Both the +// offset and the width are public, so the byte range is exact -- the caller's +// vector never needs slack past the last field. +EXPORT void bitvec_xoru32_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value) { + uint8_t* const r = (uint8_t*)res; + CREQUIRE(public_nbits <= 32, "field too wide (%" PRId64 " bits)", public_nbits); + const uint64_t first_byte = public_bitpos >> 3; + const uint64_t shift = public_bitpos & 7; + const uint64_t nbytes = (shift + public_nbits + 7) >> 3; + CREQUIRE(first_byte + nbytes <= bytelen, // + "field [%" PRId64 ",+%" PRId64 ") out of range (bytelen %" PRId64 ")", public_bitpos, public_nbits, bytelen); + // keep only the low public_nbits bits: the width is public, so is the mask + const uint32_t field_mask = public_nbits >= 32 ? UINT32_C(-1) : (UINT32_C(1) << public_nbits) - 1; + const uint64_t shifted = (uint64_t)(secret_value & field_mask) << shift; + for (uint64_t k = 0; k < nbytes; ++k) { + r[first_byte + k] ^= (uint8_t)(shifted >> (8 * k)); + } +} + +// Here the position itself is secret, so it cannot be used to address memory: +// every word of the vector is read and written, and a mask picks the one that +// actually changes. Cost is the whole vector per call instead of one byte. +EXPORT void bitvec_xorbit_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask) { + uint8_t* const r = (uint8_t*)res; + // debug-only: a range check on a secret would itself be a branch on a secret. + // Out of range is harmless anyway -- no byte matches, so the call is a no-op. + CASSERT((secret_bitpos >> 3) < bytelen, // + "bitpos %" PRId64 " out of range (bytelen %" PRId64 ")", secret_bitpos, bytelen); + const uint64_t target_byte = secret_bitpos >> 3; + const uint8_t bit = (uint8_t)1 << (secret_bitpos & 7); + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] ^= bit & (uint8_t)mask_eq_ct_ref(i, target_byte) & (uint8_t)secret_mask; + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/ct_utils_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/ct_utils_avx2.c new file mode 100644 index 0000000000..f8ff72fe57 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/ct_utils_avx2.c @@ -0,0 +1,126 @@ +#include +#include + +#include "sdith_ct_utils.h" +#include "vole_private.h" + +// Hardened constant-time helpers (x86-64). +// +// Same results as the _ref ones in ct_utils.c, but the mask arithmetic is +// written in inline assembly so the compiler cannot turn it back into a +// conditional jump. Two x86 idioms carry most of the work: +// +// cmp a, b ; sbb m, m m = -(a < b): CMP borrows when a < b, and +// SBB m,m computes m - m - CF = -CF. +// neg x ; sbb m, m m = -(x != 0): NEG sets CF exactly when x != 0. +// +// Both are three-cycle, branch-free, and independent of the operand values. + +EXPORT uint64_t mask_lt_ct_avx(uint64_t secret_a, uint64_t secret_b) { + uint64_t m; + // CF = (a < b) unsigned, then m = -CF + __asm__("cmpq %2, %1\n\t" + "sbbq %0, %0" + : "=r"(m) + : "r"(secret_a), "r"(secret_b) + : "cc"); + return m; +} + +EXPORT uint64_t mask_eq_ct_avx(uint64_t secret_a, uint64_t secret_b) { + uint64_t m, t; + // t = a ^ b; CF = (t != 0); m = -CF; then invert to get -(a == b) + __asm__("movq %2, %1\n\t" + "xorq %3, %1\n\t" + "negq %1\n\t" + "sbbq %0, %0\n\t" + "notq %0" + : "=r"(m), "=&r"(t) + : "r"(secret_a), "r"(secret_b) + : "cc"); + return m; +} + +// Schoolbook restoring division (see the _ref version for the plain form), with +// the "did the remainder grow past d?" test turned into a mask: instead of +// subtracting under an if, we always subtract d & ge. Exactly 32 iterations, +// whatever n is. +EXPORT void div_rem_u32_ct_avx(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d) { + CREQUIRE(public_d != 0, "division by zero"); + const uint64_t d = public_d; + uint64_t rem = 0; + uint64_t quo = 0; + for (int64_t i = 31; i >= 0; --i) { + rem = (rem << 1) | ((uint64_t)(secret_n >> i) & 1); + uint64_t ge; + // ge = -(rem >= d), i.e. the complement of -(rem < d) + __asm__("cmpq %2, %1\n\t" + "sbbq %0, %0\n\t" + "notq %0" + : "=r"(ge) + : "r"(rem), "r"(d) + : "cc"); + rem -= d & ge; + quo |= ge & (UINT64_C(1) << i); + } + *q = (uint32_t)quo; + *r = (uint32_t)rem; +} + +// Vector AND/XOR: no branch to reintroduce, and the mask never reaches a flag +// register. bytelen is public, so the loop trip count and the tail are too. +EXPORT void bitvec_xor_to_masked_ct_avx(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask) { + uint8_t* const r = (uint8_t*)res; + const uint8_t* const b = (const uint8_t*)secret_b; + const __m256i mv = _mm256_set1_epi64x((long long)secret_mask); + uint64_t i = 0; + for (; i + 32 <= bytelen; i += 32) { + const __m256i rv = _mm256_loadu_si256((const __m256i*)(r + i)); + const __m256i bv = _mm256_loadu_si256((const __m256i*)(b + i)); + _mm256_storeu_si256((__m256i*)(r + i), _mm256_xor_si256(rv, _mm256_and_si256(bv, mv))); + } + const uint8_t m8 = (uint8_t)secret_mask; + for (; i < bytelen; ++i) { + r[i] ^= b[i] & m8; + } +} + +// Nothing to harden: every address here comes from public_bitpos, and the only +// secret is the bit pattern being xored in. The barrier just forbids the +// compiler from ever specialising on the value (e.g. skipping a zero). +EXPORT void bitvec_xoru32_ct_avx(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value) { + uint8_t* const r = (uint8_t*)res; + CREQUIRE(public_nbits <= 32, "field too wide (%" PRId64 " bits)", public_nbits); + const uint64_t first_byte = public_bitpos >> 3; + const uint64_t shift = public_bitpos & 7; + const uint64_t nbytes = (shift + public_nbits + 7) >> 3; + CREQUIRE(first_byte + nbytes <= bytelen, // + "field [%" PRId64 ",+%" PRId64 ") out of range (bytelen %" PRId64 ")", public_bitpos, public_nbits, bytelen); + const uint32_t field_mask = public_nbits >= 32 ? UINT32_C(-1) : (UINT32_C(1) << public_nbits) - 1; + uint64_t shifted = (uint64_t)(secret_value & field_mask) << shift; + __asm__("" : "+r"(shifted)); // opaque: the value must not drive any branch + for (uint64_t k = 0; k < nbytes; ++k) { + r[first_byte + k] ^= (uint8_t)(shifted >> (8 * k)); + } +} + +EXPORT void bitvec_xorbit_ct_avx(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask) { + uint8_t* const r = (uint8_t*)res; + // debug-only: a range check on a secret would itself be a branch on a secret. + // Out of range is harmless anyway -- no byte matches, so the call is a no-op. + CASSERT((secret_bitpos >> 3) < bytelen, // + "bitpos %" PRId64 " out of range (bytelen %" PRId64 ")", secret_bitpos, bytelen); + const uint64_t target_byte = secret_bitpos >> 3; + // 1 << (secret_bitpos % 8). SHL by CL is data-independent on x86-64; spelling + // it out here keeps the compiler from turning a 3-bit shift count into a + // jump table or a chain of tests. + uint64_t bit = 1; + __asm__("shlq %%cl, %0" : "+r"(bit) : "c"(secret_bitpos & 7) : "cc"); + // The position is secret, so it cannot address memory: touch every byte and + // let the mask decide which one actually changes. + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] ^= (uint8_t)(bit & mask_eq_ct_avx(i, target_byte) & secret_mask); + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/fips202_glue.h b/src/sig/sdith/sdith_sdith_common_avx2/fips202_glue.h new file mode 100644 index 0000000000..70e1cf1676 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/fips202_glue.h @@ -0,0 +1,44 @@ +#ifndef FIPS202_GLUE_H +#define FIPS202_GLUE_H + +#include + +typedef xof_ctx Keccak_HashInstance; // defined in sdith_prng.h + +static inline void Keccak_HashInitialize_SHAKE128(Keccak_HashInstance* inst) { + inst->shake = 128; + OQS_SHA3_shake128_inc_init(&inst->shake128_state); +} + +static inline void Keccak_HashInitialize_SHAKE256(Keccak_HashInstance* inst) { + inst->shake = 256; + OQS_SHA3_shake256_inc_init(&inst->shake256_state); +} + +// XKCP lengths are in bits, liboqs lengths are in bytes +static inline void Keccak_HashUpdate(Keccak_HashInstance* inst, const void* data, uint64_t databitlen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_absorb(&inst->shake128_state, data, databitlen >> 3); + } else { + OQS_SHA3_shake256_inc_absorb(&inst->shake256_state, data, databitlen >> 3); + } +} + +static inline void Keccak_HashFinal(Keccak_HashInstance* inst, void* hashval) { + (void)hashval; // XKCP ignores it for SHAKE + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_finalize(&inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_finalize(&inst->shake256_state); + } +} + +static inline void Keccak_HashSqueeze(Keccak_HashInstance* inst, void* data, uint64_t databitlen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_squeeze(data, databitlen >> 3, &inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_squeeze(data, databitlen >> 3, &inst->shake256_state); + } +} + +#endif diff --git a/src/sig/sdith/sdith_sdith_common_avx2/fips202x4_glue.h b/src/sig/sdith/sdith_sdith_common_avx2/fips202x4_glue.h new file mode 100644 index 0000000000..a9dc109bc1 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/fips202x4_glue.h @@ -0,0 +1,109 @@ +#ifndef FIPS202X4_GLUE_H +#define FIPS202X4_GLUE_H + +#include + +#include +#include + +typedef struct { + uint32_t shake; // 128 or 256, set by SpongeInitialize + union { + OQS_SHA3_shake128_inc_ctx shake128_state; + OQS_SHA3_shake256_inc_ctx shake256_state; + }; +} KeccakWidth1600_SpongeInstance; + +typedef struct { + uint32_t shake; // 128 or 256, set by SpongeInitialize + union { + OQS_SHA3_shake128_x4_inc_ctx shake128_state; + OQS_SHA3_shake256_x4_inc_ctx shake256_state; + }; +} KeccakWidth1600times4_SpongeInstance; + + +static inline void KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance* inst, unsigned int rate, + unsigned int capacity) { + (void)rate; // only read by the asserts, which NDEBUG removes + inst->shake = capacity / 2; // SHAKE128 has capacity 256 and SHAKE256 has capacity 512 + if (inst->shake == 128) { + assert(rate == (OQS_SHA3_SHAKE128_RATE << 3)); // XKCP rates are in bits, liboqs rates in bytes + OQS_SHA3_shake128_inc_init(&inst->shake128_state); + } else { + assert(rate == (OQS_SHA3_SHAKE256_RATE << 3)); + OQS_SHA3_shake256_inc_init(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600_SpongeAbsorb(KeccakWidth1600_SpongeInstance* inst, const unsigned char* data, + size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_absorb(&inst->shake128_state, data, dataByteLen); + } else { + OQS_SHA3_shake256_inc_absorb(&inst->shake256_state, data, dataByteLen); + } +} + +// sdith always passes 0x1F (the SHAKE padding), which liboqs's finalize applies +static inline void KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance* inst, + unsigned char delimitedData) { + (void)delimitedData; // liboqs finalize applies the delimiter already + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_finalize(&inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_finalize(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance* inst, unsigned char* data, + size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_inc_squeeze(data, dataByteLen, &inst->shake128_state); + } else { + OQS_SHA3_shake256_inc_squeeze(data, dataByteLen, &inst->shake256_state); + } +} + +static inline void KeccakWidth1600times4_SpongeInitialize(KeccakWidth1600times4_SpongeInstance* inst, + unsigned int rate, unsigned int capacity) { + (void)rate; // implied by capacity + inst->shake = capacity / 2; // SHAKE128 has capacity 256 and SHAKE256 has capacity 512 + if (inst->shake == 128) { + assert(rate == (OQS_SHA3_SHAKE128_RATE << 3)); // XKCP in bits, liboqs in bytes + OQS_SHA3_shake128_x4_inc_init(&inst->shake128_state); + } else { + assert(rate == (OQS_SHA3_SHAKE256_RATE << 3)); + OQS_SHA3_shake256_x4_inc_init(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600times4_SpongeAbsorb(KeccakWidth1600times4_SpongeInstance* inst, + const unsigned char** data, size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_x4_inc_absorb(&inst->shake128_state, data[0], data[1], data[2], data[3], dataByteLen); + } else { + OQS_SHA3_shake256_x4_inc_absorb(&inst->shake256_state, data[0], data[1], data[2], data[3], dataByteLen); + } +} + +static inline void KeccakWidth1600times4_SpongeAbsorbLastFewBits(KeccakWidth1600times4_SpongeInstance* inst, + unsigned char delimitedData) { + (void)delimitedData; // liboqs finalize applies the delimiter already + if (inst->shake == 128) { + OQS_SHA3_shake128_x4_inc_finalize(&inst->shake128_state); + } else { + OQS_SHA3_shake256_x4_inc_finalize(&inst->shake256_state); + } +} + +static inline void KeccakWidth1600times4_SpongeSqueeze(KeccakWidth1600times4_SpongeInstance* inst, + unsigned char** data, size_t dataByteLen) { + if (inst->shake == 128) { + OQS_SHA3_shake128_x4_inc_squeeze(data[0], data[1], data[2], data[3], dataByteLen, &inst->shake128_state); + } else { + OQS_SHA3_shake256_x4_inc_squeeze(data[0], data[1], data[2], data[3], dataByteLen, &inst->shake256_state); + } +} + +#endif diff --git a/src/sig/sdith/sdith_sdith_common_avx2/gf128.c b/src/sig/sdith/sdith_sdith_common_avx2/gf128.c new file mode 100644 index 0000000000..9bc5a9a2bf --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/gf128.c @@ -0,0 +1,247 @@ +#include "inttypes.h" +#include "vole_private.h" + +const gf128 GF128_ZERO = {.v128 = 0}; +const gf128 GF128_ONE = {.v128 = 1}; + +SDITH_ALWAYS_INLINE uint8_t gf128p_equals(const gf128* const a, const gf128* const b) { return a->v128 == b->v128; } + +void gf128p_sum(gf128* const res, const gf128* const a, const gf128* const b) { gf128_sum_ref(res, a, b); } + +SDITH_ALWAYS_INLINE uint8_t gf128p_bitof(const gf128* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 128, "bad bit position %" PRIu64, position); + return (a->v128 >> position) & 1; +} + +void gf128p_lsh(gf128* const res, const gf128* const a, const uint64_t amount) { + CREQUIRE(amount < 128, "bad left shift amount %" PRIu64, amount); + res->v128 = a->v128 << amount; +} + +void gf128p_rsh(gf128* const res, const gf128* const a, const uint64_t amount) { + CREQUIRE(amount < 128, "bad right shift amount %" PRIu64, amount); + res->v128 = a->v128 >> amount; +} + +void gf128p_mul(gf128* const res, const gf128* const a, const gf128* const b) { gf128_product_ref(res, a, b); } + +uint8_t gf128v_equals(const gf128 a, const gf128 b) { return gf128p_equals(&a, &b); } + +gf128 gf128v_sum(const gf128 a, const gf128 b) { + gf128 res; + gf128p_sum(&res, &a, &b); + return res; +} + +uint8_t gf128v_bitof(const gf128 a, const uint64_t position) { return gf128p_bitof(&a, position); } + +gf128 gf128v_lsh(const gf128 a, const uint64_t amount) { + gf128 res; + gf128p_lsh(&res, &a, amount); + return res; +} + +gf128 gf128v_rsh(const gf128 a, const uint64_t amount) { + gf128 res; + gf128p_rsh(&res, &a, amount); + return res; +} + +gf128 gf128v_mul(const gf128 a, const gf128 b) { + gf128 res; + gf128p_mul(&res, &a, &b); + return res; +} + +EXPORT void gf128_set_ref(gf128* res, const gf128* a) { *res = *a; } +EXPORT void gf128_flambda_set_ref(flambda_t* res, const flambda_t* a) { + gf128_set_ref((gf128*) res, (const gf128*) a); +}; + + +void gf128_sum_ref(gf128* res, const gf128* a, const gf128* b) { res->v128 = a->v128 ^ b->v128; } +EXPORT void gf128_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_sum_ref((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +__uint128_t gfprod128(__uint128_t a, __uint128_t b) { + __uint128_t tt = a; + __uint128_t rr = 0; + for (uint64_t i = 0; i < 128; ++i) { + rr ^= (-((b >> i) & (__uint128_t)1)) & tt; + tt = ((-(tt >> 127)) & GF128_P) ^ (tt << 1); + } + return rr; +} + +void gf128_product_ref(gf128* res, const gf128* a, const gf128* b) { res->v128 = gfprod128(a->v128, b->v128); } +EXPORT void gf128_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_product_ref((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +__uint128_t gfprod128_f2(__uint128_t a, __uint128_t b) { return (-b) & a; } + +void gf128_product_f2_ref(gf128* res, const gf128* a, const gf128* b) { res->v128 = gfprod128_f2(a->v128, b->v128); } +EXPORT void gf128_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2) { + gf128_product_f2_ref((gf128*) res, (const gf128*) a, (const gf128*) b_f2); +} + + +EXPORT void gf128_dot_product_ref(gf128* res, const gf128* x, const gf128* y, const uint64_t size) { + __uint128_t acc = 0; + for (uint64_t i = 0; i < size; ++i) { + acc ^= gfprod128(x[i].v128, y[i].v128); + } + res->v128 = acc; +} +EXPORT void gf128_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf128_dot_product_ref((gf128*) res, (const gf128*) x, (const gf128*) y, size); +} + + +EXPORT void gf128_dot_product_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf128); + __uint128_t acc = res->v128; + for (uint64_t i = 0; i < size; ++i) { + acc ^= gfprod128(x[i * xbs].v128, y[i].v128); + } + res->v128 = acc; +} +EXPORT void gf128_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf128_dot_product_acc_ref((gf128*) res, (const gf128*) x, x_byte_slice, (const gf128*) y, size); +} + + +EXPORT void gf128_dot_product_f2_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf128); + __uint128_t acc = res->v128; + for (uint64_t i = 0; i < size; ++i) { + acc ^= gfprod128_f2(x[i * xbs].v128, y_f2[i].v128); + } + res->v128 = acc; +} +EXPORT void gf128_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf128_dot_product_f2_acc_ref((gf128*) res, (const gf128*) x, x_byte_slice, (const gf128*) y_f2, size); +} + + +EXPORT void gf128_inverse_ref(gf128* res, const gf128* a) { + // this is the euclidian algorithm to compute the extended gcd + __uint128_t aa = a->v128; + CREQUIRE(aa != 0, "inverse of 0"); + __uint128_t uu = 1; + uint64_t log2a = 127; + while (((aa >> log2a) & 1) == 0) --log2a; + if (log2a == 0) { // a == 1: inverse is 1. Early-out also avoids the aa << 128 UB below. + res->v128 = 1; + return; + } + __uint128_t bb = GF128_P ^ (aa << (128 - log2a)); + __uint128_t vv = uu << (128 - log2a); + uint64_t log2b = 127; + while (log2a != 0) { + CASSERT(gfprod128(a->v128, uu) == aa, "bug1"); + CASSERT(gfprod128(a->v128, vv) == bb, "bug2"); + while (log2b >= log2a) { + if ((bb >> log2b) & 1) { + bb ^= (aa << (log2b - log2a)); + vv ^= (uu << (log2b - log2a)); + } + --log2b; + } + // swap aa <-> bb, uu <-> vv + __uint128_t tmp = aa; + aa = bb; + bb = tmp; + tmp = uu; + uu = vv; + vv = tmp; + uint64_t tmp2 = log2a; + log2a = log2b; + log2b = tmp2; + // update log2a + CASSERT(aa != 0, "bug3"); + while (((aa >> log2a) & 1) == 0) --log2a; + } + CASSERT(aa == 1, "bug4"); + res->v128 = uu; +} +EXPORT void gf128_flambda_inverse_ref(flambda_t* res, const flambda_t* a) { + gf128_inverse_ref((gf128*) res, (const gf128*) a); +} + + +EXPORT void gf128_sum_pow2_naive(gf128* res, const gf128* x) { + static const __uint128_t ONE = 1; + __uint128_t r = 0; + for (uint64_t i = 0; i < 128; ++i) { + r ^= gfprod128(ONE << i, x[i].v128); + } + res->v128 = r; +} + +EXPORT void gf128_sum_pow2_ref(gf128* res, const gf128* x) { + __uint128_t left = x[0].v128; + __uint128_t right = 0; + for (uint64_t i = 1; i < 128; ++i) { + __uint128_t xi = x[i].v128; + left ^= xi << i; + right ^= xi >> (128 - i); + } + res->v128 = left ^ gfprod128(GF128_P, right); +} +EXPORT void gf128_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x) { + gf128_sum_pow2_ref((gf128*) res, (const gf128*) x); +} + + +void gf128_echelon_pow2_naive(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + CREQUIRE(k > 0, "k not supported"); + CREQUIRE(k * x_size <= 128, "echelon width not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf128); + gf128 ONE = GF128_ONE; + gf128 r = GF128_ZERO; + gf128 tmp; + for (uint64_t i = 0; i < x_size; ++i) { + gf128p_lsh(&tmp, &ONE, k * i); + gf128p_mul(&tmp, &tmp, x + i * xbs); + gf128p_sum(&r, &r, &tmp); + } + *res = r; +} + +void gf128_echelon_pow2_ref(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 128, "echelon width not supported"); + if (x_size == 0) { + *res = GF128_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf128); + static const gf128 PP = {.v128 = GF128_PV}; + gf128 left = x[0]; + gf128 right = GF128_ZERO; + gf128 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf128p_lsh(&tmp, x + i * xbs, k * i); + gf128p_sum(&left, &left, &tmp); + gf128p_rsh(&tmp, x + i * xbs, 128 - k * i); + gf128p_sum(&right, &right, &tmp); + } + gf128p_mul(&tmp, &right, &PP); + gf128p_sum(res, &left, &tmp); +} +EXPORT void gf128_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf128_echelon_pow2_ref(k, (gf128*) res, (const gf128*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/gf128_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/gf128_avx2.c new file mode 100644 index 0000000000..eb5e42a98e --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/gf128_avx2.c @@ -0,0 +1,213 @@ +#include + +#include "vole_private.h" + +#define PCLMUL_LO_X_LO 0 +#define PCLMUL_LO_X_HI 16 +#define PCLMUL_HI_X_LO 1 +#define PCLMUL_HI_X_HI 17 + +static void gf128_square_pclmul(gf128* res, const gf128* a) { + const __m128i p = _mm_set_epi64x(0, GF128_P); + __m128i aa = _mm_loadu_si128((__m128i*)a); + // square a + __m128i u = _mm_clmulepi64_si128(aa, aa, PCLMUL_LO_X_LO); + __m128i c = _mm_clmulepi64_si128(aa, aa, PCLMUL_HI_X_HI); + // multiply upper half by p + __m128i d = _mm_clmulepi64_si128(c, p, 1); + u = _mm_xor_si128(u, _mm_clmulepi64_si128(c, p, 0)); + u = _mm_xor_si128(u, _mm_slli_si128(d, 8)); + c = _mm_srli_si128(d, 8); + // multiply by c by p + u = _mm_xor_si128(u, _mm_clmulepi64_si128(c, p, 0)); + _mm_storeu_si128((__m128i*)res, u); +} + +void gf128_product_pclmul(gf128* res, const gf128* a, const gf128* b) { + const __m128i p = _mm_set_epi64x(0, GF128_P); + __m128i aa = _mm_loadu_si128((__m128i*)a); + __m128i bb = _mm_loadu_si128((__m128i*)b); + // multiply a and b + __m128i u = _mm_clmulepi64_si128(aa, bb, 0); + __m128i d1 = _mm_clmulepi64_si128(aa, bb, 1); + __m128i d2 = _mm_clmulepi64_si128(aa, bb, 16); + __m128i c = _mm_clmulepi64_si128(aa, bb, 17); + __m128i d = _mm_xor_si128(d1, d2); + u = _mm_xor_si128(u, _mm_slli_si128(d, 8)); + c = _mm_xor_si128(c, _mm_srli_si128(d, 8)); + // multiply by c by p + d = _mm_clmulepi64_si128(c, p, 1); + u = _mm_xor_si128(u, _mm_clmulepi64_si128(c, p, 0)); + u = _mm_xor_si128(u, _mm_slli_si128(d, 8)); + c = _mm_srli_si128(d, 8); + // multiply by c by p + u = _mm_xor_si128(u, _mm_clmulepi64_si128(c, p, 0)); + _mm_storeu_si128((__m128i*)res, u); +} +EXPORT void gf128_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_product_pclmul((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +void gf128_product_pclmul_f2(gf128* res, const gf128* a, const gf128* b) { + __m128i aa = _mm_loadu_si128((__m128i*)a); + //__m128i bb = _mm_loadu_si128((__m128i*)b); + + __m128i u = _mm_set1_epi32(-b->v[0]); + u = _mm_and_si128(u, aa); + + _mm_storeu_si128((__m128i*)res, u); +} +EXPORT void gf128_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_product_pclmul_f2((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +// res = sum_i x[i . x_byte_slice]*y[i] (accumulated on top of res if accumulate). +// The clmul products are aggregated per Karatsuba term across the whole vector +// (3 accumulators) and a single reduction is done at the end. +SDITH_ALWAYS_INLINE void gf128_dot_product_core_pclmul(gf128* res, const uint8_t* x, const uint64_t x_byte_slice, + const gf128* y, const uint64_t size, + const int accumulate) { + const __m128i p = _mm_set_epi64x(0, GF128_P); + // one accumulator per clmul product (3 = 2*(2+1)/2) + __m128i accD0 = _mm_setzero_si128(); // sum x0*y0 (degree 0) + __m128i accD1 = _mm_setzero_si128(); // sum x1*y1 (degree 2) + __m128i accP = _mm_setzero_si128(); // sum (x0+x1)*(y0+y1) (degree 1, Karatsuba) + for (uint64_t i = 0; i < size; ++i) { + __m128i xx = _mm_loadu_si128((__m128i*)(x + i * x_byte_slice)); + __m128i yy = _mm_loadu_si128((__m128i*)&y[i]); + __m128i xs = _mm_xor_si128(xx, _mm_srli_si128(xx, 8)); // lane0 = x0^x1 + __m128i ys = _mm_xor_si128(yy, _mm_srli_si128(yy, 8)); // lane0 = y0^y1 + accD0 = _mm_xor_si128(accD0, _mm_clmulepi64_si128(xx, yy, PCLMUL_LO_X_LO)); + accD1 = _mm_xor_si128(accD1, _mm_clmulepi64_si128(xx, yy, PCLMUL_HI_X_HI)); + accP = _mm_xor_si128(accP, _mm_clmulepi64_si128(xs, ys, PCLMUL_LO_X_LO)); + } + // degree-1 coefficient: (x0y1 + x1y0) = accP + accD0 + accD1 + __m128i d = _mm_xor_si128(accP, _mm_xor_si128(accD0, accD1)); + // condense to the 256-bit representation u (low) || c (high) + __m128i u = _mm_xor_si128(accD0, _mm_slli_si128(d, 8)); + __m128i c = _mm_xor_si128(accD1, _mm_srli_si128(d, 8)); + // single reduction (same tail as gf128_product_pclmul) + d = _mm_clmulepi64_si128(c, p, 1); + u = _mm_xor_si128(u, _mm_clmulepi64_si128(c, p, 0)); + u = _mm_xor_si128(u, _mm_slli_si128(d, 8)); + c = _mm_srli_si128(d, 8); + u = _mm_xor_si128(u, _mm_clmulepi64_si128(c, p, 0)); + if (accumulate) u = _mm_xor_si128(u, _mm_loadu_si128((__m128i*)res)); + _mm_storeu_si128((__m128i*)res, u); +} + +void gf128_dot_product_pclmul(gf128* res, const gf128* x, const gf128* y, const uint64_t size) { + gf128_dot_product_core_pclmul(res, (const uint8_t*)x, sizeof(gf128), y, size, 0); +} +EXPORT void gf128_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf128_dot_product_pclmul((gf128*) res, (const gf128*) x, (const gf128*) y, size); +} + + +EXPORT void gf128_dot_product_acc_pclmul(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + gf128_dot_product_core_pclmul(res, (const uint8_t*)x, x_byte_slice, y, size, 1); +} +EXPORT void gf128_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf128_dot_product_acc_pclmul((gf128*) res, (const gf128*) x, x_byte_slice, (const gf128*) y, size); +} + + +EXPORT void gf128_dot_product_f2_acc_avx2(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + const uint8_t* xp = (const uint8_t*)x; + __m128i acc = _mm_loadu_si128((__m128i*)res); + for (uint64_t i = 0; i < size; ++i) { + // y_f2[i] is 0 or 1: broadcasting its negation gives the 0/all-ones bit-select mask + __m128i mask = _mm_set1_epi32(-y_f2[i].v[0]); + acc = _mm_xor_si128(acc, _mm_and_si128(mask, _mm_loadu_si128((__m128i*)(xp + i * x_byte_slice)))); + } + _mm_storeu_si128((__m128i*)res, acc); +} +EXPORT void gf128_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf128_dot_product_f2_acc_avx2((gf128*) res, (const gf128*) x, x_byte_slice, (const gf128*) y_f2, size); +} + + +void gf128_sum_avx2(gf128* res, const gf128* a, const gf128* b) { + __m128i aa = _mm_loadu_si128((__m128i*)a); + __m128i bb = _mm_loadu_si128((__m128i*)b); + aa = _mm_xor_si128(aa, bb); + _mm_storeu_si128((__m128i*)res, aa); +} +EXPORT void gf128_flambda_sum_avx2(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf128_sum_avx2((gf128*) res, (const gf128*) a, (const gf128*) b); +} + + +void gf128_inverse_pclmul(gf128* res, const gf128* a) { + gf128 tmp, pow_a[6]; // pow_a[i] = a**(2**(2**(i+1))-1) --> a**3, a**15, a**255, a**65536, ... + gf128* pow_a_ptr = &pow_a[0]; + + gf128_square_pclmul(&tmp, a); + gf128_product_pclmul(&pow_a[0], &tmp, a); // pow_a[0] = a^3 + + for (size_t i = 2; i < 64; i <<= 1) { + gf128_square_pclmul(&tmp, pow_a_ptr); + for (size_t j = 1; j < i; j++) { + gf128_square_pclmul(&tmp, &tmp); + } + gf128_product_pclmul(pow_a_ptr + 1, &tmp, pow_a_ptr); + pow_a_ptr++; + } + + pow_a_ptr = &pow_a[4]; + for (size_t i = 32; i > 1; i >>= 1) { + for (size_t j = 0; j < i; j++) { + gf128_square_pclmul(&pow_a[5], &pow_a[5]); + } + gf128_product_pclmul(&pow_a[5], &pow_a[5], pow_a_ptr); + pow_a_ptr--; + } + + // pow_a[5] = a**(2**126-1) + + gf128_square_pclmul(&pow_a[5], &pow_a[5]); + gf128_product_pclmul(&pow_a[5], &pow_a[5], a); + + // pow_a[5] = a**(2**127-1) + + gf128_square_pclmul(res, &pow_a[5]); // res = (a**(2**127-1))**2 = a**(2*2**127-2) = a**(2**128-2) = a**-1 +} +EXPORT void gf128_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a) { + gf128_inverse_pclmul((gf128*) res, (const gf128*) a); +} + + +void gf128_echelon_pow2_avx(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf128) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 128, "echelon width not supported"); + if (x_size == 0) { + *res = GF128_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf128); + static const gf128 PP = {.v128 = GF128_PV}; + gf128 left = x[0]; + gf128 right = GF128_ZERO; + gf128 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf128p_lsh(&tmp, x + i * xbs, k * i); + gf128_sum_avx2(&left, &left, &tmp); + gf128p_rsh(&tmp, x + i * xbs, 128 - k * i); + gf128_sum_avx2(&right, &right, &tmp); + } + gf128_product_pclmul(&tmp, &right, &PP); + gf128_sum_avx2(res, &left, &tmp); +} +EXPORT void gf128_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf128_echelon_pow2_avx(k, (gf128*) res, (const gf128*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/gf192.c b/src/sig/sdith/sdith_sdith_common_avx2/gf192.c new file mode 100644 index 0000000000..f42ab6c58a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/gf192.c @@ -0,0 +1,343 @@ +#include +#include +#include +#include +#include + +#include "vole_private.h" + +const gf192 GF192_ZERO = {.v64 = {0, 0, 0}}; +const gf192 GF192_ONE = {.v64 = {1, 0, 0}}; + +SDITH_ALWAYS_INLINE uint8_t gf192p_equals(const gf192* const a, const gf192* const b) { + return memcmp(a->v, b->v, 24) == 0; +} + +SDITH_ALWAYS_INLINE void gf192p_sum(gf192* const res, const gf192* const a, const gf192* const b) { + gf192_sum_ref(res, a, b); +} + +SDITH_ALWAYS_INLINE uint8_t gf192p_bitof(const gf192* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 192, "bad bit position %" PRIu64, position); + const uint64_t q8 = position >> 3; + const uint64_t r8 = position & 7; + return (a->v[q8] >> r8) & 1; +} + +// 64-bit limb shifts (little-endian v64[3]). +// This function does not need to be CT: amount is always public in the hot callers (sum_pow2/echelon loop index); +// It is also used on delta by the ref_inverse +// which is also public since delta is part of the signature. +void gf192p_lsh(gf192* const res, const gf192* const a, const uint64_t amount) { + CREQUIRE(amount < 192, "bad left shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[3] = {0, 0, 0}; + if (rb == 0) { + for (uint64_t i = ql; i < 3; i++) o[i] = a->v64[i - ql]; + } else { + for (uint64_t i = 3; i-- > ql;) { + const uint64_t hi = a->v64[i - ql] << rb; + const uint64_t lo = (i - ql >= 1) ? (a->v64[i - ql - 1] >> (64 - rb)) : 0; + o[i] = hi | lo; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; +} + +void gf192p_rsh(gf192* const res, const gf192* const a, const uint64_t amount) { + CREQUIRE(amount < 192, "bad right shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[3] = {0, 0, 0}; + if (rb == 0) { + for (uint64_t i = 0; i + ql < 3; i++) o[i] = a->v64[i + ql]; + } else { + for (uint64_t i = 0; i + ql < 3; i++) { + const uint64_t lo = a->v64[i + ql] >> rb; + const uint64_t hi = (i + ql + 1 < 3) ? (a->v64[i + ql + 1] << (64 - rb)) : 0; + o[i] = lo | hi; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; +} + +SDITH_ALWAYS_INLINE void gf192p_mul(gf192* const res, const gf192* const a, const gf192* const b) { + gf192_product_ref(res, a, b); +} + +uint8_t gf192v_equals(const gf192 a, const gf192 b) { return gf192p_equals(&a, &b); } + +gf192 gf192v_sum(const gf192 a, const gf192 b) { + gf192 res; + gf192p_sum(&res, &a, &b); + return res; +} + +uint8_t gf192v_bitof(const gf192 a, const uint64_t position) { return gf192p_bitof(&a, position); } + +gf192 gf192v_lsh(const gf192 a, const uint64_t amount) { + gf192 res; + gf192p_lsh(&res, &a, amount); + return res; +} + +gf192 gf192v_rsh(const gf192 a, const uint64_t amount) { + gf192 res; + gf192p_rsh(&res, &a, amount); + return res; +} + +gf192 gf192v_mul(const gf192 a, const gf192 b) { + gf192 res; + gf192p_mul(&res, &a, &b); + return res; +} + +EXPORT void gf192_set_ref(gf192* res, const gf192* a) { *res = *a; } +EXPORT void gf192_flambda_set_ref(flambda_t* res, const flambda_t* a) { + gf192_set_ref((gf192*) res, (const gf192*) a); +} + +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b) { + for (uint64_t i = 0; i < 3; ++i) res->v64[i] = a->v64[i] ^ b->v64[i]; +} +EXPORT void gf192_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf192_sum_ref((gf192*) res, (const gf192*) a, (const gf192*) b); +} + + +EXPORT void gf192_product_ref(gf192* res, const gf192* a, const gf192* b) { + // deal with the in-place issue + if (res == b) { + gf192 tmp; + gf192p_mul(&tmp, a, b); + memcpy(res->v, tmp.v, 24); + return; + } + // Out of place product, constant-time and word-level. The 3x3 carryless limb + // products (Karatsuba gf_clmul64) are accumulated into a 384-bit result, then + // reduced modulo the field polynomial x^192 + x^7 + x^2 + x + 1 (0x87) with + // sparse shift-xors. There is no data-dependent branch or memory access, so + // the running time is independent of the secret bits of a and b (this runs on + // prover witness values, where a data-dependent branch would be a timing + // leak). The result is bit-identical to the schoolbook version, so all KATs + // are unchanged. Operand limbs are read before res is written, so res may + // alias a (res == b is handled by the guard above). + const uint64_t* const av = a->v64; + const uint64_t* const bv = b->v64; + uint64_t t[6] = {0}, hi, lo; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) { + gf_clmul64(av[i], bv[j], &hi, &lo); + t[i + j] ^= lo; + t[i + j + 1] ^= hi; + } + // fold the high 192 bits (t[3..5]) down: x^(192+n) = x^n * (x^7 + x^2 + x + 1) + uint64_t r0 = t[0], r1 = t[1], r2 = t[2], c; +#define GF192_FOLD(v, L, H) \ + do { \ + (L) = (v) ^ ((v) << 1) ^ ((v) << 2) ^ ((v) << 7); \ + (H) = ((v) >> 63) ^ ((v) >> 62) ^ ((v) >> 57); \ + } while (0) + GF192_FOLD(t[3], lo, hi); r0 ^= lo; r1 ^= hi; + GF192_FOLD(t[4], lo, hi); r1 ^= lo; r2 ^= hi; + GF192_FOLD(t[5], lo, hi); r2 ^= lo; c = hi; // c holds coefficients of bits 192..198 + r0 ^= c ^ (c << 1) ^ (c << 2) ^ (c << 7); // second fold; c <= 7 bits, no further overflow +#undef GF192_FOLD + res->v64[0] = r0; + res->v64[1] = r1; + res->v64[2] = r2; +} +EXPORT void gf192_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf192_product_ref((gf192*) res, (const gf192*) a, (const gf192*) b); +} + + +EXPORT void gf192_dot_product_ref(gf192* res, const gf192* x, const gf192* y, const uint64_t size) { + gf192 acc = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf192_product_ref(&tmp, &x[i], &y[i]); + gf192_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf192_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf192_dot_product_ref((gf192*) res, (const gf192*) x, (const gf192*) y, size); +} + + +EXPORT void gf192_dot_product_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf192); + gf192 acc = *res; + gf192 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf192_product_ref(&tmp, &x[i * xbs], &y[i]); + gf192_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf192_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf192_dot_product_acc_ref((gf192*) res, (const gf192*) x, x_byte_slice, (const gf192*) y, size); +} + + +EXPORT void gf192_dot_product_f2_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf192); + uint64_t acc0 = res->v64[0], acc1 = res->v64[1], acc2 = res->v64[2]; + for (uint64_t i = 0; i < size; ++i) { + const uint64_t mask = -y_f2[i].v64[0]; + acc0 ^= x[i * xbs].v64[0] & mask; + acc1 ^= x[i * xbs].v64[1] & mask; + acc2 ^= x[i * xbs].v64[2] & mask; + } + res->v64[0] = acc0; + res->v64[1] = acc1; + res->v64[2] = acc2; +} +EXPORT void gf192_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf192_dot_product_f2_acc_ref((gf192*) res, (const gf192*) x, x_byte_slice, (const gf192*) y_f2, size); +} + + +EXPORT void gf192_product_f2_ref(gf192* res, const gf192* a, const gf192* b_f2) { + const uint64_t mask = -b_f2->v64[0]; + for (uint64_t i = 0; i < 3; ++i) res->v64[i] = a->v64[i] & mask; +} +EXPORT void gf192_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2) { + gf192_product_f2_ref((gf192*) res, (const gf192*) a, (const gf192*) b_f2); +} + + +EXPORT void gf192_inverse_ref(gf192* res, const gf192* a) { + // this is the euclidian algorithm to compute the extended gcd + gf192 aa = *a; + CREQUIRE(!gf192p_equals(&aa, &GF192_ZERO), "inverse of 0"); + gf192 uu = GF192_ONE; + uint64_t log2a = 191; + while (gf192p_bitof(&aa, log2a) == 0) --log2a; + gf192 bb; + gf192p_lsh(&bb, &aa, 192 - log2a); + bb.v64[0] ^= GF192_P; + gf192 vv; + gf192p_lsh(&vv, &uu, 192 - log2a); + uint64_t log2b = 191; + while (log2a != 0) { + CASSERT(gf192v_equals(gf192v_mul(*a, uu), aa), "bug1"); + CASSERT(gf192v_equals(gf192v_mul(*a, vv), bb), "bug2"); + while (log2b >= log2a) { + if (gf192p_bitof(&bb, log2b)) { + gf192 tmp; + gf192p_lsh(&tmp, &aa, log2b - log2a); + gf192p_sum(&bb, &bb, &tmp); + gf192p_lsh(&tmp, &uu, log2b - log2a); + gf192p_sum(&vv, &vv, &tmp); + } + --log2b; + } + // swap aa <-> bb, uu <-> vv + gf192 tmp = aa; + aa = bb; + bb = tmp; + tmp = uu; + uu = vv; + vv = tmp; + uint64_t tmp2 = log2a; + log2a = log2b; + log2b = tmp2; + // update log2a + CASSERT(!gf192p_equals(&aa, &GF192_ZERO), "bug3"); + while (gf192p_bitof(&aa, log2a) == 0) --log2a; + } + CASSERT(gf192p_equals(&aa, &GF192_ONE), "bug4"); + *res = uu; +} +EXPORT void gf192_flambda_inverse_ref(flambda_t* res, const flambda_t* a) { + gf192_inverse_ref((gf192*) res, (const gf192*) a); +} + + +EXPORT void gf192_sum_pow2_naive(gf192* res, const gf192* x) { + gf192 ONE = GF192_ONE; + gf192 r = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 0; i < 192; ++i) { + gf192p_lsh(&tmp, &ONE, i); + gf192p_mul(&tmp, &tmp, x + i); + gf192p_sum(&r, &r, &tmp); + } + *res = r; +} + +EXPORT void gf192_sum_pow2_ref(gf192* res, const gf192* x) { + static const gf192 PP = {.v64 = {GF192_PV, 0, 0}}; + gf192 left = x[0]; + gf192 right = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 1; i < 192; ++i) { + gf192p_lsh(&tmp, x + i, i); + gf192p_sum(&left, &left, &tmp); + gf192p_rsh(&tmp, x + i, 192 - i); + gf192p_sum(&right, &right, &tmp); + } + gf192p_mul(&tmp, &right, &PP); + gf192p_sum(res, &left, &tmp); +} +EXPORT void gf192_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x) { + gf192_sum_pow2_ref((gf192*) res, (const gf192*) x); +} + + +void gf192_echelon_pow2_naive(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + CREQUIRE(k > 0, "k not supported"); + CREQUIRE(k * x_size <= 192, "echelon width not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf192); + gf192 ONE = GF192_ONE; + gf192 r = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 0; i < x_size; ++i) { + gf192p_lsh(&tmp, &ONE, k * i); + gf192p_mul(&tmp, &tmp, x + i * xbs); + gf192p_sum(&r, &r, &tmp); + } + *res = r; +} + +void gf192_echelon_pow2_ref(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 192, "echelon width not supported"); + if (x_size == 0) { + *res = GF192_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf192); + static const gf192 PP = {.v64 = {GF192_PV, 0, 0}}; + gf192 left = x[0]; + gf192 right = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf192p_lsh(&tmp, x + i * xbs, k * i); + gf192p_sum(&left, &left, &tmp); + gf192p_rsh(&tmp, x + i * xbs, 192 - k * i); + gf192p_sum(&right, &right, &tmp); + } + gf192p_mul(&tmp, &right, &PP); + gf192p_sum(res, &left, &tmp); +} +EXPORT void gf192_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf192_echelon_pow2_ref(k, (gf192*) res, (const gf192*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/gf192_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/gf192_avx2.c new file mode 100644 index 0000000000..d2fe408c95 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/gf192_avx2.c @@ -0,0 +1,352 @@ +#include + +#include "vole_private.h" + +#define PCLMUL_LO_X_LO 0 +#define PCLMUL_LO_X_HI 16 +#define PCLMUL_HI_X_LO 1 +#define PCLMUL_HI_X_HI 17 + +static void gf192_square_pclmul(gf192* res, const gf192* a) { + const __m128i pa2 = _mm_set_epi64x(a->v64[2], GF192_P); + __m128i a01 = _mm_loadu_si128((__m128i*)a); + // multiply a and b + // we have a = (a2X^128 + a1X^64 + a0) + // then c = c2X^256 + c1X^128 + c0 + // with c2 = a2a2 + // and c1 = a1a1 + // and c0 = a0a0 + __m128i c0, c1, c2, c3, tmp[4]; + + c0 = _mm_clmulepi64_si128(a01, a01, PCLMUL_LO_X_LO); // c0 = a0a0 + c1 = _mm_clmulepi64_si128(a01, a01, PCLMUL_HI_X_HI); // c1 = a1a1 + c2 = _mm_clmulepi64_si128(pa2, pa2, PCLMUL_HI_X_HI); // c2 = a2a2 + + // condense to a 4-register representation where two hold the low result and two hold the high result + // currently we have + // c0c0 + // c1c1 + // c2c2 + // and we want c0||c1 to hold the low result and c2||c3 to hold the high result + tmp[0] = _mm_setzero_si128(); + c3 = _mm_srli_si128(c2, 8); // upper half of c2 goes to c3 lower half + c2 = _mm_slli_si128(c2, 8); // lower half of c2 goes to c2 upper half + tmp[1] = _mm_srli_si128(c1, 8); // move upper half of c1 down to tmp1 + c2 = _mm_blend_epi32(c2, tmp[1], 0b0011); // upper half stays in c2, lower half taken from tmp1 + + // c1 still has its upper bits that are moved to c2! + + // reduction: + // (1) multiply high result (in c2 and c3) by p, return 192 MSBs, then + // (2) multiply that by p again, return 192 LSBs as remainder + // (3) add remainder to 192 LSBs of multiplication result + + // Step 1: multiply high result (in c2 and c3) by p, return 192 MSBs + // (c2L + c2HX^64 + c3LX^128) * (p + X^192) = p*c2L + p*c2HX^64 + p*c3LX^128 + c2LX^192 + c2HX^256 + c3LX^384 + // but we only care about the high result: + // p*c2L + p*c2HX^64 are completely in the low half + // the upper half of p*c3LX^128 is the first term of the high result + // c2LX^192 + c2HX^256 + c3LX^384 is added to that + tmp[1] = _mm_clmulepi64_si128(c3, pa2, PCLMUL_LO_X_LO); + tmp[1] = _mm_bsrli_si128(tmp[1], 8); + c2 = _mm_xor_si128(tmp[1], c2); + + // c2 and c3 now hold the high multiplication result, and now we multiply p again + // but now we want the LSBs of (c2L + c2HX^64 + c3LX^128) * p + tmp[0] = _mm_clmulepi64_si128(c3, pa2, PCLMUL_LO_X_LO); // tmp0 = p * c3 (HIGH) + tmp[2] = _mm_clmulepi64_si128(c2, pa2, PCLMUL_LO_X_LO); // tmp1 = p * c2L (LOW) + tmp[3] = _mm_clmulepi64_si128(c2, pa2, PCLMUL_HI_X_LO); // tmp2 = p * c2H (MID) + c1 = _mm_xor_si128(c1, tmp[0]); // reduce HIGH + c0 = _mm_xor_si128(c0, tmp[2]); // reduce LOW + tmp[0] = _mm_bsrli_si128(tmp[3], 8); // tmp0 = (p*c2H) >> 64 + tmp[2] = _mm_bslli_si128(tmp[3], 8); // tmp2 = (p*c2H) << 64 + c1 = _mm_xor_si128(c1, tmp[0]); // reduce MID + c0 = _mm_xor_si128(c0, tmp[2]); // reduce MID + + _mm_storeu_si128((__m128i*)res, c0); + res->v64[2] = _mm_extract_epi64(c1, 0); +} + +EXPORT void gf192_product_pclmul(gf192* res, const gf192* a, const gf192* b) { + const __m128i p = _mm_set_epi64x(0, GF192_P); + __m128i a01 = _mm_loadu_si128((__m128i*)a); + __m128i b01 = _mm_loadu_si128((__m128i*)b); + __m128i a2b2 = _mm_set_epi64x(a->v64[2], b->v64[2]); + // multiply a and b + // we have a = (a2X^128 + a1X^64 + a0) and b analogous + // then c = c4X^256 + c3X^192 + c2X^128 + c1X^64 + c0 + // with c4 = a2b2 + // and c3 = a2b1 + a1b2 + // and c2 = a2b0 + a1b1 + a0b2 + // and c1 = a1b0 + a0b1 + // and c0 = a0b0 + __m128i c0, c1, c2, c3, c4, tmp[4]; + + c0 = _mm_clmulepi64_si128(a01, b01, PCLMUL_LO_X_LO); // c0 = a0b0 + c1 = _mm_clmulepi64_si128(a01, b01, PCLMUL_HI_X_LO); // c1 = a1b0 + c2 = _mm_clmulepi64_si128(a2b2, b01, PCLMUL_HI_X_LO); // c2 = a2b0 + c3 = _mm_clmulepi64_si128(a2b2, b01, PCLMUL_HI_X_HI); // c3 = a2b1 + c4 = _mm_clmulepi64_si128(a2b2, a2b2, PCLMUL_HI_X_LO); // c4 = a2b2 + tmp[0] = _mm_clmulepi64_si128(a01, b01, PCLMUL_LO_X_HI); // tmp0 = a0b1 + tmp[1] = _mm_clmulepi64_si128(a01, b01, PCLMUL_HI_X_HI); // tmp1 = a1b1 + tmp[2] = _mm_clmulepi64_si128(a01, a2b2, PCLMUL_LO_X_LO); // tmp2 = a0b2 + tmp[3] = _mm_clmulepi64_si128(a01, a2b2, PCLMUL_HI_X_LO); // tmp3 = a1b2 + + c1 = _mm_xor_si128(c1, tmp[0]); // c1 = a1b0 + a0b1 + c2 = _mm_xor_si128(c2, tmp[1]); // c2 = a2b0 + a1b1 + c3 = _mm_xor_si128(c3, tmp[3]); // c3 = a2b1 + a1b2 + c2 = _mm_xor_si128(c2, tmp[2]); // c2 = a2b0 + a1b1 + a0b2 + + // condense to a 4-register representation where two hold the low result and two hold the high result + // currently we have + // c0c0 + // c1c1 + // c2c2 + // c3c3 + // c4c4 + // and we want c0||c1 to hold the low result and c2||c3 to hold the high result + // so we need to do: + // - c0 += c1L<<64 + // - c1 := c1H + c2L + // - c2 := c3 + c2H + (c4L<<64) + // - c3 := c4H + tmp[0] = _mm_setzero_si128(); + c1 = _mm_shuffle_epi32(c1, 0b01001110); // c1 := c1 with swapped 64-bit words + c4 = _mm_shuffle_epi32(c4, 0b01001110); // c4 := c4 with swapped 64-bit words + tmp[2] = _mm_shuffle_epi32(c2, 0b01001110); // tmp2 := c2 with swapped 64-bit words + tmp[3] = _mm_blend_epi32(c1, tmp[0], 0b0011); // tmp3 only has the high half of c1, which is now c1L + tmp[1] = _mm_blend_epi32(tmp[2], c4, 0b1100); // tmp1 has now c2H + (c4L<<64) + c1 = _mm_xor_si128(c1, c2); // c1 := c1H + c2L (plus nonsense higher 64 bits) + c0 = _mm_xor_si128(c0, tmp[3]); // c0 := c0 + (c1L<<64) + c2 = _mm_xor_si128(c3, tmp[1]); // c2 := c3 + c2H + (c4L<<64) + c3 = _mm_blend_epi32(c4, tmp[0], 0b1100); // c3 := c4H + c1 = _mm_blend_epi32(c1, tmp[0], 0b1100); // c1 := c1H + c2L + + // c4 is now free to be used as tmp registers + + // reduction: + // (1) multiply high result (in c2 and c3) by p, return 192 MSBs, then + // (2) multiply that by p again, return 192 LSBs as remainder + // (3) add remainder to 192 LSBs of multiplication result + + // Step 1: multiply high result (in c2 and c3) by p, return 192 MSBs + // (c2L + c2HX^64 + c3LX^128) * (p + X^192) = p*c2L + p*c2HX^64 + p*c3LX^128 + c2LX^192 + c2HX^256 + c3LX^384 + // but we only care about the high result: + // p*c2L + p*c2HX^64 are completely in the low half + // the upper half of p*c3LX^128 is the first term of the high result + // c2LX^192 + c2HX^256 + c3LX^384 is added to that + tmp[1] = _mm_clmulepi64_si128(c3, p, PCLMUL_LO_X_LO); + tmp[1] = _mm_bsrli_si128(tmp[1], 8); + c2 = _mm_xor_si128(tmp[1], c2); + + // c2 and c3 now hold the high multiplication result, and now we multiply p again + // but now we want the LSBs of (c2L + c2HX^64 + c3LX^128) * p + tmp[0] = _mm_clmulepi64_si128(c3, p, PCLMUL_LO_X_LO); // tmp0 = p * c3 (HIGH) + tmp[2] = _mm_clmulepi64_si128(c2, p, PCLMUL_LO_X_LO); // tmp1 = p * c2L (LOW) + tmp[3] = _mm_clmulepi64_si128(c2, p, PCLMUL_HI_X_LO); // tmp2 = p * c2H (MID) + c1 = _mm_xor_si128(c1, tmp[0]); // reduce HIGH + c0 = _mm_xor_si128(c0, tmp[2]); // reduce LOW + tmp[0] = _mm_bsrli_si128(tmp[3], 8); // tmp0 = (p*c2H) >> 64 + tmp[2] = _mm_bslli_si128(tmp[3], 8); // tmp2 = (p*c2H) << 64 + c1 = _mm_xor_si128(c1, tmp[0]); // reduce MID + c0 = _mm_xor_si128(c0, tmp[2]); // reduce MID + + _mm_storeu_si128((__m128i*)res, c0); + res->v64[2] = _mm_extract_epi64(c1, 0); +} +EXPORT void gf192_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf192_product_pclmul((gf192*) res, (const gf192*) a, (const gf192*) b); +} + + +// res = sum_i x[i . x_byte_slice]*y[i] (accumulated on top of res if accumulate). +// The clmul products are aggregated per Karatsuba term across the whole vector +// (6 accumulators) and a single reduction is done at the end. +SDITH_ALWAYS_INLINE void gf192_dot_product_core_pclmul(gf192* res, const uint8_t* x, const uint64_t x_byte_slice, + const gf192* y, const uint64_t size, + const int accumulate) { + const __m128i p = _mm_set_epi64x(0, GF192_P); + // one accumulator per clmul product (6 = 3*(3+1)/2) + __m128i accD0 = _mm_setzero_si128(); // x0*y0 (deg 0) + __m128i accD1 = _mm_setzero_si128(); // x1*y1 (deg 2) + __m128i accD2 = _mm_setzero_si128(); // x2*y2 (deg 4) + __m128i accP01 = _mm_setzero_si128(); // (x0+x1)*(y0+y1) (deg 1) + __m128i accP02 = _mm_setzero_si128(); // (x0+x2)*(y0+y2) (deg 2) + __m128i accP12 = _mm_setzero_si128(); // (x1+x2)*(y1+y2) (deg 3) + for (uint64_t i = 0; i < size; ++i) { + const gf192* xi = (const gf192*)(x + i * x_byte_slice); + __m128i a01 = _mm_loadu_si128((__m128i*)xi); // (x0,x1) + __m128i b01 = _mm_loadu_si128((__m128i*)&y[i]); // (y0,y1) + __m128i a2 = _mm_loadl_epi64((__m128i*)&xi->v64[2]); // (x2,0) + __m128i b2 = _mm_loadl_epi64((__m128i*)&y[i].v64[2]); // (y2,0) + __m128i a1 = _mm_srli_si128(a01, 8); // (x1,0) + __m128i b1 = _mm_srli_si128(b01, 8); // (y1,0) + // pair sums (each in lane 0) + __m128i sx01 = _mm_xor_si128(a01, a1); // x0^x1 + __m128i sy01 = _mm_xor_si128(b01, b1); // y0^y1 + __m128i sx02 = _mm_xor_si128(a01, a2); // x0^x2 + __m128i sy02 = _mm_xor_si128(b01, b2); // y0^y2 + __m128i sx12 = _mm_xor_si128(a1, a2); // x1^x2 + __m128i sy12 = _mm_xor_si128(b1, b2); // y1^y2 + accD0 = _mm_xor_si128(accD0, _mm_clmulepi64_si128(a01, b01, PCLMUL_LO_X_LO)); + accD1 = _mm_xor_si128(accD1, _mm_clmulepi64_si128(a01, b01, PCLMUL_HI_X_HI)); + accD2 = _mm_xor_si128(accD2, _mm_clmulepi64_si128(a2, b2, PCLMUL_LO_X_LO)); + accP01 = _mm_xor_si128(accP01, _mm_clmulepi64_si128(sx01, sy01, PCLMUL_LO_X_LO)); + accP02 = _mm_xor_si128(accP02, _mm_clmulepi64_si128(sx02, sy02, PCLMUL_LO_X_LO)); + accP12 = _mm_xor_si128(accP12, _mm_clmulepi64_si128(sx12, sy12, PCLMUL_LO_X_LO)); + } + // degree coefficients c0..c4 (same layout as gf192_product_pclmul before condensing) + __m128i c0 = accD0; // deg 0 + __m128i c1 = _mm_xor_si128(accP01, _mm_xor_si128(accD0, accD1)); // deg 1 + __m128i c2 = _mm_xor_si128(accD1, _mm_xor_si128(accP02, _mm_xor_si128(accD0, accD2))); // deg 2 + __m128i c3 = _mm_xor_si128(accP12, _mm_xor_si128(accD1, accD2)); // deg 3 + __m128i c4 = accD2; // deg 4 + __m128i tmp[4]; + + // condense to the 4-register (low||high) representation (from gf192_product_pclmul) + tmp[0] = _mm_setzero_si128(); + c1 = _mm_shuffle_epi32(c1, 0b01001110); // c1 := c1 with swapped 64-bit words + c4 = _mm_shuffle_epi32(c4, 0b01001110); // c4 := c4 with swapped 64-bit words + tmp[2] = _mm_shuffle_epi32(c2, 0b01001110); // tmp2 := c2 with swapped 64-bit words + tmp[3] = _mm_blend_epi32(c1, tmp[0], 0b0011); // tmp3 only has the high half of c1, which is now c1L + tmp[1] = _mm_blend_epi32(tmp[2], c4, 0b1100); // tmp1 has now c2H + (c4L<<64) + c1 = _mm_xor_si128(c1, c2); // c1 := c1H + c2L (plus nonsense higher 64 bits) + c0 = _mm_xor_si128(c0, tmp[3]); // c0 := c0 + (c1L<<64) + c2 = _mm_xor_si128(c3, tmp[1]); // c2 := c3 + c2H + (c4L<<64) + c3 = _mm_blend_epi32(c4, tmp[0], 0b1100); // c3 := c4H + c1 = _mm_blend_epi32(c1, tmp[0], 0b1100); // c1 := c1H + c2L + + // single reduction (from gf192_product_pclmul) + tmp[1] = _mm_clmulepi64_si128(c3, p, PCLMUL_LO_X_LO); + tmp[1] = _mm_bsrli_si128(tmp[1], 8); + c2 = _mm_xor_si128(tmp[1], c2); + + tmp[0] = _mm_clmulepi64_si128(c3, p, PCLMUL_LO_X_LO); // tmp0 = p * c3 (HIGH) + tmp[2] = _mm_clmulepi64_si128(c2, p, PCLMUL_LO_X_LO); // tmp1 = p * c2L (LOW) + tmp[3] = _mm_clmulepi64_si128(c2, p, PCLMUL_HI_X_LO); // tmp2 = p * c2H (MID) + c1 = _mm_xor_si128(c1, tmp[0]); // reduce HIGH + c0 = _mm_xor_si128(c0, tmp[2]); // reduce LOW + tmp[0] = _mm_bsrli_si128(tmp[3], 8); // tmp0 = (p*c2H) >> 64 + tmp[2] = _mm_bslli_si128(tmp[3], 8); // tmp2 = (p*c2H) << 64 + c1 = _mm_xor_si128(c1, tmp[0]); // reduce MID + c0 = _mm_xor_si128(c0, tmp[2]); // reduce MID + + if (accumulate) { + c0 = _mm_xor_si128(c0, _mm_loadu_si128((__m128i*)res)); + c1 = _mm_xor_si128(c1, _mm_loadl_epi64((__m128i*)&res->v64[2])); + } + _mm_storeu_si128((__m128i*)res, c0); + res->v64[2] = _mm_extract_epi64(c1, 0); +} + +void gf192_dot_product_pclmul(gf192* res, const gf192* x, const gf192* y, const uint64_t size) { + gf192_dot_product_core_pclmul(res, (const uint8_t*)x, sizeof(gf192), y, size, 0); +} +EXPORT void gf192_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf192_dot_product_pclmul((gf192*) res, (const gf192*) x, (const gf192*) y, size); +} + + +EXPORT void gf192_dot_product_acc_pclmul(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + gf192_dot_product_core_pclmul(res, (const uint8_t*)x, x_byte_slice, y, size, 1); +} +EXPORT void gf192_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf192_dot_product_acc_pclmul((gf192*) res, (const gf192*) x, x_byte_slice, (const gf192*) y, size); +} + + +// res += sum_i x[i . x_byte_slice] * y_f2[i], where every y_f2[i] is 0 or 1 (a bit-select). +// gf192 is 24 bytes: the low two limbs go through a 128-bit lane, the top limb through a 64-bit +// one, so nothing is written past res. +EXPORT void gf192_dot_product_f2_acc_avx2(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + const uint8_t* xp = (const uint8_t*)x; + __m128i acc01 = _mm_loadu_si128((__m128i*)res); // res.v64[0..1] + __m128i acc2 = _mm_loadl_epi64((__m128i*)&res->v64[2]); // res.v64[2] + for (uint64_t i = 0; i < size; ++i) { + const gf192* xi = (const gf192*)(xp + i * x_byte_slice); + // y_f2[i] is 0 or 1: broadcasting its negation gives the 0/all-ones bit-select mask + __m128i mask = _mm_set1_epi64x(-(int64_t)y_f2[i].v64[0]); + acc01 = _mm_xor_si128(acc01, _mm_and_si128(mask, _mm_loadu_si128((__m128i*)xi))); + acc2 = _mm_xor_si128(acc2, _mm_and_si128(mask, _mm_loadl_epi64((__m128i*)&xi->v64[2]))); + } + _mm_storeu_si128((__m128i*)res, acc01); + res->v64[2] = _mm_extract_epi64(acc2, 0); +} +EXPORT void gf192_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf192_dot_product_f2_acc_avx2((gf192*) res, (const gf192*) x, x_byte_slice, (const gf192*) y_f2, size); +} + + +EXPORT void gf192_sum_pow2_avx2(gf192* res, const gf192* x) { gf192_sum_pow2_ref(res, x); } + +void gf192_inverse_pclmul(gf192* res, const gf192* a) { + gf192 tmp, pow_a[7]; // pow_a[i] = a**(2**(2**(i+1))-1) --> a**3, a**15, a**255, a**65536, ... + gf192* pow_a_ptr = &pow_a[0]; + + gf192_square_pclmul(&tmp, a); + gf192_product_pclmul(&pow_a[0], &tmp, a); // pow_a[0] = a^3 + + for (size_t i = 2; i < 128; i <<= 1) { + gf192_square_pclmul(&tmp, pow_a_ptr); + for (size_t j = 1; j < i; j++) { + gf192_square_pclmul(&tmp, &tmp); + } + gf192_product_pclmul(pow_a_ptr + 1, &tmp, pow_a_ptr); + pow_a_ptr++; + } + + pow_a_ptr = &pow_a[4]; + for (size_t i = 32; i > 1; i >>= 1) { + for (size_t j = 0; j < i; j++) { + gf192_square_pclmul(&pow_a[6], &pow_a[6]); + } + gf192_product_pclmul(&pow_a[6], &pow_a[6], pow_a_ptr); + pow_a_ptr--; + } + + // pow_a[6] = a**(2**190-1) + + gf192_square_pclmul(&pow_a[6], &pow_a[6]); + gf192_product_pclmul(&pow_a[6], &pow_a[6], a); + + // pow_a[6] = a**(2**191-1) + + gf192_square_pclmul(res, &pow_a[6]); // res = (a**(2**191-1))**2 = a**(2*2**191-2) = a**(2**192-2) = a**-1 +} +EXPORT void gf192_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a) { + gf192_inverse_pclmul((gf192*) res, (const gf192*) a); +} + + +void gf192_echelon_pow2_avx(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf192) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 192, "echelon width not supported"); + if (x_size == 0) { + *res = GF192_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf192); + static const gf192 PP = {.v64 = {GF192_PV, 0, 0}}; + gf192 left = x[0]; + gf192 right = GF192_ZERO; + gf192 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf192p_lsh(&tmp, x + i * xbs, k * i); + gf192_sum_ref(&left, &left, &tmp); + gf192p_rsh(&tmp, x + i * xbs, 192 - k * i); + gf192_sum_ref(&right, &right, &tmp); + } + gf192_product_pclmul(&tmp, &right, &PP); + gf192_sum_ref(res, &left, &tmp); +} +EXPORT void gf192_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf192_echelon_pow2_avx(k, (gf192*) res, (const gf192*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/gf256.c b/src/sig/sdith/sdith_sdith_common_avx2/gf256.c new file mode 100644 index 0000000000..086401349d --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/gf256.c @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include + +#include "vole_private.h" + +const gf256 GF256_ZERO = {.v64 = {0, 0, 0, 0}}; +const gf256 GF256_ONE = {.v64 = {1, 0, 0, 0}}; + +SDITH_ALWAYS_INLINE uint8_t gf256p_equals(const gf256* const a, const gf256* const b) { + return memcmp(a->v, b->v, 32) == 0; +} + +SDITH_ALWAYS_INLINE void gf256p_sum(gf256* const res, const gf256* const a, const gf256* const b) { + gf256_sum_ref(res, a, b); +} + +SDITH_ALWAYS_INLINE uint8_t gf256p_bitof(const gf256* const a, const uint64_t position) { + CREQUIRE(position >= 0 && position < 256, "bad bit position %" PRIu64, position); + const uint64_t q8 = position >> 3; + const uint64_t r8 = position & 7; + return (a->v[q8] >> r8) & 1; +} + +// 64-bit limb shifts (little-endian v64[4]). +// This function does not need to be CT (same as lsh). +void gf256p_lsh(gf256* const res, const gf256* const a, const uint64_t amount) { + CREQUIRE(amount < 256, "bad left shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[4] = {0, 0, 0, 0}; + if (rb == 0) { + for (uint64_t i = ql; i < 4; i++) o[i] = a->v64[i - ql]; + } else { + for (uint64_t i = 4; i-- > ql;) { + const uint64_t hi = a->v64[i - ql] << rb; + const uint64_t lo = (i - ql >= 1) ? (a->v64[i - ql - 1] >> (64 - rb)) : 0; + o[i] = hi | lo; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; + res->v64[3] = o[3]; +} + +void gf256p_rsh(gf256* const res, const gf256* const a, const uint64_t amount) { + CREQUIRE(amount < 256, "bad right shift amount %" PRIu64, amount); + const uint64_t ql = amount >> 6; + const uint64_t rb = amount & 63; + uint64_t o[4] = {0, 0, 0, 0}; + if (rb == 0) { + for (uint64_t i = 0; i + ql < 4; i++) o[i] = a->v64[i + ql]; + } else { + for (uint64_t i = 0; i + ql < 4; i++) { + const uint64_t lo = a->v64[i + ql] >> rb; + const uint64_t hi = (i + ql + 1 < 4) ? (a->v64[i + ql + 1] << (64 - rb)) : 0; + o[i] = lo | hi; + } + } + res->v64[0] = o[0]; + res->v64[1] = o[1]; + res->v64[2] = o[2]; + res->v64[3] = o[3]; +} + +SDITH_ALWAYS_INLINE void gf256p_mul(gf256* const res, const gf256* const a, const gf256* const b) { + gf256_product_ref(res, a, b); +} + +uint8_t gf256v_equals(const gf256 a, const gf256 b) { return gf256p_equals(&a, &b); } + +gf256 gf256v_sum(const gf256 a, const gf256 b) { + gf256 res; + gf256p_sum(&res, &a, &b); + return res; +} + +uint8_t gf256v_bitof(const gf256 a, const uint64_t position) { return gf256p_bitof(&a, position); } + +gf256 gf256v_lsh(const gf256 a, const uint64_t amount) { + gf256 res; + gf256p_lsh(&res, &a, amount); + return res; +} + +gf256 gf256v_rsh(const gf256 a, const uint64_t amount) { + gf256 res; + gf256p_rsh(&res, &a, amount); + return res; +} + +gf256 gf256v_mul(const gf256 a, const gf256 b) { + gf256 res; + gf256p_mul(&res, &a, &b); + return res; +} + +EXPORT void gf256_set_ref(gf256* res, const gf256* a) { *res = *a; } +EXPORT void gf256_flambda_set_ref(flambda_t* res, const flambda_t* a) { + gf256_set_ref((gf256*) res, (const gf256*) a); +} + + +EXPORT void gf256_sum_ref(gf256* res, const gf256* a, const gf256* b) { + for (uint64_t i = 0; i < 32; ++i) res->v[i] = a->v[i] ^ b->v[i]; +} +EXPORT void gf256_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_sum_ref((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +EXPORT void gf256_product_ref(gf256* res, const gf256* a, const gf256* b) { + // deal with the in-place issue + if (res == b) { + gf256 tmp; + gf256p_mul(&tmp, a, b); + memcpy(res->v, tmp.v, 32); + return; + } + // Out of place product, constant-time and word-level. The 4x4 carryless limb + // products (Karatsuba gf_clmul64) are accumulated into a 512-bit result, then + // reduced modulo the field polynomial x^256 + x^10 + x^5 + x^2 + 1 (0x425) + // with sparse shift-xors. There is no data-dependent branch or memory access, + // so the running time is independent of the secret bits of a and b (this runs + // on prover witness values, where a data-dependent branch would be a timing + // leak). The result is bit-identical to the schoolbook version, so all KATs + // are unchanged. Operand limbs are read before res is written, so res may + // alias a (res == b is handled by the guard above). + const uint64_t* const av = a->v64; + const uint64_t* const bv = b->v64; + uint64_t t[8] = {0}, hi, lo; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) { + gf_clmul64(av[i], bv[j], &hi, &lo); + t[i + j] ^= lo; + t[i + j + 1] ^= hi; + } + // fold the high 256 bits (t[4..7]) down: x^(256+n) = x^n * (x^10 + x^5 + x^2 + 1) + uint64_t r0 = t[0], r1 = t[1], r2 = t[2], r3 = t[3], c; +#define GF256_FOLD(v, L, H) \ + do { \ + (L) = (v) ^ ((v) << 2) ^ ((v) << 5) ^ ((v) << 10); \ + (H) = ((v) >> 62) ^ ((v) >> 59) ^ ((v) >> 54); \ + } while (0) + GF256_FOLD(t[4], lo, hi); r0 ^= lo; r1 ^= hi; + GF256_FOLD(t[5], lo, hi); r1 ^= lo; r2 ^= hi; + GF256_FOLD(t[6], lo, hi); r2 ^= lo; r3 ^= hi; + GF256_FOLD(t[7], lo, hi); r3 ^= lo; c = hi; // c holds coefficients of bits 256..265 + r0 ^= c ^ (c << 2) ^ (c << 5) ^ (c << 10); // second fold; c <= 10 bits, no further overflow +#undef GF256_FOLD + res->v64[0] = r0; + res->v64[1] = r1; + res->v64[2] = r2; + res->v64[3] = r3; +} +EXPORT void gf256_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_product_ref((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +EXPORT void gf256_dot_product_ref(gf256* res, const gf256* x, const gf256* y, const uint64_t size) { + gf256 acc = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf256_product_ref(&tmp, &x[i], &y[i]); + gf256_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf256_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf256_dot_product_ref((gf256*) res, (const gf256*) x, (const gf256*) y, size); +} + + +EXPORT void gf256_dot_product_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + gf256 acc = *res; + gf256 tmp; + for (uint64_t i = 0; i < size; ++i) { + gf256_product_ref(&tmp, &x[i * xbs], &y[i]); + gf256_sum_ref(&acc, &acc, &tmp); + } + *res = acc; +} +EXPORT void gf256_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf256_dot_product_acc_ref((gf256*) res, (const gf256*) x, x_byte_slice, (const gf256*) y, size); +} + + +EXPORT void gf256_dot_product_f2_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + gf256 acc = *res; + for (uint64_t i = 0; i < size; ++i) { + const uint64_t mask = -y_f2[i].v64[0]; + for (uint64_t k = 0; k < 4; ++k) acc.v64[k] ^= x[i * xbs].v64[k] & mask; + } + *res = acc; +} +EXPORT void gf256_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf256_dot_product_f2_acc_ref((gf256*) res, (const gf256*) x, x_byte_slice, (const gf256*) y_f2, size); +} + + +EXPORT void gf256_product_f2_ref(gf256* res, const gf256* a, const gf256* b_f2) { + const uint64_t mask = -b_f2->v64[0]; + for (uint64_t i = 0; i < 4; ++i) res->v64[i] = a->v64[i] & mask; +} +EXPORT void gf256_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2) { + gf256_product_f2_ref((gf256*) res, (const gf256*) a, (const gf256*) b_f2); +} + + +EXPORT void gf256_inverse_ref(gf256* res, const gf256* a) { + // this is the euclidian algorithm to compute the extended gcd + gf256 aa = *a; + CREQUIRE(!gf256p_equals(&aa, &GF256_ZERO), "inverse of 0"); + gf256 uu = GF256_ONE; + uint64_t log2a = 255; + while (gf256p_bitof(&aa, log2a) == 0) --log2a; + gf256 bb; + gf256p_lsh(&bb, &aa, 256 - log2a); + bb.v64[0] ^= GF256_P; + gf256 vv; + gf256p_lsh(&vv, &uu, 256 - log2a); + uint64_t log2b = 255; + while (log2a != 0) { + CASSERT(gf256v_equals(gf256v_mul(*a, uu), aa), "bug1"); + CASSERT(gf256v_equals(gf256v_mul(*a, vv), bb), "bug2"); + while (log2b >= log2a) { + if (gf256p_bitof(&bb, log2b)) { + gf256 tmp; + gf256p_lsh(&tmp, &aa, log2b - log2a); + gf256p_sum(&bb, &bb, &tmp); + gf256p_lsh(&tmp, &uu, log2b - log2a); + gf256p_sum(&vv, &vv, &tmp); + } + --log2b; + } + // swap aa <-> bb, uu <-> vv + gf256 tmp = aa; + aa = bb; + bb = tmp; + tmp = uu; + uu = vv; + vv = tmp; + uint64_t tmp2 = log2a; + log2a = log2b; + log2b = tmp2; + // update log2a + CASSERT(!gf256p_equals(&aa, &GF256_ZERO), "bug3"); + while (gf256p_bitof(&aa, log2a) == 0) --log2a; + } + CASSERT(gf256p_equals(&aa, &GF256_ONE), "bug4"); + *res = uu; +} +EXPORT void gf256_flambda_inverse_ref(flambda_t* res, const flambda_t* a) { + gf256_inverse_ref((gf256*) res, (const gf256*) a); +} + + +EXPORT void gf256_sum_pow2_naive(gf256* res, const gf256* x) { + gf256 ONE = GF256_ONE; + gf256 r = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 0; i < 256; ++i) { + gf256p_lsh(&tmp, &ONE, i); + gf256p_mul(&tmp, &tmp, x + i); + gf256p_sum(&r, &r, &tmp); + } + *res = r; +} + +EXPORT void gf256_sum_pow2_ref(gf256* res, const gf256* x) { + static const gf256 PP = {.v64 = {GF256_PV, 0, 0, 0}}; + gf256 left = x[0]; + gf256 right = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 1; i < 256; ++i) { + gf256p_lsh(&tmp, x + i, i); + gf256p_sum(&left, &left, &tmp); + gf256p_rsh(&tmp, x + i, 256 - i); + gf256p_sum(&right, &right, &tmp); + } + gf256p_mul(&tmp, &right, &PP); + gf256p_sum(res, &left, &tmp); +} +EXPORT void gf256_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x) { + gf256_sum_pow2_ref((gf256*) res, (const gf256*) x); +} + + +void gf256_echelon_pow2_naive(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + CREQUIRE(k > 0, "k not supported"); + CREQUIRE(k * x_size <= 256, "echelon width not supported"); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + gf256 ONE = GF256_ONE; + gf256 r = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 0; i < x_size; ++i) { + gf256p_lsh(&tmp, &ONE, k * i); + gf256p_mul(&tmp, &tmp, x + i * xbs); + gf256p_sum(&r, &r, &tmp); + } + *res = r; +} + +void gf256_echelon_pow2_ref(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 256, "echelon width not supported"); + if (x_size == 0) { + *res = GF256_ZERO; + return; + } + const uint64_t xbs = x_byte_slice / sizeof(gf256); + static const gf256 PP = {.v64 = {GF256_PV, 0, 0, 0}}; + gf256 left = x[0]; + gf256 right = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf256p_lsh(&tmp, x + i * xbs, k * i); + gf256p_sum(&left, &left, &tmp); + gf256p_rsh(&tmp, x + i * xbs, 256 - k * i); + gf256p_sum(&right, &right, &tmp); + } + gf256p_mul(&tmp, &right, &PP); + gf256p_sum(res, &left, &tmp); +} +EXPORT void gf256_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf256_echelon_pow2_ref(k, (gf256*) res, (const gf256*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/gf256_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/gf256_avx2.c new file mode 100644 index 0000000000..c76eea1ecf --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/gf256_avx2.c @@ -0,0 +1,401 @@ +#include + +#include "vole_private.h" + +#define PCLMUL_LO_X_LO 0 +#define PCLMUL_LO_X_HI 16 +#define PCLMUL_HI_X_LO 1 +#define PCLMUL_HI_X_HI 17 + +static void gf256_square_pclmul(gf256* res, const gf256* a) { + const __m128i p = _mm_set_epi64x(0, GF256_P); + __m128i a01 = _mm_loadu_si128((__m128i*)a); + __m128i a23 = _mm_loadu_si128((__m128i*)&a->v64[2]); + // multiply a and b + // we have a = (a3X^192 + a2X^128 + a1X^64 + a0) + // then c = c4X^256 + c3X^192 + c2X^128 + c1X^64 + c0 + // with c6 = a3a3 + // and c4 = a2a2 + // and c2 = a1a1 + // and c0 = a0a0 + __m128i tmp[9]; + + tmp[0] = _mm_clmulepi64_si128(a01, a01, PCLMUL_LO_X_LO); // tmp0 = a0b0 + tmp[1] = _mm_clmulepi64_si128(a01, a01, PCLMUL_HI_X_HI); // tmp3 = a1b1 + tmp[2] = _mm_clmulepi64_si128(a23, a23, PCLMUL_LO_X_LO); // tmp8 = a2b2 + tmp[3] = _mm_clmulepi64_si128(a23, a23, PCLMUL_HI_X_HI); // tmp6 = a3b3 + + // reduction: + // (1) multiply high result (in tmp2 and tmp3) by p, return 256 MSBs, then + // (2) multiply that by p again, return 256 LSBs as remainder + // (3) add remainder to 256 LSBs of multiplication result + + // Step 1: multiply high result (in tmp2 and tmp3) by p, return 256 MSBs + // (c2L + c2HX^64 + c3LX^128 + c3HX^192) * (p + X^256) = p*c2L + p*c2HX^64 + p*c3LX^128 + p*c3HX^192 + c2LX^256 + + // c2HX^320 + c3LX^384 + c3HX^448 but we only care about the high result: p*c2L + p*c2HX^64 + p*c3LX^128 are + // completely in the low half the upper half of p*c3HX^192 is the first term of the high result c2LX^256 + c2HX^320 + + // c3LX^384 + c3HX^448 is added to that + tmp[4] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_HI_X_LO); + tmp[4] = _mm_bsrli_si128(tmp[4], 8); + tmp[2] = _mm_xor_si128(tmp[4], tmp[2]); + + // tmp2 and tmp3 now hold the high multiplication result, and now we multiply p again + // but now we want the LSBs of (c2L + c2HX^64 + c3LX^128 + c3HX^192) * p + tmp[4] = _mm_clmulepi64_si128(tmp[2], p, PCLMUL_LO_X_LO); // tmp4 = p * c2L (X^0) + tmp[5] = _mm_clmulepi64_si128(tmp[2], p, PCLMUL_HI_X_LO); // tmp5 = p * c2H (X^64) + tmp[6] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_LO_X_LO); // tmp6 = p * c3L (X^128) + tmp[7] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_HI_X_LO); // tmp7 = p * c3H (X^192) + tmp[0] = _mm_xor_si128(tmp[0], tmp[4]); // reduce LOW first step + tmp[1] = _mm_xor_si128(tmp[1], tmp[6]); // reduce HIGH first step + tmp[2] = _mm_bslli_si128(tmp[5], 8); + tmp[3] = _mm_bsrli_si128(tmp[5], 8); + tmp[4] = _mm_bslli_si128(tmp[7], 8); + tmp[0] = _mm_xor_si128(tmp[0], tmp[2]); // final LOW reduction + tmp[1] = _mm_xor_si128(tmp[1], tmp[3]); // HIGH second step + tmp[1] = _mm_xor_si128(tmp[1], tmp[4]); // HIGH final step + + _mm_storeu_si128((__m128i*)res, tmp[0]); + _mm_storeu_si128((__m128i*)&res->v64[2], tmp[1]); +} + +EXPORT void gf256_product_pclmul(gf256* res, const gf256* a, const gf256* b) { + const __m128i p = _mm_set_epi64x(0, GF256_P); + __m128i a01 = _mm_loadu_si128((__m128i*)a); + __m128i b01 = _mm_loadu_si128((__m128i*)b); + __m128i a23 = _mm_loadu_si128((__m128i*)&a->v64[2]); + __m128i b23 = _mm_loadu_si128((__m128i*)&b->v64[2]); + // multiply a and b + // we have a = (a3X^192 + a2X^128 + a1X^64 + a0) and b analogous + // then c = c4X^256 + c3X^192 + c2X^128 + c1X^64 + c0 + // with c6 = a3b3 + // and c5 = a3b2 + a2b3 + // and c4 = a3b1 + a2b2 + a1b3 + // and c3 = a3b0 + a2b1 + a1b2 + a0b3 + // and c2 = a2b0 + a1b1 + a0b2 + // and c1 = a1b0 + a0b1 + // and c0 = a0b0 + __m128i tmp[9]; + + tmp[0] = _mm_clmulepi64_si128(a01, b01, PCLMUL_LO_X_LO); // tmp0 = a0b0 + tmp[1] = _mm_clmulepi64_si128(a01, b01, PCLMUL_LO_X_HI); // tmp1 = a0b1 + tmp[2] = _mm_clmulepi64_si128(a01, b01, PCLMUL_HI_X_LO); // tmp2 = a1b0 + tmp[3] = _mm_clmulepi64_si128(a01, b01, PCLMUL_HI_X_HI); // tmp3 = a1b1 + tmp[4] = _mm_clmulepi64_si128(a01, b23, PCLMUL_LO_X_LO); // tmp4 = a0b2 + tmp[5] = _mm_clmulepi64_si128(a01, b23, PCLMUL_LO_X_HI); // tmp5 = a0b3 + tmp[6] = _mm_clmulepi64_si128(a01, b23, PCLMUL_HI_X_LO); // tmp6 = a1b2 + tmp[7] = _mm_clmulepi64_si128(a01, b23, PCLMUL_HI_X_HI); // tmp7 = a1b3 + tmp[8] = _mm_clmulepi64_si128(a23, b23, PCLMUL_LO_X_LO); // tmp8 = a2b2 + + // a01 is now free to be used as tmp register + + tmp[1] = _mm_xor_si128(tmp[1], tmp[2]); // tmp1 = a0b1 + a1b0 + tmp[2] = _mm_xor_si128(tmp[3], tmp[4]); // tmp2 = a1b1 + a0b2 + tmp[3] = _mm_xor_si128(tmp[5], tmp[6]); // tmp3 = a0b3 + a1b2 + tmp[4] = _mm_xor_si128(tmp[7], tmp[8]); // tmp4 = a1b3 + a2b2 + + tmp[5] = _mm_clmulepi64_si128(a23, b23, PCLMUL_LO_X_HI); // tmp5 = a2b3 + tmp[7] = _mm_clmulepi64_si128(a23, b23, PCLMUL_HI_X_LO); // tmp7 = a3b2 + tmp[6] = _mm_clmulepi64_si128(a23, b23, PCLMUL_HI_X_HI); // tmp6 = a3b3 + // b23 is now free to be used as tmp register + tmp[8] = _mm_clmulepi64_si128(a23, b01, PCLMUL_LO_X_LO); // tmp8 = a2b0 + a01 = _mm_clmulepi64_si128(a23, b01, PCLMUL_LO_X_HI); // a01 = a2b1 + b23 = _mm_clmulepi64_si128(a23, b01, PCLMUL_HI_X_LO); // b23 = a3b0 + a23 = _mm_clmulepi64_si128(a23, b01, PCLMUL_HI_X_HI); // a23 = a3b1 + + tmp[2] = _mm_xor_si128(tmp[2], tmp[8]); // tmp2 = a1b1 + a0b2 + a2b0 + tmp[3] = _mm_xor_si128(tmp[3], a01); // tmp3 = a0b3 + a1b2 + a2b1 + tmp[4] = _mm_xor_si128(tmp[4], a23); // tmp4 = a1b3 + a2b2 + a3b1 + tmp[5] = _mm_xor_si128(tmp[5], tmp[7]); // tmp5 = a2b3 + a3b2 + tmp[3] = _mm_xor_si128(tmp[3], b23); // tmp3 = a0b3 + a1b2 + a2b1 + a3b0 + + // condense to a 4-register representation where two hold the low result and two hold the high result + // currently we have + // c0c0 + // c1c1 + // c2c2 + // c3 c3 + // c4c4 + // c5c5 + // c6c6 + // and we want c0||c1 to hold the low result and c2||c3 to hold the high result + tmp[7] = _mm_bslli_si128(tmp[1], 8); + tmp[1] = _mm_bsrli_si128(tmp[1], 8); + tmp[0] = _mm_xor_si128(tmp[0], tmp[7]); // tmp0 = c0 + c1L<<64 + tmp[1] = _mm_xor_si128(tmp[1], tmp[2]); // tmp1 = c2 + c1H + tmp[7] = _mm_bslli_si128(tmp[3], 8); // tmp7 = c3L<<64 + tmp[2] = _mm_bsrli_si128(tmp[3], 8); // tmp2 = c3H + tmp[1] = _mm_xor_si128(tmp[1], tmp[7]); // tmp1 = c2 + c1H + c3L<<64 + tmp[2] = _mm_xor_si128(tmp[2], tmp[4]); // tmp2 = c3H + c4 + tmp[4] = _mm_bslli_si128(tmp[5], 8); // tmp4 = c5L<<64 + tmp[5] = _mm_bsrli_si128(tmp[5], 8); // tmp5 = c5H + tmp[2] = _mm_xor_si128(tmp[2], tmp[4]); // tmp2 = c3H + c4 + c5L<<64 + tmp[3] = _mm_xor_si128(tmp[6], tmp[5]); // tmp3 = c6 + c5H + + // reduction: + // (1) multiply high result (in tmp2 and tmp3) by p, return 256 MSBs, then + // (2) multiply that by p again, return 256 LSBs as remainder + // (3) add remainder to 256 LSBs of multiplication result + + // Step 1: multiply high result (in tmp2 and tmp3) by p, return 256 MSBs + // (c2L + c2HX^64 + c3LX^128 + c3HX^192) * (p + X^256) = p*c2L + p*c2HX^64 + p*c3LX^128 + p*c3HX^192 + c2LX^256 + + // c2HX^320 + c3LX^384 + c3HX^448 but we only care about the high result: p*c2L + p*c2HX^64 + p*c3LX^128 are + // completely in the low half the upper half of p*c3HX^192 is the first term of the high result c2LX^256 + c2HX^320 + + // c3LX^384 + c3HX^448 is added to that + tmp[4] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_HI_X_LO); + tmp[4] = _mm_bsrli_si128(tmp[4], 8); + tmp[2] = _mm_xor_si128(tmp[4], tmp[2]); + + // tmp2 and tmp3 now hold the high multiplication result, and now we multiply p again + // but now we want the LSBs of (c2L + c2HX^64 + c3LX^128 + c3HX^192) * p + tmp[4] = _mm_clmulepi64_si128(tmp[2], p, PCLMUL_LO_X_LO); // tmp4 = p * c2L (X^0) + tmp[5] = _mm_clmulepi64_si128(tmp[2], p, PCLMUL_HI_X_LO); // tmp5 = p * c2H (X^64) + tmp[6] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_LO_X_LO); // tmp6 = p * c3L (X^128) + tmp[7] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_HI_X_LO); // tmp7 = p * c3H (X^192) + tmp[0] = _mm_xor_si128(tmp[0], tmp[4]); // reduce LOW first step + tmp[1] = _mm_xor_si128(tmp[1], tmp[6]); // reduce HIGH first step + tmp[2] = _mm_bslli_si128(tmp[5], 8); + tmp[3] = _mm_bsrli_si128(tmp[5], 8); + tmp[4] = _mm_bslli_si128(tmp[7], 8); + tmp[0] = _mm_xor_si128(tmp[0], tmp[2]); // final LOW reduction + tmp[1] = _mm_xor_si128(tmp[1], tmp[3]); // HIGH second step + tmp[1] = _mm_xor_si128(tmp[1], tmp[4]); // HIGH final step + + _mm_storeu_si128((__m128i*)res, tmp[0]); + _mm_storeu_si128((__m128i*)&res->v64[2], tmp[1]); +} +EXPORT void gf256_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_product_pclmul((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +EXPORT void gf256_product_pclmul_f2(gf256* res, const gf256* a, const gf256* b) { + __m256i bb = _mm256_set1_epi64x(-b->v64[0]); + __m256i aa = _mm256_loadu_si256((__m256i*)a); + bb = _mm256_and_si256(bb, aa); + _mm256_storeu_si256((__m256i*)res, bb); +} +EXPORT void gf256_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_product_pclmul_f2((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +// res = sum_i x[i . x_byte_slice]*y[i] (accumulated on top of res if accumulate). +// The clmul products are aggregated per Karatsuba term across the whole vector +// (10 accumulators) and a single reduction is done at the end. +SDITH_ALWAYS_INLINE void gf256_dot_product_core_pclmul(gf256* res, const uint8_t* x, const uint64_t x_byte_slice, + const gf256* y, const uint64_t size, + const int accumulate) { + const __m128i p = _mm_set_epi64x(0, GF256_P); + // one accumulator per clmul product (10 = 4*(4+1)/2) + __m128i accD0 = _mm_setzero_si128(); // x0*y0 (deg 0) + __m128i accD1 = _mm_setzero_si128(); // x1*y1 (deg 2) + __m128i accD2 = _mm_setzero_si128(); // x2*y2 (deg 4) + __m128i accD3 = _mm_setzero_si128(); // x3*y3 (deg 6) + __m128i accP01 = _mm_setzero_si128(); // (x0+x1)*(y0+y1) (deg 1) + __m128i accP02 = _mm_setzero_si128(); // (x0+x2)*(y0+y2) (deg 2) + __m128i accP03 = _mm_setzero_si128(); // (x0+x3)*(y0+y3) (deg 3) + __m128i accP12 = _mm_setzero_si128(); // (x1+x2)*(y1+y2) (deg 3) + __m128i accP13 = _mm_setzero_si128(); // (x1+x3)*(y1+y3) (deg 4) + __m128i accP23 = _mm_setzero_si128(); // (x2+x3)*(y2+y3) (deg 5) + for (uint64_t i = 0; i < size; ++i) { + const gf256* xi = (const gf256*)(x + i * x_byte_slice); + __m128i a01 = _mm_loadu_si128((__m128i*)xi); // (x0,x1) + __m128i a23 = _mm_loadu_si128((__m128i*)&xi->v64[2]); // (x2,x3) + __m128i b01 = _mm_loadu_si128((__m128i*)&y[i]); // (y0,y1) + __m128i b23 = _mm_loadu_si128((__m128i*)&y[i].v64[2]); // (y2,y3) + __m128i a1 = _mm_srli_si128(a01, 8); // (x1,0) + __m128i a3 = _mm_srli_si128(a23, 8); // (x3,0) + __m128i b1 = _mm_srli_si128(b01, 8); // (y1,0) + __m128i b3 = _mm_srli_si128(b23, 8); // (y3,0) + // pair sums (each in lane 0) + __m128i sx01 = _mm_xor_si128(a01, a1); // x0^x1 + __m128i sx23 = _mm_xor_si128(a23, a3); // x2^x3 + __m128i sx02 = _mm_xor_si128(a01, a23); // x0^x2 + __m128i sx13 = _mm_xor_si128(a1, a3); // x1^x3 + __m128i sx03 = _mm_xor_si128(a01, a3); // x0^x3 + __m128i sx12 = _mm_xor_si128(a1, a23); // x1^x2 + __m128i sy01 = _mm_xor_si128(b01, b1); // y0^y1 + __m128i sy23 = _mm_xor_si128(b23, b3); // y2^y3 + __m128i sy02 = _mm_xor_si128(b01, b23); // y0^y2 + __m128i sy13 = _mm_xor_si128(b1, b3); // y1^y3 + __m128i sy03 = _mm_xor_si128(b01, b3); // y0^y3 + __m128i sy12 = _mm_xor_si128(b1, b23); // y1^y2 + accD0 = _mm_xor_si128(accD0, _mm_clmulepi64_si128(a01, b01, PCLMUL_LO_X_LO)); + accD1 = _mm_xor_si128(accD1, _mm_clmulepi64_si128(a01, b01, PCLMUL_HI_X_HI)); + accD2 = _mm_xor_si128(accD2, _mm_clmulepi64_si128(a23, b23, PCLMUL_LO_X_LO)); + accD3 = _mm_xor_si128(accD3, _mm_clmulepi64_si128(a23, b23, PCLMUL_HI_X_HI)); + accP01 = _mm_xor_si128(accP01, _mm_clmulepi64_si128(sx01, sy01, PCLMUL_LO_X_LO)); + accP23 = _mm_xor_si128(accP23, _mm_clmulepi64_si128(sx23, sy23, PCLMUL_LO_X_LO)); + accP02 = _mm_xor_si128(accP02, _mm_clmulepi64_si128(sx02, sy02, PCLMUL_LO_X_LO)); + accP13 = _mm_xor_si128(accP13, _mm_clmulepi64_si128(sx13, sy13, PCLMUL_LO_X_LO)); + accP03 = _mm_xor_si128(accP03, _mm_clmulepi64_si128(sx03, sy03, PCLMUL_LO_X_LO)); + accP12 = _mm_xor_si128(accP12, _mm_clmulepi64_si128(sx12, sy12, PCLMUL_LO_X_LO)); + } + // degree coefficients c0..c6 (same layout as gf256_product_pclmul before condensing) + __m128i tmp[9]; + tmp[0] = accD0; // c0 + tmp[1] = _mm_xor_si128(accP01, _mm_xor_si128(accD0, accD1)); // c1 + tmp[2] = _mm_xor_si128(accD1, _mm_xor_si128(accP02, _mm_xor_si128(accD0, accD2))); // c2 + tmp[3] = _mm_xor_si128(_mm_xor_si128(accP03, _mm_xor_si128(accD0, accD3)), + _mm_xor_si128(accP12, _mm_xor_si128(accD1, accD2))); // c3 + tmp[4] = _mm_xor_si128(accD2, _mm_xor_si128(accP13, _mm_xor_si128(accD1, accD3))); // c4 + tmp[5] = _mm_xor_si128(accP23, _mm_xor_si128(accD2, accD3)); // c5 + tmp[6] = accD3; // c6 + + // condense to the 4-register (low||high) representation (from gf256_product_pclmul) + tmp[7] = _mm_bslli_si128(tmp[1], 8); + tmp[1] = _mm_bsrli_si128(tmp[1], 8); + tmp[0] = _mm_xor_si128(tmp[0], tmp[7]); // tmp0 = c0 + c1L<<64 + tmp[1] = _mm_xor_si128(tmp[1], tmp[2]); // tmp1 = c2 + c1H + tmp[7] = _mm_bslli_si128(tmp[3], 8); // tmp7 = c3L<<64 + tmp[2] = _mm_bsrli_si128(tmp[3], 8); // tmp2 = c3H + tmp[1] = _mm_xor_si128(tmp[1], tmp[7]); // tmp1 = c2 + c1H + c3L<<64 + tmp[2] = _mm_xor_si128(tmp[2], tmp[4]); // tmp2 = c3H + c4 + tmp[4] = _mm_bslli_si128(tmp[5], 8); // tmp4 = c5L<<64 + tmp[5] = _mm_bsrli_si128(tmp[5], 8); // tmp5 = c5H + tmp[2] = _mm_xor_si128(tmp[2], tmp[4]); // tmp2 = c3H + c4 + c5L<<64 + tmp[3] = _mm_xor_si128(tmp[6], tmp[5]); // tmp3 = c6 + c5H + + // single reduction (from gf256_product_pclmul) + tmp[4] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_HI_X_LO); + tmp[4] = _mm_bsrli_si128(tmp[4], 8); + tmp[2] = _mm_xor_si128(tmp[4], tmp[2]); + + tmp[4] = _mm_clmulepi64_si128(tmp[2], p, PCLMUL_LO_X_LO); // tmp4 = p * c2L (X^0) + tmp[5] = _mm_clmulepi64_si128(tmp[2], p, PCLMUL_HI_X_LO); // tmp5 = p * c2H (X^64) + tmp[6] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_LO_X_LO); // tmp6 = p * c3L (X^128) + tmp[7] = _mm_clmulepi64_si128(tmp[3], p, PCLMUL_HI_X_LO); // tmp7 = p * c3H (X^192) + tmp[0] = _mm_xor_si128(tmp[0], tmp[4]); // reduce LOW first step + tmp[1] = _mm_xor_si128(tmp[1], tmp[6]); // reduce HIGH first step + tmp[2] = _mm_bslli_si128(tmp[5], 8); + tmp[3] = _mm_bsrli_si128(tmp[5], 8); + tmp[4] = _mm_bslli_si128(tmp[7], 8); + tmp[0] = _mm_xor_si128(tmp[0], tmp[2]); // final LOW reduction + tmp[1] = _mm_xor_si128(tmp[1], tmp[3]); // HIGH second step + tmp[1] = _mm_xor_si128(tmp[1], tmp[4]); // HIGH final step + + if (accumulate) { + tmp[0] = _mm_xor_si128(tmp[0], _mm_loadu_si128((__m128i*)res)); + tmp[1] = _mm_xor_si128(tmp[1], _mm_loadu_si128((__m128i*)&res->v64[2])); + } + _mm_storeu_si128((__m128i*)res, tmp[0]); + _mm_storeu_si128((__m128i*)&res->v64[2], tmp[1]); +} + +void gf256_dot_product_pclmul(gf256* res, const gf256* x, const gf256* y, const uint64_t size) { + gf256_dot_product_core_pclmul(res, (const uint8_t*)x, sizeof(gf256), y, size, 0); +} +EXPORT void gf256_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size) { + gf256_dot_product_pclmul((gf256*) res, (const gf256*) x, (const gf256*) y, size); +} + + +EXPORT void gf256_dot_product_acc_pclmul(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + gf256_dot_product_core_pclmul(res, (const uint8_t*)x, x_byte_slice, y, size, 1); +} +EXPORT void gf256_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size) { + gf256_dot_product_acc_pclmul((gf256*) res, (const gf256*) x, x_byte_slice, (const gf256*) y, size); +} + + +EXPORT void gf256_dot_product_f2_acc_avx2(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size) { + CASSERT(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + const uint8_t* xp = (const uint8_t*)x; + __m256i acc = _mm256_loadu_si256((__m256i*)res); + for (uint64_t i = 0; i < size; ++i) { + // y_f2[i] is 0 or 1: broadcasting its negation gives the 0/all-ones bit-select mask + __m256i mask = _mm256_set1_epi64x(-y_f2[i].v64[0]); + acc = _mm256_xor_si256(acc, _mm256_and_si256(mask, _mm256_loadu_si256((__m256i*)(xp + i * x_byte_slice)))); + } + _mm256_storeu_si256((__m256i*)res, acc); +} +EXPORT void gf256_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size) { + gf256_dot_product_f2_acc_avx2((gf256*) res, (const gf256*) x, x_byte_slice, (const gf256*) y_f2, size); +} + + +EXPORT void gf256_sum_avx2(gf256* res, const gf256* a, const gf256* b) { + __m256i acc0, acc1, acc2; + acc0 = _mm256_loadu_si256((__m256i*)(a->v)); + acc1 = _mm256_loadu_si256((__m256i*)(b->v)); + acc2 = _mm256_xor_si256(acc0, acc1); + _mm256_storeu_si256((__m256i*)(res->v), acc2); +} +EXPORT void gf256_flambda_sum_avx2(flambda_t* res, const flambda_t* a, const flambda_t* b) { + gf256_sum_avx2((gf256*) res, (const gf256*) a, (const gf256*) b); +} + + +void gf256_inverse_pclmul(gf256* res, const gf256* a) { + gf256 tmp, pow_a[7]; // pow_a[i] = a**(2**(2**(i+1))-1) --> a**3, a**15, a**255, a**65536, ... + gf256* pow_a_ptr = &pow_a[0]; + + gf256_square_pclmul(&tmp, a); + gf256_product_pclmul(&pow_a[0], &tmp, a); // pow_a[0] = a^3 + + for (size_t i = 2; i < 128; i <<= 1) { + gf256_square_pclmul(&tmp, pow_a_ptr); + for (size_t j = 1; j < i; j++) { + gf256_square_pclmul(&tmp, &tmp); + } + gf256_product_pclmul(pow_a_ptr + 1, &tmp, pow_a_ptr); + pow_a_ptr++; + } + + pow_a_ptr = &pow_a[5]; + for (size_t i = 64; i > 1; i >>= 1) { + for (size_t j = 0; j < i; j++) { + gf256_square_pclmul(&pow_a[6], &pow_a[6]); + } + gf256_product_pclmul(&pow_a[6], &pow_a[6], pow_a_ptr); + pow_a_ptr--; + } + + // pow_a[6] = a**(2**254-1) + + gf256_square_pclmul(&pow_a[6], &pow_a[6]); + gf256_product_pclmul(&pow_a[6], &pow_a[6], a); + + // pow_a[6] = a**(2**255-1) + + gf256_square_pclmul(res, &pow_a[6]); // res = (a**(2**255-1))**2 = a**(2*2**255-2) = a**(2**256-2) = a**-1 +} +EXPORT void gf256_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a) { + gf256_inverse_pclmul((gf256*) res, (const gf256*) a); +} + + +void gf256_echelon_pow2_avx(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice) { + CREQUIRE(x_byte_slice % sizeof(gf256) == 0, "byte slice not supported"); + CASSERT(k > 0, "k not supported"); + CASSERT(k * x_size <= 256, "echelon width not supported"); + CASSERT_ALIGNMENT(res, 32); + + if (x_size == 0) { + *res = GF256_ZERO; + return; + } + CASSERT_ALIGNMENT(x, 32); + const uint64_t xbs = x_byte_slice / sizeof(gf256); + static const gf256 PP = {.v64 = {GF256_PV, 0, 0, 0}}; + gf256 left = x[0]; + gf256 right = GF256_ZERO; + gf256 tmp; + for (uint64_t i = 1; i < x_size; ++i) { + gf256p_lsh(&tmp, x + i * xbs, k * i); + gf256_sum_avx2(&left, &left, &tmp); + gf256p_rsh(&tmp, x + i * xbs, 256 - k * i); + gf256_sum_avx2(&right, &right, &tmp); + } + gf256_product_pclmul(&tmp, &right, &PP); + gf256_sum_avx2(res, &left, &tmp); +} +EXPORT void gf256_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice) { + gf256_echelon_pow2_avx(k, (gf256*) res, (const gf256*) x, x_size, x_byte_slice); +} + diff --git a/src/sig/sdith/sdith_sdith_common_avx2/ggm.c b/src/sig/sdith/sdith_sdith_common_avx2/ggm.c new file mode 100644 index 0000000000..3d8b3051ef --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/ggm.c @@ -0,0 +1,222 @@ +#include "ggm.h" + +#include +#include + +#include "sdith_prng.h" +#include "vole_private.h" + +// private layout (move to a ggm-private.h if needed) +struct full_ggm_tree_t { + uint32_t lambda; + uint32_t tau; + uint32_t kappa; + uint32_t lambda_bytes; + uint32_t depth; + uint32_t theta; // domain-separation truncation width = depth + 2 + uint32_t num_leaves; + uint64_t rng_data[4]; // here: global salt (lambda bits used) + GGM_SEED_RNG_LR_F* seed_rng_lr; // left and right in one call + GGM_COMMIT_RNG_F* commit_rng; // takes the extended leaf seed + EXTEND_LEAF_SEED_F* extend_leaf_seed; // raw leaf seed -> extended leaf seed + uint32_t extended_bytes; // byte size of an extended leaf seed + const seed_t* root_seed; // shared with seeds_cache + seed_t* seeds_cache; // 2*lambda_bytes*depth bytes + uint32_t cached_index; // + uint32_t* open_buf; // 4*tau*depth bytes + // space for the root seed copy + cache + open buffer +}; + +/** @brief if x==0, return 0, else floor(log2(x)) */ +uint32_t floor_log2i(uint32_t x) { + if (x == 0) return 0; + return 31 - __builtin_clz(x); +} + +// alternative function to use if the builtin above does not exist +uint32_t floor_log2i_compat(uint32_t x) { + uint32_t res = 0; + uint32_t t = x; + if (t >> 16) { + res += 16; + t >>= 16; + } + if (t >> 8) { + res += 8; + t >>= 8; + } + if (t >> 4) { + res += 4; + t >>= 4; + } + if (t >> 2) { + res += 2; + t >>= 2; + } + if (t >> 1) { + res += 1; + } + return res; +} + +/** @brief if x==0, return 0, else ceil(log2(x)) */ +uint32_t ceil_log2i(uint32_t x) { + uint32_t res = floor_log2i(x); + if (x == (UINT32_C(1) << res)) + return res; + else + return res + 1; +} + +EXPORT uint32_t estimate_topen_tmp_bytes(uint32_t tau, uint32_t kappa) { + uint32_t depth = ceil_log2i(tau) + kappa; // depth = ceil(log2(tau)) + kappa. + return 4 * tau * depth; +} + + +/** decode "delta" into the indexes of the hidden leaves */ +// hidden_nodes = [delta[i.kappa, (i+1).kappa) * tau + i for i in range(tau)] +// qsort hidden_leaves +// uint64_t hidden_leaves_indexes(uint64_t kappa, uint64_t tau, // dims +// uint32_t* hidden_leaves, // output: node indexes +// const bitvec_t* delta); // input: bits of delta + +// swap two elements - used in partition +void swap(uint32_t* a, uint32_t* b) { + uint32_t t = *a; + *a = *b; + *b = t; +} + +// partioning - used in quick sort +int partition(uint32_t arr[], int low, int high) { + uint32_t pivot = arr[high]; + int hi = high - 1; + int lo = low; + while (1) { + while (lo <= hi && arr[lo] <= pivot) ++lo; + while (lo <= hi && arr[hi] >= pivot) --hi; + if (lo > hi) break; + swap(arr + lo, arr + hi); + ++lo; + --hi; + } + swap(arr + lo, arr + high); + return lo; +} + +// QuickSort - used in hidden_leaves_indexes +void quickSort(uint32_t arr[], int low, int high) { + if (low < high) { + int pi = partition(arr, low, high); + + quickSort(arr, low, pi - 1); + quickSort(arr, pi + 1, high); + } +} + +SDITH_ALWAYS_INLINE uint32_t extract_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, const uint64_t* data) { + const uint64_t kappa_mask = (UINT64_C(1) << kappa) - 1; + uint64_t limb_pos = bitpos >> 6; + uint64_t limb_rem = bitpos & UINT64_C(63); + if (limb_rem + kappa <= 64) { + return (data[limb_pos] >> limb_rem) & kappa_mask; + } else { + return ((data[limb_pos] >> limb_rem) | (data[limb_pos + 1] << (64 - limb_rem))) & kappa_mask; + } +} +SDITH_ALWAYS_INLINE void xorto_kappabit_uint_inline(uint64_t kappa, uint64_t bitpos, uint64_t* data, uint64_t value) { + const uint64_t kappa_mask = (UINT64_C(1) << kappa) - 1; + uint64_t limb_pos = bitpos >> 6; + uint64_t limb_rem = bitpos & UINT64_C(63); + value &= kappa_mask; + if (limb_rem + kappa <= 64) { + data[limb_pos] ^= value << limb_rem; + } else { + data[limb_pos] ^= value << limb_rem; + data[limb_pos + 1] ^= value >> (64 - limb_rem); + } +} + +EXPORT uint32_t extract_kappabit_uint(uint64_t kappa, uint64_t bitpos, const void* data) { + return extract_kappabit_uint_inline(kappa, bitpos, (uint64_t*)data); +} +EXPORT void xorto_kappabit_uint(uint64_t kappa, uint64_t bitpos, void* data, uint64_t value) { + xorto_kappabit_uint_inline(kappa, bitpos, (uint64_t*)data, value); +} + +EXPORT void hidden_leaves_indexes(uint64_t kappa, uint64_t tau, uint32_t* hidden_leaves, const bitvec_t* delta) { + for (uint64_t k = 0; k < tau; ++k) { + hidden_leaves[k] = extract_kappabit_uint_inline(kappa, k * kappa, delta) * tau + k; + } + quickSort(hidden_leaves, 0, tau - 1); +} +EXPORT void hidden_leaves_indexes2(uint64_t kappa, uint64_t tau, uint32_t* hidden_leaves, const bitvec_t* delta) { + const uint64_t start_index = tau * (UINT64_C(1) << kappa); + for (uint64_t k = 0; k < tau; ++k) { + hidden_leaves[k] = extract_kappabit_uint_inline(kappa, k * kappa, delta) * tau + k + start_index; + } + quickSort(hidden_leaves, 0, tau - 1); +} + +/** estimate the number of nodes to open for this choice of delta: */ +// algorithm: +// sibling_path_indexes = [] +// new nodes_list = [] +// for (depth = tau*kappa-1 down to 0) +// while hidden_leave is not empty { +// if (hidden_leaves have >= 2 elements and hidden_leave[0] ^ hidden_leave[1] == 1) { +// append hidden_leave[0] >> 1 to new nodes_list +// pop the two first nodes of hidden_nodes +// } else { +// append hidden_leave[0] ^ 1 to sibling_path_indexes +// append hidden_leave[0] >> 1 to new nodes_list +// pop the first nodes of hidden_nodes +// } +// } +// } +uint64_t estimate_topen(const uint32_t tau, const uint32_t kappa, uint64_t max_topen, const uint32_t* hidden_leaves_idx, + uint8_t* tmp_space) { + // CASSERT(max_topen < tree->tau * tree->kappa, "topen bug"); + uint32_t sibling_path_size = 0; + uint32_t* bstart = (uint32_t*)tmp_space; + uint32_t* bend = bstart + tau; +#ifndef NDEBUG + uint32_t num_leaves = tau * UINT64_C(1) << kappa; + uint32_t last_leave_index = num_leaves - 1; + for (uint32_t i = 0; i < tau; ++i) { + CREQUIRE(hidden_leaves_idx[i] > last_leave_index, "incorrect leave node index"); + last_leave_index = hidden_leaves_idx[i]; + } +#endif + // copy the leaf indexes in reversed order + for (uint32_t i = 0; i < tau; ++i) { + bstart[tau - i - 1] = hidden_leaves_idx[i]; + } + while (bend - bstart >= 2) { + uint32_t first_idx = *(bstart++); + uint32_t second_idx = *(bstart); + uint32_t next_idx = first_idx >> 1; + CASSERT(first_idx > 1, "bug1"); + CASSERT(*(bend - 1) > next_idx, "bug2"); + if ((first_idx ^ second_idx) == 1) { + // two hidden nodes with the same parent + ++bstart; + } else { + // single child out of at least 2 + ++sibling_path_size; + } + *(bend++) = next_idx; + } + while (*bstart != 1) { + ++sibling_path_size; + *bstart >>= 1; + } + return sibling_path_size; +} + + +struct ggm_multi_item_t { + uint16_t type : 2; + uint16_t addr : 14; +}; diff --git a/src/sig/sdith/sdith_sdith_common_avx2/ggm.h b/src/sig/sdith/sdith_sdith_common_avx2/ggm.h new file mode 100644 index 0000000000..93035a3619 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/ggm.h @@ -0,0 +1,53 @@ +#ifndef AQ_VOLE_IMPL_GGM_H +#define AQ_VOLE_IMPL_GGM_H + +// This file contains the declaration of all algebra functions over vectors and matrices over F2 + +#include "commons.h" + +typedef void GGM_SEED_RNG_LR_F(void* lr_out, const void* salt, const void* key, uint64_t node_idx, uint32_t theta); +typedef void GGM_COMMIT_RNG_F(void* out, const void* salt, const void* key, uint64_t node_idx); + +/** decode "delta" into the indexes of the hidden leaves */ +// hidden_nodes = [delta[i.kappa, (i+1).kappa) * tau + i for i in range(tau)] +// qsort hidden_leaves +EXPORT void hidden_leaves_indexes(uint64_t kappa, uint64_t tau, // dims + uint32_t* hidden_leaves, // output: node indexes + const bitvec_t* delta); // input: bits of delta +/** decode "delta" into the indexes of the hidden leaves: + * the v2 version returns node indexes instead of leave indexes */ +EXPORT void hidden_leaves_indexes2(uint64_t kappa, uint64_t tau, // dims + uint32_t* hidden_leaves, // output: node indexes + const bitvec_t* delta); // input: bits of delta + +/** estimate the number of nodes to open for this choice of delta: */ +// algorithm: +// sibling_path_indexes = [] +// new nodes_list = [] +// for (depth = tau*kappa-1 down to 0) +// while hidden_leave is not empty { +// if (hidden_leaves have >= 2 elements and hidden_leave[0] ^ hidden_leave[1] == 1) { +// append hidden_leave[0] >> 1 to new nodes_list +// pop the two first nodes of hidden_nodes +// } else { +// append hidden_leave[0] ^ 1 to sibling_path_indexes +// append hidden_leave[0] >> 1 to new nodes_list +// pop the first nodes of hidden_nodes +// } +// } +// } +EXPORT uint32_t estimate_topen_tmp_bytes( + uint32_t tau, + uint32_t kappa + ); + +EXPORT uint64_t estimate_topen( // + const uint32_t tau, + const uint32_t kappa, + uint64_t max_topen, // TODO ignored for now + const uint32_t* hidden_leaves_idx, + uint8_t* tmp_space + ); // + + +#endif // AQ_VOLE_IMPL_GGM_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/matrix_transpose_f2.c b/src/sig/sdith/sdith_sdith_common_avx2/matrix_transpose_f2.c new file mode 100644 index 0000000000..d593d8cf96 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/matrix_transpose_f2.c @@ -0,0 +1,525 @@ +#include +#include +#include +#include + +#include "vole_private.h" + +EXPORT void transpose_128_128_naive(void* out, const void* in) { + CASSERT(out != in); + typedef __uint128_t T; + const T* x = (T*)in; + T* r = (T*)out; + for (uint64_t i = 0; i < 128; ++i) { + __uint128_t oi = 0; + for (uint64_t j = 0; j < 128; ++j) { + oi |= ((x[j] >> i) & 1) << j; + } + r[i] = oi; + } +} + +EXPORT void transpose_192_192_naive(void* out, const void* in) { + CASSERT(out != in); + const uint64_t* x = (uint64_t*)in; + uint64_t *r = out; + for (uint64_t i = 0; i < 192; ++i) { + uint64_t tmp[3] = {0}; + for (uint64_t j = 0; j < 192; ++j) { + tmp[j/64] |= ((x[j*3 + i/64] >> (i%64)) & 1) << (j%64); + } + for (uint64_t j = 0; j < 3; ++j) + { + r[i*3 + j] = tmp[j]; + } + } +} + +EXPORT void transpose_256_256_naive(void* out, const void* in) { + CASSERT(out != in); + const uint64_t* x = (uint64_t*)in; + uint64_t *r = out; + for (uint64_t i = 0; i < 256; ++i) { + uint64_t tmp[4] = {0}; + for (uint64_t j = 0; j < 256; ++j) { + tmp[j/64] |= ((x[j*4 + i/64] >> (i%64)) & 1) << (j%64); + } + for (uint64_t j = 0; j < 4; ++j) + { + r[i*4 + j] = tmp[j]; + } + } +} + +SDITH_ALWAYS_INLINE void transpose8(uint8_t *a, uint64_t stride) { + int j, k; + uint64_t m, t; + m = 0x0F; + for (j = 4; j != 0; j = j >> 1, m = m ^ (m << j)) { + for (k = 0; k < 8; k = (k + j + 1) & ~j) { + t = (a[(k + j)*stride] ^ (a[k*stride] >> j)) & m; + a[(k + j)*stride] = a[(k + j)*stride] ^ t; + a[k*stride] = a[k*stride] ^ (t << j); + } + } +} + +SDITH_ALWAYS_INLINE void transpose64(uint64_t *a, uint64_t stride) { + int j, k; + uint64_t m, t; + m = 0x00000000FFFFFFFFULL; + for (j = 32; j != 0; j = j >> 1, m = m ^ (m << j)) { + for (k = 0; k < 64; k = (k + j + 1) & ~j) { + t = (a[(k + j)*stride] ^ (a[k*stride] >> j)) & m; + a[(k + j)*stride] = a[(k + j)*stride] ^ t; + a[k*stride] = a[k*stride] ^ (t << j); + } + } +} + +/* Not called anywhere in the current build; kept as a utility. */ +SDITH_MAYBE_UNUSED SDITH_ALWAYS_INLINE void transpose64_unaligned(uint8_t *a, uint64_t byte_stride) +{ + uint64_t tmp[64]; + for (size_t i = 0; i < 64; i++) + { + tmp[i] = *((uint64_t*)&a[i*byte_stride]); + } + transpose64(tmp, 1); + for (size_t i = 0; i < 64; i++) + { + *((uint64_t*)&a[i*byte_stride]) = tmp[i]; + } +} + +SDITH_ALWAYS_INLINE void transpose128(__uint128_t *a, uint64_t stride) { + int j, k; + __uint128_t m, t; + m = 1; + m <<= 64; + m -= 1; + for (j = 64; j != 0; j = j >> 1, m = m ^ (m << j)) { + for (k = 0; k < 128; k = (k + j + 1) & ~j) { + t = (a[(k + j)*stride] ^ (a[k*stride] >> j)) & m; + a[(k + j)*stride] = a[(k + j)*stride] ^ t; + a[k*stride] = a[k*stride] ^ (t << j); + } + } +} + +EXPORT void transpose_128_128_ref(void* x) { + transpose128((__uint128_t*)x, 1); + + // legacy code: + //uint64_t *x64 = x; + //// split into 4 submatrices: + //// A B + //// C D + //// A starts at x64[0] + //// B starts at x64[1] + //// C starts at x64[128] + //// D starts at x64[129] + //transpose64(&x64[0], 2); + //transpose64(&x64[1], 2); + //transpose64(&x64[128], 2); + //transpose64(&x64[129], 2); + // + //// swap submatrix B and C + //for (uint64_t i = 0; i < 64; i++) + //{ + // x64[2*i+ 1] ^= x64[2*i+128]; + // x64[2*i+128] ^= x64[2*i+ 1]; + // x64[2*i+ 1] ^= x64[2*i+128]; + //} +} + +EXPORT void transpose_192_192_ref(void* x) { + uint64_t *x64 = x; + // split into 9 submatrices: + // A B C + // D E F + // G H I + uint64_t *A = &x64[0]; + uint64_t *B = &x64[1]; + uint64_t *C = &x64[2]; + uint64_t *D = &x64[192]; + uint64_t *E = &x64[193]; + uint64_t *F = &x64[194]; + uint64_t *G = &x64[384]; + uint64_t *H = &x64[385]; + uint64_t *I = &x64[386]; + + transpose64(A, 3); + transpose64(B, 3); + transpose64(C, 3); + transpose64(D, 3); + transpose64(E, 3); + transpose64(F, 3); + transpose64(G, 3); + transpose64(H, 3); + transpose64(I, 3); + + // swap C and G + for (uint64_t i = 0; i < 64; i++) + { + C[3*i] ^= G[3*i]; + G[3*i] ^= C[3*i]; + C[3*i] ^= G[3*i]; + } + // swap B and D + for (uint64_t i = 0; i < 64; i++) + { + B[3*i] ^= D[3*i]; + D[3*i] ^= B[3*i]; + B[3*i] ^= D[3*i]; + } + // swap F and H + for (uint64_t i = 0; i < 64; i++) + { + F[3*i] ^= H[3*i]; + H[3*i] ^= F[3*i]; + F[3*i] ^= H[3*i]; + } +} + +EXPORT void transpose_256_256_ref(void* x) { + __uint128_t *x128 = x; + // split into 4 submatrices: + // A B + // C D + __uint128_t *A = &x128[0]; + __uint128_t *B = &x128[1]; + __uint128_t *C = &x128[256]; + __uint128_t *D = &x128[257]; + + transpose128(A, 2); + transpose128(B, 2); + transpose128(C, 2); + transpose128(D, 2); + + // swap submatrix B and C + for (uint64_t i = 0; i < 128; i++) + { + B[2*i] ^= C[2*i]; + C[2*i] ^= B[2*i]; + B[2*i] ^= C[2*i]; + } +} + +EXPORT void transpose_128_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: lambda elements of Lbyte bytes + * Output order: Lbyte*8 elements of lambda bits + */ + const uint64_t Lbyte = L/8; + CREQUIRE(Lslice >= Lbyte, "Lslice must be larger than L/8"); + const uint8_t* x = (uint8_t*)in; + // x[0..Lbyte-1] hold the first row + // x[Lbyte..2Lbyte-1] the second and so on, until + // x[127Lbyte..128Lbyte-1] hold the last row + uint8_t *r = out; + // r[0..15] hold the first output row + // r[16..31] hold the second output row and so on, until + // r[(L-1)*16..L*16-1] hold the last output row + for (uint64_t i = 0; i < 128*Lbyte; i++) + { + r[i] = 0; + } + for (uint64_t i = 0; i < L; ++i) + { + for (uint64_t j = 0; j < 128; ++j) + { + // get the i-th bit in the j-th input row + uint8_t tmp = (x[j*Lslice+i/8] >> (i%8)) & 1; + // store it to the j-th output bit of the i-th output row + r[i*16+j/8] |= tmp << (j%8); + } + } +} + +EXPORT void transpose_128_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 128 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 128 bits + */ + const uint64_t Lbyte = L/8; + CASSERT(Lslice >= Lbyte, "Lslice must be larger than L/8"); + uint64_t* o64 = (uint64_t*)out; + + if ((L%128) == 0) + { + uint64_t* x64 = (uint64_t*)in; + + // x64[0..Lbyte/8-1] hold the first row + // x64[Lbyte/8..2Lbyte/8-1] the second and so on, until + // x64[127Lbyte/8..128Lbyte/8-1] hold the last row + // x64[0..1] hold the first output row + // x64[2..3] hold the second output row and so on, until + // x64[(L-1)*2..L*2-1] hold the last output row + + // we split the whole matrix into Lbyte/16 sub-matrices (128x128 bit) + for (size_t i = 0; i < Lbyte/16; i++) + { + // first copy into out + for (size_t j = 0; j < 64*4; j++) + { + o64[j + i*64*4] = x64[(j%2) + (j/2)*Lslice/8 + i*2]; + } + transpose_128_128_ref(&o64[i*64*4]); + } + + } else { + + uint8_t* x8 = (uint8_t*)in; + uint8_t* o8 = (uint8_t*)out; + // x8[0..Lbyte-1] hold the first row + // x8[Lbyte..2Lbyte-1] the second and so on, until + // x8[127Lbyte..128Lbyte-1] hold the last row + // o8[0..15] hold the first output row + // o8[16..31] hold the second output row and so on, until + // o8[(L-1)*16..L*16-1] hold the last output row + + for (size_t i = 0; i < Lbyte/16; i++) + { + // copy 128x128 submatrix to output + for (size_t j = 0; j < 128*128/8; j++) + { + o8[j + i*128*16] = x8[(j%16) + (j/16)*Lslice + i*16]; + } + transpose_128_128_ref(&o64[i*64*4]); + } + + // now transpose the remainder bytes byte-wise + for (size_t i = (Lbyte/16)*16; i < Lbyte; i++) + { + for (size_t j = 0; j < 128/8; j++) + { + // copy this 8x8 matrix to its destination, then transpose + for (size_t k = 0; k < 8; k++) + { + o8[16*8*i + 16*k + j] = x8[i + Lslice*8*j + Lslice*k]; + } + transpose8(&o8[16*8*i + j], 16); + } + } + + } +} + +EXPORT void transpose_192_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 192 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 192 bits + */ + const uint64_t Lbyte = L/8; + CREQUIRE(Lslice >= Lbyte, "Lslice must be larger than L/8"); + const uint8_t* x = (uint8_t*)in; + // x[0..Lbyte-1] hold the first row + // x[Lbyte..2Lbyte-1] the second and so on, until + // x[191Lbyte..192Lbyte-1] hold the last row + uint8_t *r = out; + // r[0..23] hold the first output row + // r[24..47] hold the second output row and so on, until + // r[(L-1)*24..L*24-1] hold the last output row + for (uint64_t i = 0; i < 192*Lbyte; i++) + { + r[i] = 0; + } + for (uint64_t i = 0; i < L; ++i) + { + for (uint64_t j = 0; j < 192; ++j) + { + // get the i-th bit in the j-th input row + uint8_t tmp = (x[j*Lslice+i/8] >> (i%8)) & 1; + // store it to the j-th output bit of the i-th output row + r[i*24+j/8] |= tmp << (j%8); + } + } +} + +EXPORT void transpose_192_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 192 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 192 bits + */ + const uint64_t Lbyte = L/8; + CASSERT(Lslice >= Lbyte, "Lslice must be larger than L/8"); + uint64_t* o64 = (uint64_t*)out; + + if ((L%192) == 0) + { + uint64_t* x64 = (uint64_t*)in; + + // x64[0..Lbyte/8-1] hold the first row + // x64[Lbyte/8..2Lbyte/8-1] the second and so on, until + // x64[191Lbyte/8..192Lbyte/8-1] hold the last row + // x64[0..1] hold the first output row + // x64[2..3] hold the second output row and so on, until + // x64[(L-1)*2..L*2-1] hold the last output row + + // we split the whole matrix into Lbyte/24 sub-matrices (192x192 bit) + for (size_t i = 0; i < Lbyte/24; i++) + { + // first copy into out + for (size_t j = 0; j < 64*9; j++) + { + o64[j + i*64*9] = x64[(j%3) + (j/3)*Lslice/8 + i*3]; + } + transpose_192_192_ref(&o64[i*64*9]); + } + + } else { + + uint8_t* x8 = (uint8_t*)in; + uint8_t* o8 = (uint8_t*)out; + // x8[0..Lbyte-1] hold the first row + // x8[Lbyte..2Lbyte-1] the second and so on, until + // x8[191Lbyte..192Lbyte-1] hold the last row + // o8[0..15] hold the first output row + // o8[16..31] hold the second output row and so on, until + // o8[(L-1)*16..L*16-1] hold the last output row + + for (size_t i = 0; i < Lbyte/24; i++) + { + // copy 192x192 submatrix to output + for (size_t j = 0; j < 192*192/8; j++) + { + o8[j + i*192*24] = x8[(j%24) + (j/24)*Lslice + i*24]; + } + transpose_192_192_ref(&o64[i*64*9]); + } + + // now transpose the remainder bytes byte-wise + for (size_t i = (Lbyte/24)*24; i < Lbyte; i++) + { + for (size_t j = 0; j < 192/8; j++) + { + // copy this 8x8 matrix to its destination, then transpose + for (size_t k = 0; k < 8; k++) + { + o8[24*8*i + 24*k + j] = x8[i + Lslice*8*j + Lslice*k]; + } + transpose8(&o8[24*8*i + j], 24); + } + } + + } +} + +EXPORT void transpose_256_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: lambda elements of Lbyte bytes + * Output order: Lbyte*8 elements of lambda bits + */ + const uint64_t Lbyte = L/8; + CREQUIRE(Lslice >= Lbyte, "Lslice must be larger than L/8"); + const uint8_t* x = (uint8_t*)in; + // x[0..Lbyte-1] hold the first row + // x[Lbyte..2Lbyte-1] the second and so on, until + // x[255Lbyte..256Lbyte-1] hold the last row + uint8_t *r = out; + // r[0..31] hold the first output row + // r[32..64] hold the second output row and so on, until + // r[(L-1)*32..L*32-1] hold the last output row + for (uint64_t i = 0; i < 256*Lbyte; i++) + { + r[i] = 0; + } + for (uint64_t i = 0; i < L; ++i) + { + for (uint64_t j = 0; j < 256; ++j) + { + // get the i-th bit in the j-th input row + uint8_t tmp = (x[j*Lslice+i/8] >> (i%8)) & 1; + // store it to the j-th output bit of the i-th output row + r[i*32+j/8] |= tmp << (j%8); + } + } +} + +EXPORT void transpose_256_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice) +{ + CASSERT(out != in); + CREQUIRE((L & 7) == 0, "L must be a multiple of 8"); + /* + * Input order: 256 elements of Lbyte bytes + * Output order: Lbyte*8 elements of 256 bits + */ + const uint64_t Lbyte = L/8; + CASSERT(Lslice >= Lbyte, "Lslice must be larger than L/8"); + uint64_t* o64 = (uint64_t*)out; + + if ((L%256) == 0) + { + uint64_t* x64 = (uint64_t*)in; + + // x64[0..Lbyte/8-1] hold the first row + // x64[Lbyte/8..2Lbyte/8-1] the second and so on, until + // x64[255Lbyte/8..256Lbyte/8-1] hold the last row + // x64[0..1] hold the first output row + // x64[2..3] hold the second output row and so on, until + // x64[(L-1)*2..L*2-1] hold the last output row + + // we split the whole matrix into Lbyte/32 sub-matrices (256x256 bit) + for (size_t i = 0; i < Lbyte/32; i++) + { + // first copy into out + for (size_t j = 0; j < 64*16; j++) + { + o64[j + i*64*16] = x64[(j%4) + (j/4)*Lslice/8 + i*4]; + } + transpose_256_256_ref(&o64[i*64*16]); + } + + } else { + + uint8_t* x8 = (uint8_t*)in; + uint8_t* o8 = (uint8_t*)out; + // x8[0..Lbyte-1] hold the first row + // x8[Lbyte..2Lbyte-1] the second and so on, until + // x8[255Lbyte..256Lbyte-1] hold the last row + // o8[0..15] hold the first output row + // o8[16..31] hold the second output row and so on, until + // o8[(L-1)*16..L*16-1] hold the last output row + + for (size_t i = 0; i < Lbyte/32; i++) + { + // copy 256x256 submatrix to output + for (size_t j = 0; j < 256*256/8; j++) + { + o8[j + i*256*32] = x8[(j%32) + (j/32)*Lslice + i*32]; + } + transpose_256_256_ref(&o64[i*64*16]); + } + + // now transpose the remainder bytes byte-wise + for (size_t i = (Lbyte/32)*32; i < Lbyte; i++) + { + for (size_t j = 0; j < 256/8; j++) + { + // copy this 8x8 matrix to its destination, then transpose + for (size_t k = 0; k < 8; k++) + { + o8[32*8*i + 32*k + j] = x8[i + Lslice*8*j + Lslice*k]; + } + transpose8(&o8[32*8*i + j], 32); + } + } + + } +} \ No newline at end of file diff --git a/src/sig/sdith/sdith_sdith_common_avx2/matrix_vector_products_f2.c b/src/sig/sdith/sdith_sdith_common_avx2/matrix_vector_products_f2.c new file mode 100755 index 0000000000..ee9f5d5a34 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/matrix_vector_products_f2.c @@ -0,0 +1,95 @@ +#include + +#include "vole_private.h" + +// A helper to set a single bit in a bit vector (XOR it with 'value'): +static inline void bitvec_value_xor_to(bitvec_t* v, uint64_t index, uint8_t value) { + const uint64_t byte_pos = index / 8; + const uint64_t bit_pos = index % 8; + ((uint8_t*)v)[byte_pos] ^= (uint8_t)(value << bit_pos); +} + +// Get a bit from a bit vector +static inline uint8_t bitvec_get_value(const bitvec_t* v, uint64_t idx) { + const uint8_t* vec = (uint8_t*)v; + return ( (vec[idx/8] >> (idx%8)) & 1 ); +} + +SDITH_ALWAYS_INLINE void bitvec_xor_inline_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, + const bitvec_t* b) { + uint8_t* r = (uint8_t*)res; + const uint8_t* aa = (uint8_t*)a; + const uint8_t* bb = (uint8_t*)b; + for (uint64_t i = 0; i < bytelen; ++i) { + r[i] = aa[i] ^ bb[i]; + } +} + +EXPORT void bitvec_xor_to_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* b) { + bitvec_xor_inline_ref(bytelen, res, res, b); +} + +EXPORT void bitvec_xor_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b) { + bitvec_xor_inline_ref(bytelen, res, a, b); +} + +// b^=a then c^=b +EXPORT void bitvec_cascade_xor_to_ref(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a) { + bitvec_xor_inline_ref(bytelen, b, b, a); + bitvec_xor_inline_ref(bytelen, c, c, b); +} + + +uint8_t bitmat_get_value(const bitmat_t* v, uint64_t ncols, uint64_t row, uint64_t col) { + return bitvec_get_value(v, (row * ncols + col)); +} + +EXPORT void matrix_vector_product_f2_ref( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b) // bit vector of size ncols +{ + memset(res, 0, (nrows+7)/8); + for (uint64_t i=0; i> 3; + // Clear the result + memset(res, 0, nrows * lambda_bytes); + + // For each row i + for (uint64_t i = 0; i < nrows; i++) { + // Pointer to the result block for row i + uint8_t* r_i = res + i * lambda_bytes; + + for (uint64_t j = 0; j < ncols; j++) { + // Extract bit A[i,j] + uint64_t bit_index = i*ncols + j; + uint8_t a_ij = (amat[bit_index/8] >> (bit_index%8)) & 1; + + if (a_ij) { + // If a_ij is 1, XOR the block B[j] into r_i + const uint8_t* b_j = bvec + j * lambda_bytes; + for (int x = 0; x < lambda_bytes; x++) { + r_i[x] ^= b_j[x]; + } + } + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/matrix_vector_products_f2_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/matrix_vector_products_f2_avx2.c new file mode 100755 index 0000000000..3aab79f3c5 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/matrix_vector_products_f2_avx2.c @@ -0,0 +1,490 @@ +#include +#include + +#include "vole_private.h" + +EXPORT void bitvec_xor_to_avx2(uint64_t bytelen, bitvec_t* res, const bitvec_t* b) { + uint8_t* r = (uint8_t*)res; + const uint8_t* bb = (uint8_t*)b; + uint64_t i = 0; + for (; i + 32 <= bytelen; i += 32) { + __m256i rv = _mm256_loadu_si256((const __m256i*)(r + i)); + __m256i bv = _mm256_loadu_si256((const __m256i*)(bb + i)); + _mm256_storeu_si256((__m256i*)(r + i), _mm256_xor_si256(rv, bv)); + } + for (; i < bytelen; i++) { + r[i] ^= bb[i]; + } +} + +EXPORT void bitvec_xor_avx2(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b) { + uint8_t* r = (uint8_t*)res; + const uint8_t* aa = (uint8_t*)a; + const uint8_t* bb = (uint8_t*)b; + uint64_t i = 0; + for (; i + 32 <= bytelen; i += 32) { + __m256i av = _mm256_loadu_si256((const __m256i*)(aa + i)); + __m256i bv = _mm256_loadu_si256((const __m256i*)(bb + i)); + _mm256_storeu_si256((__m256i*)(r + i), _mm256_xor_si256(av, bv)); + } + for (; i < bytelen; i++) { + r[i] = aa[i] ^ bb[i]; + } +} + +// there is a missing builtin in gcc < 10. +// clang also defines __GNUC__ (as 4) but ships the real intrinsic, so exclude it — +// otherwise this redefines clang's builtin and the whole tree fails to compile under clang. +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ < 10 +__m256i _mm256_zextsi128_si256 (__m128i x) +{ + return __extension__ (__m256i) { x[0], x[1], 0, 0 }; +} +#endif +#endif + + +// Compute parity of a 64-bit value +static inline uint8_t parity64(uint64_t x) { + x ^= x >> 32; + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + return (uint8_t)((0x6996 >> (x & 0xF)) & 1); +} + +// Reduce a __m256i to a 64-bit XOR of all its bits +static inline uint64_t avx2_reduce_to_64(__m256i x) { + __m128i x128 = _mm_xor_si128(_mm256_castsi256_si128(x), + _mm256_extracti128_si256(x, 1)); + x128 = _mm_xor_si128(x128, _mm_srli_si128(x128, 8)); + uint64_t val64 = (uint64_t)_mm_cvtsi128_si64(x128); + return val64; +} + +// Reduce a __m128i to a 64-bit XOR of all its bits +static inline uint64_t sse2_reduce_to_64(__m128i x) { + x = _mm_xor_si128(x, _mm_srli_si128(x, 8)); + uint64_t val64 = (uint64_t)_mm_cvtsi128_si64(x); + return val64; +} + + +EXPORT void matrix_vector_product_f2_avx2( + uint64_t nrows, uint64_t ncols, + bitvec_t* res, + const bitmat_t* a, + const bitvec_t* b) +{ + memset(res, 0, (nrows+7) >> 3); + + uint64_t n_256 = ncols >> 8; + uint64_t r = ncols & 0xFF; + + uint64_t n_128 = r >> 7; + r &= 0x7F; + + uint64_t n_64 = r >> 6; + r &= 0x3F; + + uint64_t n_32 = r >> 5; + r &= 0x1F; + + uint64_t n_8 = r >> 3; // remainder in bytes + + for (uint64_t i = 0; i < nrows; i++) { + uint64_t accum = 0ULL; // accumulate XOR of all bits + + uint64_t row_offset = i * ncols; + + // 1. Process 256-bit blocks with AVX2 + if (n_256 > 0) { + __m256i avx_accum = _mm256_setzero_si256(); + for (uint64_t c = 0; c < n_256; c++) { + uint64_t bitpos = row_offset + (c << 8); + const uint8_t* A_ptr = a + (bitpos >> 3); + const uint8_t* B_ptr = b + c*32; + + __m256i A_vec = _mm256_loadu_si256((const __m256i*)A_ptr); + __m256i B_vec = _mm256_loadu_si256((const __m256i*)B_ptr); + __m256i and_vec = _mm256_and_si256(A_vec, B_vec); + avx_accum = _mm256_xor_si256(avx_accum, and_vec); + } + accum ^= avx2_reduce_to_64(avx_accum); + } + + uint64_t used_bits = n_256 << 8; + uint64_t offset_after_256 = row_offset + used_bits; + + // 2. Process 128-bit blocks with SSE2 + if (n_128 > 0) { + __m128i sse_accum = _mm_setzero_si128(); + for (uint64_t c = 0; c < n_128; c++) { + uint64_t bitpos = offset_after_256 + (c << 7); + const uint8_t* A_ptr = a + (bitpos >> 3); + const uint8_t* B_ptr = b + (used_bits >> 3) + (c << 4); + + __m128i A_vec = _mm_loadu_si128((const __m128i*)A_ptr); + __m128i B_vec = _mm_loadu_si128((const __m128i*)B_ptr); + __m128i and_vec = _mm_and_si128(A_vec, B_vec); + sse_accum = _mm_xor_si128(sse_accum, and_vec); + } + accum ^= sse2_reduce_to_64(sse_accum); + } + + used_bits += n_128 << 7; + uint64_t offset_after_128 = row_offset + used_bits; + + // 3. Process 64-bit blocks + for (uint64_t c = 0; c < n_64; c++) { + uint64_t bitpos = offset_after_128 + (c << 6); + const uint8_t* A_ptr = a + (bitpos >> 3); + const uint8_t* B_ptr = b + (used_bits >> 3) + (c << 3); + + uint64_t A_val = *(const uint64_t*)A_ptr; + uint64_t B_val = *(const uint64_t*)B_ptr; + accum ^= (A_val & B_val); + } + + used_bits += n_64 << 6; + uint64_t offset_after_64 = row_offset + used_bits; + + // 4. Process 32-bit blocks + for (uint64_t c = 0; c < n_32; c++) { + uint64_t bitpos = offset_after_64 + (c << 5); + const uint8_t* A_ptr = a + (bitpos >> 3); + const uint8_t* B_ptr = b + (used_bits >> 3) + (c << 2); + + uint32_t A_val = *(const uint32_t*)A_ptr; + uint32_t B_val = *(const uint32_t*)B_ptr; + uint32_t and_val = A_val & B_val; + accum ^= (uint64_t)and_val; + } + + used_bits += n_32 << 5; + uint64_t offset_after_32 = row_offset + used_bits; + + // 5. Process 8-bit blocks + for (uint64_t c = 0; c < n_8; c++) { + uint64_t bitpos = offset_after_32 + (c << 3); + const uint8_t* A_ptr = a + (bitpos >> 3); + const uint8_t* B_ptr = b + (used_bits >> 3) + c; + + uint8_t A_val = *A_ptr; + uint8_t B_val = *B_ptr; + accum ^= (A_val & B_val); + } + + // Compute parity of accum + uint8_t parity = parity64(accum); + + // Set bit i of res to parity (branchless). + ((uint8_t*)res)[i >> 3] ^= (uint8_t)(parity << (i & 7)); + } +} + + + + + + +// Number of A rows processed together by the lambda=128 kernel. Each B[j] block is +// loaded once per row-group instead of once per row, cutting redundant B reads ~R x. +// Must be even (rows are packed 2-per-__m256i). Tuned by benchmark. +#define MVP128_BLOCK_ROWS 4 + +// Specialized function for lambda=128 bits (16 bytes). +// +// Computes res = A * B over F2: res[i] (128 bits) = XOR of B[j] (128 bits) over all +// columns j where A[i][j] == 1. +// +// Strategy: process MVP128_BLOCK_ROWS rows of A at a time, keeping their result +// accumulators live in registers while sweeping the columns once. Each B[j] is loaded +// a single time for the whole row-group and XORed (branchlessly, via an all-ones / +// all-zeros mask built from the A bit) into every accumulator whose row selects it. +// Two rows share one __m256i accumulator (one 128-bit lane each), so B[j] is broadcast +// to both lanes and full AVX2 width is used. +// +// Assumes ncols is a multiple of 8 (guaranteed by the consistency-check callers), so A +// rows are byte aligned and there are no leftover bits. +static void matrix_vector_product_f2_block_128( + uint64_t nrows, + uint64_t ncols, + uint8_t* res, + const uint8_t* A, + const uint8_t* B +) { + const uint64_t lambda = 16; + memset(res, 0, nrows * lambda); + + const uint64_t full_bytes = ncols / 8; // ncols is a multiple of 8 + const uint64_t row_bytes = full_bytes; + const int R = MVP128_BLOCK_ROWS; + + uint64_t i = 0; + for (; i + (uint64_t)R <= nrows; i += R) { + __m256i acc[MVP128_BLOCK_ROWS / 2]; + for (int p = 0; p < R / 2; p++) acc[p] = _mm256_setzero_si256(); + + const uint8_t* A_rows[MVP128_BLOCK_ROWS]; + for (int r = 0; r < R; r++) A_rows[r] = A + (i + r) * row_bytes; + + for (uint64_t byte_i = 0; byte_i < full_bytes; byte_i++) { + uint8_t a_byte[MVP128_BLOCK_ROWS]; + for (int r = 0; r < R; r++) a_byte[r] = A_rows[r][byte_i]; + + for (int bit = 0; bit < 8; bit++) { + const uint8_t* b_j = B + (byte_i * 8 + bit) * lambda; + __m128i bj = _mm_loadu_si128((const __m128i*)b_j); + __m256i bcast = _mm256_broadcastsi128_si256(bj); // [B[j], B[j]] + + for (int p = 0; p < R / 2; p++) { + // Lane 0 -> row (i+2p), lane 1 -> row (i+2p+1); mask is all-ones + // when the corresponding A bit is set, all-zeros otherwise. + int64_t m0 = -(int64_t)((a_byte[2 * p] >> bit) & 1); + int64_t m1 = -(int64_t)((a_byte[2 * p + 1] >> bit) & 1); + __m256i mask = _mm256_set_epi64x(m1, m1, m0, m0); + acc[p] = _mm256_xor_si256(acc[p], _mm256_and_si256(bcast, mask)); + } + } + } + + for (int p = 0; p < R / 2; p++) { + __m128i lo = _mm256_castsi256_si128(acc[p]); + __m128i hi = _mm256_extracti128_si256(acc[p], 1); + _mm_storeu_si128((__m128i*)(res + (i + 2 * p) * lambda), lo); + _mm_storeu_si128((__m128i*)(res + (i + 2 * p + 1) * lambda), hi); + } + } + + // Tail: fewer than R rows left. Handle one row at a time. + for (; i < nrows; i++) { + __m256i acc = _mm256_setzero_si256(); + const uint8_t* A_row = A + i * row_bytes; + for (uint64_t byte_i = 0; byte_i < full_bytes; byte_i++) { + uint8_t a = A_row[byte_i]; + while (a) { + int bit = __builtin_ctz(a); + a &= (uint8_t)(a - 1); + const uint8_t* b_j = B + (byte_i * 8 + bit) * lambda; + __m128i bj = _mm_loadu_si128((const __m128i*)b_j); + acc = _mm256_xor_si256(acc, _mm256_zextsi128_si256(bj)); + } + } + _mm_storeu_si128((__m128i*)(res + i * lambda), _mm256_castsi256_si128(acc)); + } +} + + +// Number of A rows processed together by the lambda=192 kernel (see block_128 for the +// rationale). A 192-bit row occupies 24 of the 32 bytes of a __m256i, so each row gets +// its own full-width accumulator (no 2-rows-per-lane packing). +#define MVP192_BLOCK_ROWS 8 + +// Specialized function for lambda=192 bits (24 bytes). Same row-blocked, branchless +// strategy as matrix_vector_product_f2_block_128: process MVP192_BLOCK_ROWS rows at a +// time so each B[j] block is loaded once per row-group and XORed (via an all-ones / +// all-zeros mask) into the accumulator of every selecting row. +// +// Each 24-byte B[j] is assembled from a 16-byte and an 8-byte load (never a 32-byte +// load) so the final block does not read past the end of B; the high 8 bytes of the +// __m256i stay zero, so the unused top of every accumulator remains zero and only 24 +// bytes are stored per row. +// +// Assumes ncols is a multiple of 8 (guaranteed by the consistency-check callers). +static void matrix_vector_product_f2_block_192( + uint64_t nrows, + uint64_t ncols, + uint8_t* res, + const uint8_t* A, + const uint8_t* B +) { + const uint64_t lambda = 24; + memset(res, 0, nrows * lambda); + + const uint64_t full_bytes = ncols / 8; // ncols is a multiple of 8 + const uint64_t row_bytes = full_bytes; + const int R = MVP192_BLOCK_ROWS; + + uint64_t i = 0; + for (; i + (uint64_t)R <= nrows; i += R) { + __m256i acc[MVP192_BLOCK_ROWS]; + for (int r = 0; r < R; r++) acc[r] = _mm256_setzero_si256(); + + const uint8_t* A_rows[MVP192_BLOCK_ROWS]; + for (int r = 0; r < R; r++) A_rows[r] = A + (i + r) * row_bytes; + + for (uint64_t byte_i = 0; byte_i < full_bytes; byte_i++) { + uint8_t a_byte[MVP192_BLOCK_ROWS]; + for (int r = 0; r < R; r++) a_byte[r] = A_rows[r][byte_i]; + + for (int bit = 0; bit < 8; bit++) { + const uint8_t* b_j = B + (byte_i * 8 + bit) * lambda; + __m128i lo = _mm_loadu_si128((const __m128i*)b_j); // bytes 0..15 + __m128i hi = _mm_loadl_epi64((const __m128i*)(b_j + 16)); // bytes 16..23 + __m256i bj = _mm256_inserti128_si256(_mm256_castsi128_si256(lo), hi, 1); + + for (int r = 0; r < R; r++) { + __m256i mask = _mm256_set1_epi32(-(int32_t)((a_byte[r] >> bit) & 1)); + acc[r] = _mm256_xor_si256(acc[r], _mm256_and_si256(bj, mask)); + } + } + } + + for (int r = 0; r < R; r++) { + uint8_t* r_i = res + (i + r) * lambda; + _mm_storeu_si128((__m128i*)r_i, _mm256_castsi256_si128(acc[r])); + _mm_storel_epi64((__m128i*)(r_i + 16), _mm256_extracti128_si256(acc[r], 1)); + } + } + + // Tail: fewer than R rows left. Handle one row at a time. + for (; i < nrows; i++) { + __m256i acc = _mm256_setzero_si256(); + const uint8_t* A_row = A + i * row_bytes; + for (uint64_t byte_i = 0; byte_i < full_bytes; byte_i++) { + uint8_t a = A_row[byte_i]; + while (a) { + int bit = __builtin_ctz(a); + a &= (uint8_t)(a - 1); + const uint8_t* b_j = B + (byte_i * 8 + bit) * lambda; + __m128i lo = _mm_loadu_si128((const __m128i*)b_j); + __m128i hi = _mm_loadl_epi64((const __m128i*)(b_j + 16)); + __m256i bj = _mm256_inserti128_si256(_mm256_castsi128_si256(lo), hi, 1); + acc = _mm256_xor_si256(acc, bj); + } + } + uint8_t* r_i = res + i * lambda; + _mm_storeu_si128((__m128i*)r_i, _mm256_castsi256_si128(acc)); + _mm_storel_epi64((__m128i*)(r_i + 16), _mm256_extracti128_si256(acc, 1)); + } +} + + +// Number of A rows processed together by the lambda=256 kernel (see block_128 for the +// rationale). A 256-bit row is exactly one __m256i, so each row gets its own accumulator. +#define MVP256_BLOCK_ROWS 12 + +// Specialized function for lambda=256 bits (32 bytes). Same row-blocked, branchless +// strategy as matrix_vector_product_f2_block_128: process MVP256_BLOCK_ROWS rows at a +// time so each B[j] block is loaded once per row-group and XORed (via an all-ones / +// all-zeros mask) into the accumulator of every selecting row. +// +// Assumes ncols is a multiple of 8 (guaranteed by the consistency-check callers). +static void matrix_vector_product_f2_block_256( + uint64_t nrows, + uint64_t ncols, + uint8_t* res, + const uint8_t* A, + const uint8_t* B +) { + const uint64_t lambda = 32; + memset(res, 0, nrows * lambda); + + const uint64_t full_bytes = ncols / 8; // ncols is a multiple of 8 + const uint64_t row_bytes = full_bytes; + const int R = MVP256_BLOCK_ROWS; + + uint64_t i = 0; + for (; i + (uint64_t)R <= nrows; i += R) { + __m256i acc[MVP256_BLOCK_ROWS]; + for (int r = 0; r < R; r++) acc[r] = _mm256_setzero_si256(); + + const uint8_t* A_rows[MVP256_BLOCK_ROWS]; + for (int r = 0; r < R; r++) A_rows[r] = A + (i + r) * row_bytes; + + for (uint64_t byte_i = 0; byte_i < full_bytes; byte_i++) { + uint8_t a_byte[MVP256_BLOCK_ROWS]; + for (int r = 0; r < R; r++) a_byte[r] = A_rows[r][byte_i]; + + for (int bit = 0; bit < 8; bit++) { + const uint8_t* b_j = B + (byte_i * 8 + bit) * lambda; + __m256i bj = _mm256_loadu_si256((const __m256i*)b_j); + + for (int r = 0; r < R; r++) { + __m256i mask = _mm256_set1_epi32(-(int32_t)((a_byte[r] >> bit) & 1)); + acc[r] = _mm256_xor_si256(acc[r], _mm256_and_si256(bj, mask)); + } + } + } + + for (int r = 0; r < R; r++) { + _mm256_storeu_si256((__m256i*)(res + (i + r) * lambda), acc[r]); + } + } + + // Tail: fewer than R rows left. Handle one row at a time. + for (; i < nrows; i++) { + __m256i acc = _mm256_setzero_si256(); + const uint8_t* A_row = A + i * row_bytes; + for (uint64_t byte_i = 0; byte_i < full_bytes; byte_i++) { + uint8_t a = A_row[byte_i]; + while (a) { + int bit = __builtin_ctz(a); + a &= (uint8_t)(a - 1); + const uint8_t* b_j = B + (byte_i * 8 + bit) * lambda; + acc = _mm256_xor_si256(acc, _mm256_loadu_si256((const __m256i*)b_j)); + } + } + _mm256_storeu_si256((__m256i*)(res + i * lambda), acc); + } +} + +// Dispatcher function +void matrix_f2_times_vector_flambda_avx2( + uint64_t lambda_bits, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b +) { + uint64_t lambda = (uint64_t)lambda_bits >> 3; // bytes + switch (lambda) { + case 16: + matrix_vector_product_f2_block_128(nrows, ncols, res, a, b); + break; + case 24: + matrix_vector_product_f2_block_192(nrows, ncols, res, a, b); + break; + case 32: + matrix_vector_product_f2_block_256(nrows, ncols, res, a, b); + break; + default: + fprintf(stderr, "Unsupported lambda size\n"); + break; + } +} + +EXPORT void bitvec_cascade_xor_to_avx2(uint64_t bytelen, void* c, void* b, const void* a) { + const uint8_t* ap = (const uint8_t*)a; + uint8_t* bp = (uint8_t*)b; + uint8_t* cp = (uint8_t*)c; + uint64_t i = 0; + for (; i + 32 <= bytelen; i += 32) { + __m256i va = _mm256_loadu_si256((const __m256i*)(ap + i)); + __m256i vb = _mm256_loadu_si256((const __m256i*)(bp + i)); + __m256i vc = _mm256_loadu_si256((const __m256i*)(cp + i)); + __m256i vnewb = _mm256_xor_si256(va, vb); + __m256i vnewc = _mm256_xor_si256(vc, vnewb); + _mm256_storeu_si256((__m256i*)(bp + i), vnewb); + _mm256_storeu_si256((__m256i*)(cp + i), vnewc); + } + if (i < bytelen) { + // trailing loop: deal with the last <= 31 bytes + for (; i + 8 <= bytelen; i += 8) { + // movq loads/stores: _mm_loadl_epi64 / _mm_storel_epi64 are the SSE2 spellings, + // unaligned like _mm_loadu_si64 but available on compilers older than gcc 9. + __m128i va = _mm_loadl_epi64((const __m128i*)(ap + i)); + __m128i vb = _mm_loadl_epi64((const __m128i*)(bp + i)); + __m128i vc = _mm_loadl_epi64((const __m128i*)(cp + i)); + vb = _mm_xor_si128(vb, va); + vc = _mm_xor_si128(vc, vb); + _mm_storel_epi64((__m128i*)(bp + i), vb); + _mm_storel_epi64((__m128i*)(cp + i), vc); + } + for (; i < bytelen; ++i) { + bp[i] ^= ap[i]; + cp[i] ^= bp[i]; + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/piop_circuit.c b/src/sig/sdith/sdith_sdith_common_avx2/piop_circuit.c new file mode 100644 index 0000000000..06e8cbdb20 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/piop_circuit.c @@ -0,0 +1,860 @@ +#include + +#include "vole_private.h" + +static const flambda_max_t FLAMBDA_ONE = {1, 0, 0, 0}; + +/** + * prover packed secret input gate (degree 1) + */ +EXPORT void prover_cst_vole_packed_secret_input_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + bitvec_t* out_pub, // [out] output publication (packed over f2) + fpoly_t* out_f, // [out] poly of degree 1 (cst term over f2) + const bitvec_t* in_value, // [in] secret bit values (packed over f2) + const bitvec_t* in_rvp_u, // [in] packed u terms + const flambda_t* in_rvp_v) // [in] packed v terms +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_v, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + uint8_t* const f = (uint8_t*)out_f; + const uint8_t* const rvp_v = (uint8_t*)in_rvp_v; + const uint8_t* const inval = (uint8_t*)in_value; + vole_params->bitvec_xor((num_inputs + 7) >> 3, out_pub, in_rvp_u, in_value); + + uint64_t leftover_bits = num_inputs & 7; + if (leftover_bits) { + uint8_t* out_pub_u8 = (uint8_t*)out_pub; + uint64_t idx = ((num_inputs + 7) >> 3) - 1; + uint64_t and_mask = (1 << leftover_bits) - 1; + out_pub_u8[idx] &= and_mask; + } + + memset(out_f, 0, 2 * num_inputs * lambda_bytes); + for (uint64_t i = 0; i < num_inputs; i++) { + uint8_t* const fi = f + i * 2 * lambda_bytes; + fi[0] = (inval[i >> 3] >> (i & 7)) & 1; + vole_params->flambda_set(fi + lambda_bytes, rvp_v + i * lambda_bytes); + } +} + +/** + * verifier packed secret input gate (degree 1) + */ +EXPORT void verifier_cst_vole_packed_secret_input_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + fpoly_t* out_q, // [out] vole evaluations + const bitvec_t* in_pub, // [in] publications (packed over f2) + const flambda_t* in_rvp_q, // [in] packed v terms + const flambda_t* delta2) // [in] verifier's point +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(delta2, alignment_of(lambda_bytes)); + + uint8_t* const q = (uint8_t*)out_q; + const uint8_t* const rvp_q = (uint8_t*)in_rvp_q; + const uint8_t* const inpub = (uint8_t*)in_pub; + uint8_t buf[32] = {0}; + +#ifndef NDEBUG + uint64_t leftover_bits = num_inputs & 7; + if (leftover_bits) { + uint64_t mask = ((1 << (8 - leftover_bits)) - 1) << leftover_bits; + uint64_t idx = ((num_inputs + 7) >> 3) - 1; + CASSERT((inpub[idx] & mask) == 0, "[in] publications does not have trailing zeros"); + } +#endif // NDEBUG + + for (uint64_t i = 0; i < num_inputs; i++) { + buf[0] = (inpub[i >> 3] >> (i & 7)) & 1; + vole_params->flambda_sum(q + i * lambda_bytes, rvp_q + i * lambda_bytes, buf); + } +} + +/** + * prover check-zero gate (degree d) + */ +EXPORT void prover_cst_vole_check_zero_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + fpoly_t* out_pub, // [out] output publication (degree d-1) -- not aligned + const fpoly_t* in_f, // [in] input (degree d) + const fpoly_t* in_rvp_f) // [in] rvp (degree d-1) +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_f, alignment_of(lambda_bytes)); + uint8_t* const pub = (uint8_t*)out_pub; + const uint8_t* const in = (uint8_t*)in_f; + const uint8_t* const rvp = (uint8_t*)in_rvp_f; + flambda_max_t pubi; // we use a temp variable for alignment issues + for (uint64_t i = 0; i < degree; i++) { + vole_params->flambda_sum(pubi, rvp + i * lambda_bytes, in + (i + 1) * lambda_bytes); + memcpy(pub + i * lambda_bytes, pubi, lambda_bytes); + } +} + +/** + * verifier check-zero gate (degree d) + */ +EXPORT uint8_t verifier_cst_vole_check_zero_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + flambda_t* out_value, // [out] deduced output value + const fpoly_t* in_pub, // [in] publication (degree d-1) -- not aligned + const flambda_t* in_q, // [in] input (degree d) + const flambda_t* in_rvp_q, // [in] rvp (degree d-1) + const flambda_t* delta2) // [in] verifier's point +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_rvp_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + const uint8_t* const pub = (uint8_t*)in_pub; + flambda_max_t pubi; // tmp variable for alignment purposes + // compute pub(delta2) via horner method + memcpy(out_value, pub + (degree - 1) * lambda_bytes, lambda_bytes); + for (int64_t i = degree - 2; i >= 0; i--) { + vole_params->flambda_product(out_value, out_value, delta2); + memcpy(pubi, pub + i * lambda_bytes, lambda_bytes); + vole_params->flambda_sum(out_value, out_value, pubi); + } + // compute (pub(delta2) + rvp_q) * delta2 + vole_params->flambda_sum(out_value, out_value, in_rvp_q); + vole_params->flambda_product(out_value, out_value, delta2); + // add in_q -> the constant term shall remain + vole_params->flambda_sum(out_value, out_value, in_q); + // zero test (does not need to be ct, nor efficient) + const uint8_t* const out = (uint8_t*)out_value; + for (uint64_t i = 0; i < lambda_bytes; i++) { + if (out[i]) return 0; + } + return 1; +} + +/** + * prover xor gate + */ +EXPORT void prover_cst_vole_xor_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree) // [in] b +{ + uint8_t* res = (uint8_t*)res_f; + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* b = (uint8_t*)b_f; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + // addition + if (a_degree < b_degree) { + for (size_t i = 0; i <= a_degree; i++) { + (*vole_params->flambda_sum)(res + lambda_bytes * i, a + lambda_bytes * i, b + lambda_bytes * i); + } + for (size_t i = a_degree + 1; i <= b_degree; i++) { + (*vole_params->flambda_set)(res + lambda_bytes * i, b + lambda_bytes * i); + } + } else { + for (size_t i = 0; i <= b_degree; i++) { + (*vole_params->flambda_sum)(res + lambda_bytes * i, a + lambda_bytes * i, b + lambda_bytes * i); + } + for (size_t i = b_degree + 1; i <= a_degree; i++) { + (*vole_params->flambda_set)(res + lambda_bytes * i, a + lambda_bytes * i); + } + } +} + +/** + * verifier xor gate + */ +EXPORT void verifier_cst_vole_xor_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_f, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_f, uint64_t a_degree, // [in] a + const flambda_t* b_f, uint64_t b_degree, // [in] b + const flambda_t* delta2) // [in] verifier's point (unused) +{ + (*vole_params->flambda_sum)(res_f, a_f, b_f); +} + +/** + * prover mul gate + */ +EXPORT void prover_cst_vole_mul_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree) // [in] b +{ + uint8_t* res = (uint8_t*)res_f; + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* b = (uint8_t*)b_f; + const size_t lambda_bytes = vole_params->lambda_bytes; + CASSERT(res != a && res != b, "function does not work in place"); + flambda_max_t tmp; + + // zeroize result + memset(res, 0, lambda_bytes * (a_degree + b_degree + 1)); + + // Schoolbook multiplication + for (size_t i_a = 0; i_a <= a_degree; i_a++) { + for (size_t i_b = 0; i_b <= b_degree; i_b++) { + (*vole_params->flambda_product)(tmp, a + lambda_bytes * i_a, b + lambda_bytes * i_b); + (*vole_params->flambda_sum)(res + lambda_bytes * (i_a + i_b), res + lambda_bytes * (i_a + i_b), tmp); + } + } +} + +/** + * verifier mul gate + */ +EXPORT void verifier_cst_vole_mul_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_q, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_q, uint64_t a_degree, // [in] a + const flambda_t* b_q, uint64_t b_degree, // [in] b + const flambda_t* delta2) // [in] verifier's point (unused) +{ + (*vole_params->flambda_product)(res_q, a_q, b_q); +} + +/** + * prover echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void prover_cst_vole_echelon_pow2_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + fpoly_t* res_f, // [out] res of degree 1 + const fpoly_t* a_f) // [in] (arity) a of degree 1 +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint8_t* const res = (uint8_t*)res_f; + const uint8_t* const a = (uint8_t*)a_f; + // note: we can speed-up the first one one since the cst term is over f2 + vole_params->flambda_echelon_pow2(k, res, a, arity, 2 * lambda_bytes); + vole_params->flambda_echelon_pow2(k, res + lambda_bytes, a + lambda_bytes, arity, 2 * lambda_bytes); +} +/** + * verifier echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void verifier_cst_vole_echelon_pow2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* delta2) // [in] verifier's point (unused) +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint8_t* const res = (uint8_t*)res_q; + const uint8_t* const a = (uint8_t*)a_q; + vole_params->flambda_echelon_pow2(k, res, a, arity, lambda_bytes); +} + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t prover_cst_check_unitary_gate_ct_ref_tmp_bytes(const vole_parameters* vole_params) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, 3 * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, 2 * lambda_bytes); + COMP_SPACE_RETURN(); +} + +/** + * prover check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void prover_cst_check_unitary_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // arity >= 1 + fpoly_t* res_f, // [out] res of degree 2 + const fpoly_t* a_f, // [in] (arity) a of deg 1 + const flambda_t* coeff, // [in] challenge coeff + uint8_t* tmp_space) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, 3 * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, 2 * lambda_bytes); + + prover_cst_vole_echelon_pow2_ct_ref(vole_params, arity, 1, tmp_fpoly_t1, a_f); + prover_cst_vole_echelon_pow2_ct_ref(vole_params, arity - 1, arity, tmp_fpoly_t2, a_f); + prover_cst_vole_mul_gate_ct_ref(vole_params, res_f, tmp_fpoly_t1, 1, tmp_fpoly_t2, 1); + + prover_cst_vole_echelon_pow2_ct_ref(vole_params, arity - 1, arity + 1, tmp_fpoly_t2, a_f); + + // Add using the xor gate + prover_cst_vole_xor_gate_ct_ref(vole_params, tmp_fpoly_t1, res_f, 2, tmp_fpoly_t2, 1); + + // Multiply by coeff + prover_cst_vole_mul_gate_ct_ref(vole_params, res_f, tmp_fpoly_t1, 2, coeff, 0); +} + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t verifier_cst_check_unitary_gate_ref_tmp_bytes(const vole_parameters* vole_params) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, lambda_bytes); + COMP_SPACE_RETURN(); +} + +/** + * verifier check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void verifier_cst_check_unitary_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* coeff, // [in] challenge coeff + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, lambda_bytes); + + verifier_cst_vole_echelon_pow2_ref(vole_params, arity, 1, tmp_fpoly_t1, a_q, delta2); + verifier_cst_vole_echelon_pow2_ref(vole_params, arity - 1, arity, tmp_fpoly_t2, a_q, delta2); + verifier_cst_vole_mul_gate_ref(vole_params, res_q, tmp_fpoly_t1, 1, tmp_fpoly_t2, 1, delta2); + + verifier_cst_vole_echelon_pow2_ref(vole_params, arity - 1, arity + 1, tmp_fpoly_t2, a_q, delta2); + + // Add using the xor gate + verifier_cst_vole_xor_gate_ref(vole_params, tmp_fpoly_t1, res_q, 2, tmp_fpoly_t2, 1, delta2); + + // Multiply by coeff + verifier_cst_vole_mul_gate_ref(vole_params, res_q, tmp_fpoly_t1, 2, coeff, 0, delta2); +} + +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes(const vole_parameters* vole_params, uint64_t arity, + uint64_t in_degree) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, (in_degree + 2) * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, (in_degree + 2) * lambda_bytes); + COMP_SPACE_RETURN(); +} + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_naive( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (real_arity) values of deg d + uint8_t* tmp_space) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* c = (uint8_t*)c_f; + uint64_t a_poly_bytes = (in_degree + 1) * lambda_bytes; + uint64_t c_poly_bytes = 2 * lambda_bytes; + + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t1, 32, (in_degree + 2) * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, tmp_fpoly_t2, 32, (in_degree + 2) * lambda_bytes); + + uint8_t* res_f_u8 = (uint8_t*)res_f; + + // a[0] + memcpy(res_f, a, (in_degree + 1) * lambda_bytes); + + // zeroing out the last coefficient + memset(res_f_u8 + (in_degree + 1) * lambda_bytes, 0, lambda_bytes); + + for (uint64_t i = 1; i < real_arity; i++) { + prover_cst_vole_xor_gate_ct_ref(vole_params, tmp_fpoly_t1, a + i * a_poly_bytes, in_degree, a, in_degree); + + // multiple the sum by a[i-1] + prover_cst_vole_mul_gate_ct_ref(vole_params, tmp_fpoly_t2, c + (i - 1) * c_poly_bytes, 1, tmp_fpoly_t1, in_degree); + + // sum the parts together + prover_cst_vole_xor_gate_ct_ref(vole_params, res_f, tmp_fpoly_t2, in_degree + 1, res_f, in_degree + 1); + } +} + +EXPORT uint64_t verifier_cst_vole_qary_mux_ctrl_bytes(const vole_parameters* vole_params, uint64_t arity) { + return arity * vole_params->lambda_bytes; +} + +/** + * Rewrite the control values as the extended control vector described in sdith_piop_circuits.h. + */ +EXPORT void verifier_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (real_arity) extended control + const flambda_t* c_q, // [in] (real_arity-1) control values + const flambda_t* delta2) { // [in] verifier's point (unused) + const uint64_t lambda_bytes = vole_params->lambda_bytes; + + const uint8_t* c = (uint8_t*)c_q; + uint8_t* ctrl_u8 = (uint8_t*)ctrl; + + // ctrl[0] accumulates all the other control values + (*vole_params->flambda_set)(ctrl_u8, FLAMBDA_ONE); + for (uint64_t i = 1; i < real_arity; ++i) { + const uint8_t* ci = c + (i - 1) * lambda_bytes; + (*vole_params->flambda_set)(ctrl_u8 + i * lambda_bytes, ci); + (*vole_params->flambda_sum)(ctrl_u8, ctrl_u8, ci); + } +} + +/** + * verifier qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void verifier_cst_vole_qary_mux_gate_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + flambda_t* res_q, // [out] evaluation of the poly of degree d+1 + const flambda_t* ctrl, // [in] (real_arity) prepared control + const flambda_t* a_q, // [in] (real_arity) values of deg d + const flambda_t* delta2) { // [in] verifier's point (unused) + // res = sum_i ctrl[i] . a[i]: the verifier's values are single field elements, so the inputs + // of a gate are already the contiguous vector a dot product wants. + (*vole_params->flambda_dot_product)(res_q, a_q, ctrl, real_arity); +} + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t verifier_cst_vole_qary_mux_gate_ref_tmp_bytes(const vole_parameters* vole_params, uint64_t arity, + uint64_t in_degree) { + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, arity)); + COMP_SPACE_RETURN(); +} + +/** + * verifier qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void verifier_cst_vole_qary_mux_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + flambda_t* res_q, // [out] poly of degree d+1 + const flambda_t* c_q, // [in] (arity-1) control bits of deg. 1 + const flambda_t* a_q, // [in] (real_arity) values of deg d + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space) { // scratch space + TMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, real_arity)); + verifier_cst_vole_qary_mux_prepare_ctrl(vole_params, real_arity, ctrl, c_q, delta2); + verifier_cst_vole_qary_mux_gate_prep(vole_params, real_arity, res_q, ctrl, a_q, delta2); +} + +EXPORT uint64_t prover_cst_vole_qary_mux_ctrl_bytes(const vole_parameters* vole_params, uint64_t arity) { + return 2 * arity * vole_params->lambda_bytes; +} + +/** + * Rewrite the control bits as the two extended control vectors described in sdith_piop_circuits.h. + */ +EXPORT void prover_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (2 x real_arity) extended control + const fpoly_t* c_f) { // [in] (real_arity-1) control bits of deg. 1 + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t c_poly_bytes = 2 * lambda_bytes; + + const uint8_t* c = (uint8_t*)c_f; + uint8_t* ctrl0 = (uint8_t*)ctrl; + uint8_t* ctrl1 = ctrl0 + real_arity * lambda_bytes; + + // ctrl{0,1}[0] accumulate the coefficients of all the other control bits + (*vole_params->flambda_set)(ctrl0, FLAMBDA_ONE); + memset(ctrl1, 0, lambda_bytes); + for (uint64_t i = 1; i < real_arity; ++i) { + const uint8_t* ci = c + (i - 1) * c_poly_bytes; + (*vole_params->flambda_set)(ctrl0 + i * lambda_bytes, ci); + (*vole_params->flambda_set)(ctrl1 + i * lambda_bytes, ci + lambda_bytes); + (*vole_params->flambda_sum)(ctrl0, ctrl0, ci); + (*vole_params->flambda_sum)(ctrl1, ctrl1, ci + lambda_bytes); + } +} + +/** + * prover qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const flambda_t* ctrl, // [in] (2 x real_arity) prepared control + const fpoly_t* a_f) { // [in] (real_arity) values of deg d + const uint64_t lambda_bytes = vole_params->lambda_bytes; + // input i lives at a + i * a_poly_bytes: for a fixed coefficient j, the inputs are a strided vector + const uint64_t a_poly_bytes = (in_degree + 1) * lambda_bytes; + + const uint8_t* a = (uint8_t*)a_f; + const uint8_t* ctrl0 = (uint8_t*)ctrl; + const uint8_t* ctrl1 = ctrl0 + real_arity * lambda_bytes; + uint8_t* res_f_u8 = (uint8_t*)res_f; + + memset(res_f_u8, 0, (in_degree + 2) * lambda_bytes); + for (uint64_t j = 0; j <= in_degree; ++j) { + // res[j] += sum_i ctrl0[i] . a[i][j] (a bit-select: the ctrl0[i] are in F2) + (*vole_params->flambda_dot_product_f2_acc)(res_f_u8 + j * lambda_bytes, // + a + j * lambda_bytes, a_poly_bytes, ctrl0, real_arity); + // res[j+1] += sum_i ctrl1[i] . a[i][j] + (*vole_params->flambda_dot_product_acc)(res_f_u8 + (j + 1) * lambda_bytes, // + a + j * lambda_bytes, a_poly_bytes, ctrl1, real_arity); + } +} + +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes(const vole_parameters* vole_params, + uint64_t arity) { + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, arity)); + COMP_SPACE_RETURN(); +} + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) using product_f2 + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t real_arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (real_arity) values of deg d + uint8_t* tmp_space) { // scratch space + TMP_SPACE_MAP_ALIGNED(uint8_t*, ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, real_arity)); + prover_cst_vole_qary_mux_prepare_ctrl(vole_params, real_arity, ctrl, c_f); + prover_cst_vole_qary_mux_gate_ct_f2_prep(vole_params, real_arity, in_degree, res_f, ctrl, a_f); +} + +void tmp_bytes_init(tmp_bytes_comp_t* tmp_bytes_comp) { + tmp_bytes_comp->local_size = 0; + tmp_bytes_comp->last_alignment = 1; + tmp_bytes_comp->max_size = 0; +} + +void tmp_bytes_reserve_local_var(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_bytes) { + tmp_bytes_comp->local_size += var_bytes; + if (tmp_bytes_comp->local_size > tmp_bytes_comp->max_size) { + tmp_bytes_comp->max_size = tmp_bytes_comp->local_size; + } +} + +void tmp_bytes_reserve_local_var_aligned(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_align, uint64_t var_bytes) { + if (var_align > tmp_bytes_comp->last_alignment) { + tmp_bytes_comp->local_size = + (tmp_bytes_comp->local_size + tmp_bytes_comp->last_alignment - 1) & (uint64_t)(-tmp_bytes_comp->last_alignment); + tmp_bytes_comp->local_size += var_align - tmp_bytes_comp->last_alignment; + tmp_bytes_comp->last_alignment = var_align; + } else { + tmp_bytes_comp->local_size = (tmp_bytes_comp->local_size + var_align - 1) & (uint64_t)(-var_align); + } + tmp_bytes_comp->local_size += var_bytes; + if (tmp_bytes_comp->local_size > tmp_bytes_comp->max_size) { + tmp_bytes_comp->max_size = tmp_bytes_comp->local_size; + } +} + +void tmp_bytes_reserve_call(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t call_tmp_bytes) { + uint64_t ms = tmp_bytes_comp->local_size + call_tmp_bytes; + if (ms > tmp_bytes_comp->max_size) { + tmp_bytes_comp->max_size = ms; + } +} + +/** + * Validate the shape of a mux-circuit and return its largest arity. + * + * The layer loops below rely on every layer having at least one output: num_out == 0 would make + * "num_out - 1" wrap around and the last mux would be applied with a nonsense arity. That cannot + * happen as soon as num_inputs >= 1 and every arity is >= 1, since ceil(n/arity) >= 1 for n >= 1. + * The last layer must also collapse to a single output, otherwise the circuit would silently drop + * the inputs beyond the first mux: iterating the ceil-division is an overflow-free way to check + * the documented "num_inputs <= product of the arities". + */ +static uint64_t mux_circuit_check_shape( // + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities + uint64_t num_inputs) { // number of inputs + CREQUIRE(depth >= 1, "mux circuit depth must be >= 1"); + CREQUIRE(num_inputs >= 1, "mux circuit must have at least one input"); + uint64_t max_arity = 1; + uint64_t num_inputs_at_depth = num_inputs; + for (uint64_t d = 0; d < depth; ++d) { + CREQUIRE(arities[d] >= 1, "mux arity must be >= 1"); + if (arities[d] > max_arity) max_arity = arities[d]; + num_inputs_at_depth = (num_inputs_at_depth + arities[d] - 1) / arities[d]; + } + CREQUIRE(num_inputs_at_depth == 1, "mux arities too small for the number of inputs"); + return max_arity; +} + +/** + * scratch space required by prover_cst_mux_circuit_ct_ref + */ +EXPORT uint64_t prover_cst_mux_circuit_ct_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs) { // scratch space + + const uint64_t lambda_bytes = vole_params->lambda_bytes; + // tmp space for calculations of check_unitary_gate: 5 * lambda_bytes + // tmp space to hold intermediate values for check_unitary_gate: 3 * lambda_bytes; + // tmp space for calculations of qary_mux_gate: 2 * (depth + 2) + // tmp space to hold 2 intermediate values for qary_mux_gate: 2*3*max_inputs*lambda_bytes + // tmp space for the prepared control of a layer (full and last, incomplete, mux) + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_values, 32, 3 * lambda_bytes); // 3*lambda_bytes; + COMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary1, 32, 3 * max_inputs * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary2, 32, 3 * max_inputs * lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_CALL(prover_cst_check_unitary_gate_ct_ref_tmp_bytes(vole_params)); + COMP_SPACE_RETURN(); +} + +const flambda_max_t FLAMBDA_2P32 = {UINT64_C(1) << 32, 0, 0, 0}; + +/** + * prover mux-circuit: + */ +EXPORT void prover_cst_mux_circuit_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + fpoly_t* res_f, // [out] res of degree depth + const fpoly_t* c_f, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge value for unitary tests + uint8_t* tmp_space) { // [tmp] scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + CASSERT_ALIGNMENT(res_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(c_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(a, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(chall_c, alignment_of(lambda_bytes)); + + TMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_values, 32, 3 * lambda_bytes); // 3*lambda_bytes; + TMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary1, 32, 3 * max_inputs * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, intermediate_unitary_quary2, 32, 3 * max_inputs * lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, prover_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_CALL(prover_cst_check_unitary_gate_ct_ref_tmp_bytes(vole_params)); + + uint8_t* c = (uint8_t*)c_f; + uint64_t c_bytes = 2 * lambda_bytes; + flambda_max_t unary_cur_chall; + uint64_t unary_next_chall_power = 0; + + // tmp + uint8_t* res_f_u8 = (uint8_t*)res_f; + memset(res_f_u8, 0, (depth + 1) * lambda_bytes); + + // correct for check_unitary_sum + uint64_t c_pos = 0; + uint64_t num_inputs_at_depth = num_inputs; + uint8_t* a_in = (uint8_t*)a; + uint8_t* output_qary = intermediate_unitary_quary1; + + for (uint64_t d = 0; d < depth; d++) { + if (arities[d] > 2) { + // prepare the next unary challenge coefficient + if (unary_next_chall_power == 0) { + vole_params->flambda_set(unary_cur_chall, chall_c); + } else { + CASSERT(unary_next_chall_power <= vole_params->LAMBDA - 32, "unary challenge overflow (bad parameter set)"); + vole_params->flambda_product(unary_cur_chall, unary_cur_chall, FLAMBDA_2P32); + } + unary_next_chall_power += 32; + // apply the check + prover_cst_check_unitary_gate_ct_ref(vole_params, arities[d] - 1, intermediate_unitary_values, + c + c_pos * c_bytes, unary_cur_chall, tmp_space); + + prover_cst_vole_xor_gate_ct_ref(vole_params, res_f, res_f, depth, intermediate_unitary_values, 2); + // prepare the next challenge point + } + + const uint64_t num_out = (num_inputs_at_depth + arities[d] - 1) / arities[d]; + uint64_t unitary_qary_in_size = (d + 1) * lambda_bytes; + uint64_t unitary_qary_out_size = (d + 2) * lambda_bytes; + + // every mux of the layer shares the same control bits: prepare it once + prover_cst_vole_qary_mux_prepare_ctrl(vole_params, arities[d], mux_ctrl, c + c_pos * c_bytes); + + for (uint64_t j = 0; j + 1 < num_out; j++) { + prover_cst_vole_qary_mux_gate_ct_f2_prep(vole_params, arities[d], d, // + output_qary + j * unitary_qary_out_size, // + mux_ctrl, // + a_in + j * arities[d] * unitary_qary_in_size); + } + + // the last mux can be incomplete (fewer inputs => a control of its own) + { + uint64_t j = num_out - 1; // num_out >= 1: guaranteed by mux_circuit_check_shape + uint64_t last_arity = num_inputs_at_depth - j * arities[d]; + CASSERT(last_arity >= 1 && last_arity <= arities[d], "bad last mux arity"); + prover_cst_vole_qary_mux_prepare_ctrl(vole_params, last_arity, mux_ctrl_last, c + c_pos * c_bytes); + prover_cst_vole_qary_mux_gate_ct_f2_prep(vole_params, last_arity, d, // + output_qary + j * unitary_qary_out_size, // + mux_ctrl_last, // + a_in + j * arities[d] * unitary_qary_in_size); + } + + // return final value + if (d == depth - 1) { + prover_cst_vole_xor_gate_ct_ref(vole_params, res_f, res_f, depth, output_qary, d + 1); + } + + c_pos += arities[d] - 1; + num_inputs_at_depth = num_out; + if (d % 2 == 0) { + a_in = intermediate_unitary_quary1; + output_qary = intermediate_unitary_quary2; + } else { + a_in = intermediate_unitary_quary2; + output_qary = intermediate_unitary_quary1; + } + } +} + +/** + * scratch space required by verifier_cst_mux_circuit_ref + */ +EXPORT uint64_t verifier_cst_mux_circuit_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs) { // scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + // tmp space for calculations: 2 * lambda_bytes + // tmp space to hold intermediate values for check_unitary_gate: 2*lambda_bytes bytes + // tmp space to hold two intermediate values for qary_mux_gate: 2*3*max_inputs*lambda_bytes + // tmp space for the prepared control of a layer (full and last, incomplete, mux) + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + const uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, unitary_chk, 32, lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_even, 32, max_inputs* lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_odd, 32, max_inputs* lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + COMP_SPACE_MAP_CALL(verifier_cst_check_unitary_gate_ref_tmp_bytes(vole_params)); // unitary chk + COMP_SPACE_RETURN(); +} + +/** + * verifier mux-circuit: + */ +EXPORT void verifier_cst_mux_circuit_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + flambda_t* res_q, // [out] res of degree depth + const flambda_t* c_q, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge value for unitary tests + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space) { // [tmp] scratch space + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(res_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(c_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(a, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(chall_c, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(delta2, alignment_of(lambda_bytes)); + + const uint64_t max_arity = mux_circuit_check_shape(depth, arities, num_inputs); + const uint64_t max_inputs = ((num_inputs + arities[0] - 1) / arities[0]); + TMP_SPACE_MAP_ALIGNED(uint8_t*, unitary_chk, 32, lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_even, 32, max_inputs* lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, in_out_odd, 32, max_inputs* lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_ctrl_last, 32, verifier_cst_vole_qary_mux_ctrl_bytes(vole_params, max_arity)); + TMP_SPACE_MAP_CALL(verifier_cst_check_unitary_gate_ref_tmp_bytes(vole_params)); // unitary chk + + uint8_t* c = (uint8_t*)c_q; + uint64_t c_bytes = lambda_bytes; + flambda_max_t unary_cur_chall; + uint64_t unary_next_chall_power = 0; + + // tmp + uint8_t* res_q_u8 = (uint8_t*)res_q; + memset(res_q_u8, 0, lambda_bytes); + + uint64_t c_pos = 0; + uint64_t num_inputs_at_depth = num_inputs; + uint8_t* a_in = (uint8_t*)a; + uint8_t* output_qary = in_out_even; + uint64_t unitary_qary_in_size = lambda_bytes; + uint64_t unitary_qary_out_size = lambda_bytes; + for (uint64_t d = 0; d < depth; d++) { + if (arities[d] > 2) { + // prepare the next unary challenge coefficient + if (unary_next_chall_power == 0) { + vole_params->flambda_set(unary_cur_chall, chall_c); + } else { + CASSERT(unary_next_chall_power <= vole_params->LAMBDA - 32, "unary challenge overflow (bad parameter set)"); + vole_params->flambda_product(unary_cur_chall, unary_cur_chall, FLAMBDA_2P32); + } + unary_next_chall_power += 32; + // apply the check + verifier_cst_check_unitary_gate_ref(vole_params, arities[d] - 1, // + unitary_chk, // + c + c_pos * c_bytes, // + unary_cur_chall, delta2, tmp_space); + verifier_cst_vole_xor_gate_ref(vole_params, res_q, res_q, depth, unitary_chk, 2, delta2); + } + + const uint64_t num_out = (num_inputs_at_depth + arities[d] - 1) / arities[d]; + + // every mux of the layer shares the same control values: prepare it once + verifier_cst_vole_qary_mux_prepare_ctrl(vole_params, arities[d], mux_ctrl, c + c_pos * c_bytes, delta2); + + for (uint64_t j = 0; j + 1 < num_out; j++) { + verifier_cst_vole_qary_mux_gate_prep(vole_params, arities[d], // + output_qary + j * unitary_qary_out_size, // + mux_ctrl, // + a_in + j * arities[d] * unitary_qary_in_size, // + delta2); + } + + // the last mux can be incomplete (fewer inputs => a control of its own) + { + uint64_t j = num_out - 1; // num_out >= 1: guaranteed by mux_circuit_check_shape + uint64_t last_arity = num_inputs_at_depth - j * arities[d]; + CASSERT(last_arity >= 1 && last_arity <= arities[d], "bad last mux arity"); + verifier_cst_vole_qary_mux_prepare_ctrl(vole_params, last_arity, mux_ctrl_last, c + c_pos * c_bytes, delta2); + verifier_cst_vole_qary_mux_gate_prep(vole_params, last_arity, // + output_qary + j * unitary_qary_out_size, // + mux_ctrl_last, // + a_in + j * arities[d] * unitary_qary_in_size, // + delta2); + } + + // return final value + if (d == depth - 1) { + verifier_cst_vole_xor_gate_ref(vole_params, res_q, res_q, depth, output_qary, d + 1, delta2); + } + + c_pos += arities[d] - 1; + num_inputs_at_depth = num_out; + + if (d % 2 == 0) { + a_in = in_out_even; + output_qary = in_out_odd; + } else { + a_in = in_out_odd; + output_qary = in_out_even; + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256.c b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256.c new file mode 100644 index 0000000000..f6a1af615b --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256.c @@ -0,0 +1,187 @@ +#include +#include "rijndael256.h" + +static const uint8_t __sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 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 __mul2[256] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, + 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, + 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, + 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, + 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, + 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 +}; + +static const uint8_t __mul3[256] = { + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, + 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, + 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, + 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, + 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, + 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, + 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, + 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, + 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, + 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, + 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a +}; + +static const size_t __SR2[Nb] = {2, 14, 26, 6, 18, 30, 10, 22}; + +static const uint8_t __rc[14] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d}; + +static inline void _SubBytes(rijndael256_state_t state) +{ + for (size_t i = 0; i < Nbytes; i++) + { + state[i] = __sbox[state[i]]; + } +} + +static inline void _ShiftRows(rijndael256_state_t state) +{ + // shift row 1 by 1 + for (size_t i = 0; i < Nb-1; i++) + { + state[4*i+1] ^= state[4*i+5]; + state[4*i+5] ^= state[4*i+1]; + state[4*i+1] ^= state[4*i+5]; + } + + // shift row 2 by 3 + for (size_t i = 0; i < Nb-1; i++) + { + state[__SR2[i+0]] ^= state[__SR2[i+1]]; + state[__SR2[i+1]] ^= state[__SR2[i+0]]; + state[__SR2[i+0]] ^= state[__SR2[i+1]]; + } + + // shift row 3 by 4 + for (size_t i = 0; i < Nb/2; i++) + { + state[4*i+ 3] ^= state[4*i+19]; + state[4*i+19] ^= state[4*i+ 3]; + state[4*i+ 3] ^= state[4*i+19]; + } +} + +static inline void _MixColumns(rijndael256_state_t state) +{ + for (size_t i = 0; i < Nb; i++) + { + uint8_t tmp[4] = { + state[4*i+0], + state[4*i+1], + state[4*i+2], + state[4*i+3] + }; + + state[4*i+0] = __mul2[tmp[0]] ^ __mul3[tmp[1]] ^ tmp[2] ^ tmp[3]; + state[4*i+1] = __mul2[tmp[1]] ^ __mul3[tmp[2]] ^ tmp[3] ^ tmp[0]; + state[4*i+2] = __mul2[tmp[2]] ^ __mul3[tmp[3]] ^ tmp[0] ^ tmp[1]; + state[4*i+3] = __mul2[tmp[3]] ^ __mul3[tmp[0]] ^ tmp[1] ^ tmp[2]; + } +} + +static inline void _AddRoundKey(rijndael256_state_t state, const rijndael256_key_t key) +{ + for (size_t i = 0; i < Nbytes; i++) + { + state[i] ^= key[i]; + } +} + +static void _round(rijndael256_state_t state, const rijndael256_key_t key) +{ + _SubBytes(state); + _ShiftRows(state); + _MixColumns(state); + _AddRoundKey(state, key); +} + +static void _keyschedule(rijndael256_key_t key, const rijndael256_key_t oldkey, int round) +{ + for (size_t j = 0; j < Nk; j++) + { + if (j == 0) + { + key[0] = oldkey[0] ^ __sbox[oldkey[29]] ^ __rc[round-1]; + key[1] = oldkey[1] ^ __sbox[oldkey[30]]; + key[2] = oldkey[2] ^ __sbox[oldkey[31]]; + key[3] = oldkey[3] ^ __sbox[oldkey[28]]; + } else if (j == 4) { + key[16] = oldkey[16] ^ __sbox[key[12]]; + key[17] = oldkey[17] ^ __sbox[key[13]]; + key[18] = oldkey[18] ^ __sbox[key[14]]; + key[19] = oldkey[19] ^ __sbox[key[15]]; + } else { + for (size_t i = 0; i < 4; i++) + { + key[j*4+i] = oldkey[j*4+i] ^ key[(j-1)*4+i]; + } + } + } +} + +static void _encrypt(rijndael256_state_t res, const rijndael256_rk_t *roundkeys) +{ + _AddRoundKey(res, roundkeys->rk[0]); + for (size_t i = 1; i < Nr; i++) + { + _round(res, roundkeys->rk[i]); + } + _SubBytes(res); + _ShiftRows(res); + _AddRoundKey(res, roundkeys->rk[Nr]); +} + +void rijndael256_key_schedule_ref(rijndael256_rk_t *roundkeys, const uint8_t key[32]) +{ + // expand key + memcpy(roundkeys->rk[0], key, Nbytes); + for (size_t i = 1; i <= Nr; i++) + { + _keyschedule(roundkeys->rk[i], roundkeys->rk[i-1], i); + } +} + + + +void rijndael256_encrypt_1block_ref(uint8_t res[ 32], const uint8_t x[ 32], const rijndael256_rk_t *roundkeys) +{ + memcpy(res, x, 32); + // encrypt + _encrypt(res, roundkeys); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256.h b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256.h new file mode 100644 index 0000000000..489c897616 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256.h @@ -0,0 +1,41 @@ +#ifndef RIJNDAEL256__H +#define RIJNDAEL256__H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#include "sdith_inline.h" + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +#define Nb 8 +#define Nk 8 +#define Nbytes (Nb*4) +#define Nr 14 + +typedef uint8_t rijndael256_state_t[Nbytes]; + +#if Nb != Nk +#error "This implementation expects Nb == Nk." +#endif + +typedef uint8_t rijndael256_key_t[Nbytes]; + +typedef struct { + rijndael256_key_t rk[Nr+1]; +} rijndael256_rk_t; + +EXPORT void rijndael256_key_schedule_ref(rijndael256_rk_t *roundkeys, const uint8_t key[32]); +EXPORT void rijndael256_encrypt_1block_ref(uint8_t res[ 32], const uint8_t x[ 32], const rijndael256_rk_t *roundkeys); + +#endif diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_avx.c b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_avx.c new file mode 100644 index 0000000000..bc9c96dc04 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_avx.c @@ -0,0 +1,148 @@ +#include "rijndael256_avx.h" + +// The following part is adapted from a work by Nir Drucker and Shay Gueron: +// Software optimization of Rijndael for Modern x86_64 platforms, +// in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) +// Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// This file now provides only the Rijndael-256 key expansion (AVX/AES-NI). The +// ECB / CTR encryption cores were removed in favour of the register-based CTR path +// in rijndael256_ctrle_special_avx2.c (sdith_rij_encN / sdith_rij_ctr_lo). + +#define KEY_SCHEDULE_ROUNDS 14 + +// AVX instructions used by the key expansion +#define SET(v1, v2, v3, v4) _mm_set_epi32((v1), (v2), (v3), (v4)) +#define LOAD(mem) _mm_loadu_si128((const __m128i*)(mem)) +#define STORE(mem, reg) _mm_storeu_si128((__m128i*)(mem), (reg)) +#define AESENCLAST(in, key) _mm_aesenclast_si128((in), (key)) +#define SLL(reg, n) _mm_slli_si128((reg), (n)) +#define SHUF8(in, mask) _mm_shuffle_epi8((in), (mask)) + +// ---- aesenclast-based batched key expansion --------------------------------- +// +// Uses aesenclast for the SubWord step (cheaper and pipelineable than the serial +// aeskeygenassist chain) and expands up to 4 independent keys at once to hide its +// latency. The round keys are bit-identical to the classic aeskeygenassist schedule +// (KAT-preserving): the rijndael256 key schedule is the AES-256 (Nk=8) schedule, +// and since SubWord is byte-wise, SubWord(RotWord(x)) == RotWord(SubWord(x)), so a +// broadcast-then-aesenclast computes exactly the SubWord step aeskeygenassist does. +// +// Each 256-bit key state is two 128-bit halves: lo = w0..w3, hi = w4..w7. Per +// round r we produce the next lo,hi (stored contiguously, matching the old layout): +// lo' = cascade(lo, g_lo), with g_lo = SubWord(RotWord(w7)) ^ rcon (broadcast) +// hi' = cascade(hi, g_hi), with g_hi = SubWord(w3 of lo') (broadcast) + +// broadcast RotWord(word3) to all four 32-bit words (bytes 13,14,15,12 of the reg) +#define R256_RWBC SET(0x0c0f0e0d, 0x0c0f0e0d, 0x0c0f0e0d, 0x0c0f0e0d) +// broadcast word3 unrotated to all four words (bytes 12,13,14,15 of the reg) +#define R256_WBC SET(0x0f0e0d0c, 0x0f0e0d0c, 0x0f0e0d0c, 0x0f0e0d0c) + +static const uint8_t r256_rcon[KEY_SCHEDULE_ROUNDS] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, + 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d}; // NOLINT + +// new word-group = g ^ w ^ (w<<4) ^ (w<<8) ^ (w<<12), g broadcast to all 4 words. +// The w-terms are a byte-word prefix-XOR of w, factored into log steps to drop one +// pslldq + one xor per half per round (the schedule is port-5 bound). Byte-identical: +// a = w ^ (w<<4); t = a ^ (a<<8); result = t ^ g. +SDITH_ALWAYS_INLINE __m128i r256_cascade(__m128i w, __m128i g) { + __m128i a = _mm_xor_si128(w, SLL(w, 4)); + __m128i t = _mm_xor_si128(a, SLL(a, 8)); + return _mm_xor_si128(t, g); +} + +// g for the low half (i%8==0): SubWord(RotWord(w7)) ^ rcon, broadcast. +SDITH_ALWAYS_INLINE __m128i r256_g_lo(__m128i hi, int rc) { + return AESENCLAST(SHUF8(hi, R256_RWBC), _mm_set1_epi32(rc)); +} +// g for the high half (i%8==4): SubWord(w3 of the updated lo), broadcast. +SDITH_ALWAYS_INLINE __m128i r256_g_hi(__m128i lo) { + return AESENCLAST(SHUF8(lo, R256_WBC), _mm_setzero_si128()); +} + +#define R256_STORE_RK(rk, off, lo, hi) \ + do { \ + STORE((__m128i*)((uint8_t*)(rk) + (off)), (lo)); \ + STORE((__m128i*)((uint8_t*)(rk) + (off) + 16), (hi)); \ + } while (0) + +void rijndael256_keyexp_x1_enclast(void* rk0, const void* k0) { + __m128i lo0 = LOAD(k0), hi0 = LOAD((const uint8_t*)k0 + 16); + R256_STORE_RK(rk0, 0, lo0, hi0); + for (size_t r = 0; r < KEY_SCHEDULE_ROUNDS; r++) { + const int rc = r256_rcon[r]; + lo0 = r256_cascade(lo0, r256_g_lo(hi0, rc)); + hi0 = r256_cascade(hi0, r256_g_hi(lo0)); + R256_STORE_RK(rk0, 32 * (r + 1), lo0, hi0); + } +} + +void rijndael256_keyexp_x2_enclast(void* rk0, void* rk1, const void* k0, const void* k1) { + __m128i lo0 = LOAD(k0), hi0 = LOAD((const uint8_t*)k0 + 16); + __m128i lo1 = LOAD(k1), hi1 = LOAD((const uint8_t*)k1 + 16); + R256_STORE_RK(rk0, 0, lo0, hi0); + R256_STORE_RK(rk1, 0, lo1, hi1); + for (size_t r = 0; r < KEY_SCHEDULE_ROUNDS; r++) { + const int rc = r256_rcon[r]; + lo0 = r256_cascade(lo0, r256_g_lo(hi0, rc)); + lo1 = r256_cascade(lo1, r256_g_lo(hi1, rc)); + hi0 = r256_cascade(hi0, r256_g_hi(lo0)); + hi1 = r256_cascade(hi1, r256_g_hi(lo1)); + R256_STORE_RK(rk0, 32 * (r + 1), lo0, hi0); + R256_STORE_RK(rk1, 32 * (r + 1), lo1, hi1); + } +} + +void rijndael256_keyexp_x3_enclast(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2) { + __m128i lo0 = LOAD(k0), hi0 = LOAD((const uint8_t*)k0 + 16); + __m128i lo1 = LOAD(k1), hi1 = LOAD((const uint8_t*)k1 + 16); + __m128i lo2 = LOAD(k2), hi2 = LOAD((const uint8_t*)k2 + 16); + R256_STORE_RK(rk0, 0, lo0, hi0); + R256_STORE_RK(rk1, 0, lo1, hi1); + R256_STORE_RK(rk2, 0, lo2, hi2); + for (size_t r = 0; r < KEY_SCHEDULE_ROUNDS; r++) { + const int rc = r256_rcon[r]; + lo0 = r256_cascade(lo0, r256_g_lo(hi0, rc)); + lo1 = r256_cascade(lo1, r256_g_lo(hi1, rc)); + lo2 = r256_cascade(lo2, r256_g_lo(hi2, rc)); + hi0 = r256_cascade(hi0, r256_g_hi(lo0)); + hi1 = r256_cascade(hi1, r256_g_hi(lo1)); + hi2 = r256_cascade(hi2, r256_g_hi(lo2)); + R256_STORE_RK(rk0, 32 * (r + 1), lo0, hi0); + R256_STORE_RK(rk1, 32 * (r + 1), lo1, hi1); + R256_STORE_RK(rk2, 32 * (r + 1), lo2, hi2); + } +} + +void rijndael256_keyexp_x4_enclast(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + __m128i lo0 = LOAD(k0), hi0 = LOAD((const uint8_t*)k0 + 16); + __m128i lo1 = LOAD(k1), hi1 = LOAD((const uint8_t*)k1 + 16); + __m128i lo2 = LOAD(k2), hi2 = LOAD((const uint8_t*)k2 + 16); + __m128i lo3 = LOAD(k3), hi3 = LOAD((const uint8_t*)k3 + 16); + R256_STORE_RK(rk0, 0, lo0, hi0); + R256_STORE_RK(rk1, 0, lo1, hi1); + R256_STORE_RK(rk2, 0, lo2, hi2); + R256_STORE_RK(rk3, 0, lo3, hi3); + for (size_t r = 0; r < KEY_SCHEDULE_ROUNDS; r++) { + const int rc = r256_rcon[r]; + lo0 = r256_cascade(lo0, r256_g_lo(hi0, rc)); + lo1 = r256_cascade(lo1, r256_g_lo(hi1, rc)); + lo2 = r256_cascade(lo2, r256_g_lo(hi2, rc)); + lo3 = r256_cascade(lo3, r256_g_lo(hi3, rc)); + hi0 = r256_cascade(hi0, r256_g_hi(lo0)); + hi1 = r256_cascade(hi1, r256_g_hi(lo1)); + hi2 = r256_cascade(hi2, r256_g_hi(lo2)); + hi3 = r256_cascade(hi3, r256_g_hi(lo3)); + R256_STORE_RK(rk0, 32 * (r + 1), lo0, hi0); + R256_STORE_RK(rk1, 32 * (r + 1), lo1, hi1); + R256_STORE_RK(rk2, 32 * (r + 1), lo2, hi2); + R256_STORE_RK(rk3, 32 * (r + 1), lo3, hi3); + } +} + +EXPORT void rijndael256_key_schedule_avx(rijndael256_avx_rk_t* roundkeys, const uint8_t key[32]) { + rijndael256_keyexp_x1_enclast(roundkeys, key); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_avx.h b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_avx.h new file mode 100644 index 0000000000..f4bd0c42e5 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_avx.h @@ -0,0 +1,64 @@ +#ifndef RIJNDAEL256_AVX2__H +#define RIJNDAEL256_AVX2__H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#include "sdith_inline.h" + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#include +#else +#define EXPORT +#include "stdint.h" +#endif +#include +#include +#include +#include + +#define Nb 8 +#define Nk 8 +#define Nbytes (Nb*4) +#define Nr 14 + +typedef union { + __m128i v[2]; + uint8_t b[Nbytes]; + } rijndael256_avx_state_t; + +#if Nb != Nk +#error "This implementation expects Nb == Nk." +#endif + +typedef union { + uint8_t v[2][16]; // no alignment assumption shall be made here + uint8_t b[Nbytes]; + } rijndael256_avx_key_t; + +typedef struct { + rijndael256_avx_key_t rk[Nr+1]; +} rijndael256_avx_rk_t; + +EXPORT void rijndael256_key_schedule_avx(rijndael256_avx_rk_t *roundkeys, const uint8_t key[32]); + +// aesenclast-based batched key expansion: expand 1..4 independent rijndael256 keys +// into 1..4 round-key buffers (each RIJNDAEL256_RK_BYTES). Round keys are +// bit-identical to rijndael256_key_schedule_avx (KAT-preserving). +EXPORT void rijndael256_keyexp_x1_enclast(void *rk0, const void *k0); +EXPORT void rijndael256_keyexp_x2_enclast(void *rk0, void *rk1, const void *k0, const void *k1); +EXPORT void rijndael256_keyexp_x3_enclast(void *rk0, void *rk1, void *rk2, // + const void *k0, const void *k1, const void *k2); +EXPORT void rijndael256_keyexp_x4_enclast(void *rk0, void *rk1, void *rk2, void *rk3, // + const void *k0, const void *k1, const void *k2, const void *k3); + +// NOTE: the ECB / CTR encryption cores (rijndael256_ecb_encrypt_{1,2,4}block_avx and +// rijndael256_ctr_encrypt_2blocks_avx) were removed; the CTR path lives in +// rijndael256_ctrle_special_avx2.c (rijndael256_ctrle_nocarry_* / sdith_rij_encN). + +#endif diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle.h b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle.h new file mode 100644 index 0000000000..1ec160cfa9 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle.h @@ -0,0 +1,83 @@ +#ifndef RIJNDAEL256_CTRLE_H +#define RIJNDAEL256_CTRLE_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#include +#else +#define EXPORT +#include "stdint.h" +#endif + +#define RIJNDAEL256_RK_BYTES 480 +#define RIJNDAEL256_RNG_BYTES 608 + +/** (special API) batched key schedule: expand 1..4 independent rijndael256 keys + * into 1..4 round-key buffers (each RIJNDAEL256_RK_BYTES). Output is bit-identical + * to rijndael256_ctrle_set_key (KAT-preserving). The avx2 path uses aesenclast for + * the SubWord step and interleaves the independent keys to hide its latency; the ref + * path just loops the scalar x1. */ +EXPORT void rijndael256_key_schedule_x1_ref(void* rk0, const void* k0); +EXPORT void rijndael256_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void rijndael256_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2); +EXPORT void rijndael256_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); +EXPORT void rijndael256_key_schedule_x1_avx2(void* rk0, const void* k0); +EXPORT void rijndael256_key_schedule_x2_avx2(void* rk0, void* rk1, const void* k0, const void* k1); +EXPORT void rijndael256_key_schedule_x3_avx2(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2); +EXPORT void rijndael256_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3); + +/** (special API) no-carry CTR encryption. Encrypts N consecutive 32-byte blocks: + * out[i] = Rijndael256(round_keys, ctr_block with its low 64 bits += i), i in 0..N-1. + * Only the low 64 bits of the counter increment (no carry). Stateless: ctr_block + * (32 bytes) is not modified. Chains into rijndael256_ctrle_nocarry_nblocks. + * (3/4-block variants added only if they beat the 2-block chaining.) */ +EXPORT void rijndael256_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks); +EXPORT void rijndael256_ctrle_nocarry_1block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_2block_avx2(void* out, const void* round_keys, const void* ctr_block); +EXPORT void rijndael256_ctrle_nocarry_nblocks_avx2(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks); + +/** + * (special API) Rijndael-256 proof-of-work grind over two independent keys. + * The Rijndael-256 analogue of aes128_proofow_grind_avx2. Encrypts the two 32-byte + * plaintext blocks in_pt512 (p0 || p1, 64 bytes) under the two round-key sets rk + * (rk[2], each RIJNDAEL256_RK_BYTES, contiguous = 960 bytes). If the ciphertexts + * satisfy the grinding condition ((c0.lo64 ^ c1.lo64) & mask_w) == 0, success: stores + * the two 32-byte ciphertexts in out_ct512 (c0 || c1), stores the winning counter in + * *in_out_counter, and returns 1. Otherwise increments the counter and the low 64 bits + * of both plaintexts by 1 (no carry into the upper bits) and retries. If the counter + * reaches 2^32 with no hit, stores 2^32 in *in_out_counter and returns 0. The winning + * counter is the smallest one in [initial, 2^32). + */ +EXPORT int rijndael256_proofow_grind_avx2( // + void* out_ct512, // [out] c0 || c1 (64 bytes) satisfying low64(c0 ^ c1) & mask_w == 0 + uint64_t* in_out_counter, // [in/out] starting counter (< 2^32) + const void* in_pt512, // [in] p0 || p1 (64 bytes) the initial plaintexts + const void* rk, // [in] two round-key sets rk[2][RIJNDAEL256_RK_BYTES] (960 bytes) + uint64_t mask_w // [in] the grinding condition +); + +typedef union { + uint64_t v64[4]; + uint8_t v8[32]; +} ctr256_t; + +typedef union { + uint64_t v64[4]; + uint8_t v8[32]; +} ctr256_align32_t __attribute__((aligned(32))); + +#endif // RIJNDAEL256_CTRLE_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle_special_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle_special_avx2.c new file mode 100644 index 0000000000..c2bc7a39bd --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle_special_avx2.c @@ -0,0 +1,168 @@ +/* Batched key schedule + no-carry CTR encryption for Rijndael-256 (AVX/AES-NI). + * + * Round-key layout matches rijndael256_ctrle_set_key_avx2 (i.e. rijndael256_avx_rk_t), + * so these are drop-in / KAT-preserving. The no-carry CTR path and the proof-of-work + * grind both build counter blocks straight in registers and run the rounds over N + * interleaved blocks via sdith_rij_encN (mirroring the aes128 sdith_aes_encN / + * sdith_ctr_lo strategy), avoiding any ECB staging buffer. The no-carry path + * increments only the low 64 bits of the 256-bit counter block. + */ +#include + +#include "rijndael256_avx.h" +#include "rijndael256_ctrle.h" + +/* -------- batched key schedule -------- + * The AVX key expansion uses aesenclast for the SubWord step and interleaves + * independent keys to hide its latency (see rijndael256_keyexp_x*_enclast). */ +void rijndael256_key_schedule_x1_avx2(void* rk0, const void* k0) { rijndael256_keyexp_x1_enclast(rk0, k0); } +void rijndael256_key_schedule_x2_avx2(void* rk0, void* rk1, const void* k0, const void* k1) { + rijndael256_keyexp_x2_enclast(rk0, rk1, k0, k1); +} +void rijndael256_key_schedule_x3_avx2(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2) { + rijndael256_keyexp_x3_enclast(rk0, rk1, rk2, k0, k1, k2); +} +void rijndael256_key_schedule_x4_avx2(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + rijndael256_keyexp_x4_enclast(rk0, rk1, rk2, rk3, k0, k1, k2, k3); +} + +/* -------- no-carry CTR encryption (direct AVX, register states) -------- + * Each 256-bit block is two 128-bit halves (lo = state cols 0..3, hi = cols 4..7); + * only the low 64 bits of lo carry the counter. Round-key layout (rijndael256_avx_rk_t): + * round r half0 at byte 32*r, half1 at 32*r+16; 15 round keys (rounds 0..14). The + * BLEND(BMASK)/SHUF8(RMASK) dance compensates for Rijndael-256's ShiftRows moving bytes + * across the two 128-bit halves. Output is bit-identical to the ECB path (KAT-preserving). */ +enum { R256_ROUNDS = 14 }; + +/* encrypt n (1..4) interleaved blocks: plaintext in (lo[k],hi[k]) -> ciphertext to out. */ +SDITH_ALWAYS_INLINE void sdith_rij_encN(uint8_t* out, const uint8_t* rk, __m128i* lo, __m128i* hi, int n) { + const __m128i RMASK = _mm_set_epi32(0x03020d0c, 0x0f0e0908, 0x0b0a0504, 0x07060100); + const __m128i BMASK = _mm_set_epi32(0x80000000, 0x80800000, 0x80800000, 0x80808000); + + // Round 0: initial xor with the master key. + __m128i k0 = _mm_loadu_si128((const __m128i*)(rk)); + __m128i k1 = _mm_loadu_si128((const __m128i*)(rk + 16)); + for (int k = 0; k < n; k++) { + lo[k] = _mm_xor_si128(lo[k], k0); + hi[k] = _mm_xor_si128(hi[k], k1); + } + // Rounds 1..13: sub bytes / shift rows / mix columns + round key. + for (int r = 1; r < R256_ROUNDS; r++) { + __m128i rk0 = _mm_loadu_si128((const __m128i*)(rk + 32 * r)); + __m128i rk1 = _mm_loadu_si128((const __m128i*)(rk + 32 * r + 16)); + for (int k = 0; k < n; k++) { + __m128i t0 = _mm_shuffle_epi8(_mm_blendv_epi8(lo[k], hi[k], BMASK), RMASK); + __m128i t1 = _mm_shuffle_epi8(_mm_blendv_epi8(hi[k], lo[k], BMASK), RMASK); + lo[k] = _mm_aesenc_si128(t0, rk0); + hi[k] = _mm_aesenc_si128(t1, rk1); + } + } + // Last round: no mix columns. + __m128i rk0 = _mm_loadu_si128((const __m128i*)(rk + 32 * R256_ROUNDS)); + __m128i rk1 = _mm_loadu_si128((const __m128i*)(rk + 32 * R256_ROUNDS + 16)); + for (int k = 0; k < n; k++) { + __m128i t0 = _mm_shuffle_epi8(_mm_blendv_epi8(lo[k], hi[k], BMASK), RMASK); + __m128i t1 = _mm_shuffle_epi8(_mm_blendv_epi8(hi[k], lo[k], BMASK), RMASK); + _mm_storeu_si128((__m128i*)(out + 32 * k), _mm_aesenclast_si128(t0, rk0)); + _mm_storeu_si128((__m128i*)(out + 32 * k + 16), _mm_aesenclast_si128(t1, rk1)); + } +} + +/* block halves for base with only its low 64 bits incremented by i (no carry). */ +SDITH_ALWAYS_INLINE void sdith_rij_ctr_lo(__m128i base_lo, __m128i base_hi, uint64_t i, // + __m128i* lo, __m128i* hi) { + *lo = _mm_add_epi64(base_lo, _mm_set_epi64x(0, (long long)i)); + *hi = base_hi; +} + +void rijndael256_ctrle_nocarry_1block_avx2(void* out, const void* round_keys, const void* ctr_block) { + __m128i lo[1] = {_mm_loadu_si128((const __m128i*)ctr_block)}; + __m128i hi[1] = {_mm_loadu_si128((const __m128i*)((const uint8_t*)ctr_block + 16))}; + sdith_rij_encN((uint8_t*)out, (const uint8_t*)round_keys, lo, hi, 1); +} +void rijndael256_ctrle_nocarry_2block_avx2(void* out, const void* round_keys, const void* ctr_block) { + __m128i base_lo = _mm_loadu_si128((const __m128i*)ctr_block); + __m128i base_hi = _mm_loadu_si128((const __m128i*)((const uint8_t*)ctr_block + 16)); + __m128i lo[2], hi[2]; + sdith_rij_ctr_lo(base_lo, base_hi, 0, &lo[0], &hi[0]); + sdith_rij_ctr_lo(base_lo, base_hi, 1, &lo[1], &hi[1]); + sdith_rij_encN((uint8_t*)out, (const uint8_t*)round_keys, lo, hi, 2); +} +void rijndael256_ctrle_nocarry_nblocks_avx2(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + const uint8_t* rk = (const uint8_t*)round_keys; + uint8_t* o = (uint8_t*)out; + __m128i base_lo = _mm_loadu_si128((const __m128i*)ctr_block); + __m128i base_hi = _mm_loadu_si128((const __m128i*)((const uint8_t*)ctr_block + 16)); + uint64_t i = 0; + for (; i + 4 <= nblocks; i += 4) { + __m128i lo[4], hi[4]; + for (int j = 0; j < 4; j++) sdith_rij_ctr_lo(base_lo, base_hi, i + j, &lo[j], &hi[j]); + sdith_rij_encN(o + 32 * i, rk, lo, hi, 4); + } + int rem = (int)(nblocks - i); + if (rem > 0) { + __m128i lo[4], hi[4]; + for (int j = 0; j < rem; j++) sdith_rij_ctr_lo(base_lo, base_hi, i + j, &lo[j], &hi[j]); + sdith_rij_encN(o + 32 * i, rk, lo, hi, rem); + } +} + +/* -------- proof-of-work grind (2 independent keys) -------- + * Rijndael-256 analogue of aes128_proofow_grind_avx2: the inner loop of the cipher-based + * proofow_grind for cat3/cat5. It encrypts two 32-byte counter blocks p0,p1 under two + * independent round-key sets rk[0],rk[1], incrementing only the low 64 bits of both + * plaintexts by 1 each step (no carry), and stops as soon as ((c0.lo64 ^ c1.lo64) & mask_w) + * == 0. Matches the scalar loop (rijndael256_ctrle_nocarry_1block on each block) bit-for-bit. + * + * Counters are processed a GROUP at a time so each key's encryption batches GROUP blocks + * through sdith_rij_encN (hiding aesenc latency), exactly like the aes128 grind. */ +int rijndael256_proofow_grind_avx2( // + void* out_ct512, // [out] c0 || c1 (64 bytes) satisfying low64(c0 ^ c1) & mask_w == 0 + uint64_t* in_out_counter, // [in/out] starting counter (< 2^32) + const void* in_pt512, // [in] p0 || p1 (64 bytes) the initial plaintexts + const void* rk, // [in] two round-key sets rk[2][RIJNDAEL256_RK_BYTES] (960 bytes) + uint64_t mask_w // [in] 64-bit mask applied to the xor of the ciphertext low words +) { + enum { GROUP = 4 }; + const uint64_t CTR_MAX = UINT64_C(1) << 32; + const uint8_t* rk0 = (const uint8_t*)rk; // rk[0] + const uint8_t* rk1 = (const uint8_t*)rk + RIJNDAEL256_RK_BYTES; // rk[1] + __m128i b0lo = _mm_loadu_si128((const __m128i*)in_pt512); + __m128i b0hi = _mm_loadu_si128((const __m128i*)((const uint8_t*)in_pt512 + 16)); + __m128i b1lo = _mm_loadu_si128((const __m128i*)((const uint8_t*)in_pt512 + 32)); + __m128i b1hi = _mm_loadu_si128((const __m128i*)((const uint8_t*)in_pt512 + 48)); + uint64_t ctr = *in_out_counter; + + uint8_t cbuf0[GROUP * 32], cbuf1[GROUP * 32]; + while (ctr < CTR_MAX) { + uint64_t remaining = CTR_MAX - ctr; + int g = remaining < (uint64_t)GROUP ? (int)remaining : GROUP; + __m128i lo0[GROUP], hi0[GROUP], lo1[GROUP], hi1[GROUP]; + for (int j = 0; j < g; j++) { + sdith_rij_ctr_lo(b0lo, b0hi, (uint64_t)j, &lo0[j], &hi0[j]); // add j to the low 64 bits only + sdith_rij_ctr_lo(b1lo, b1hi, (uint64_t)j, &lo1[j], &hi1[j]); + } + sdith_rij_encN(cbuf0, rk0, lo0, hi0, g); + sdith_rij_encN(cbuf1, rk1, lo1, hi1, g); + // check candidates in increasing-counter order; return the first hit + for (int j = 0; j < g; j++) { + uint64_t x0, x1; + memcpy(&x0, cbuf0 + 32 * j, 8); // low 64 bits of ciphertext block 0 + memcpy(&x1, cbuf1 + 32 * j, 8); // low 64 bits of ciphertext block 1 + if (((x0 ^ x1) & mask_w) == 0) { + memcpy(out_ct512, cbuf0 + 32 * j, 32); + memcpy((uint8_t*)out_ct512 + 32, cbuf1 + 32 * j, 32); + *in_out_counter = ctr + (uint64_t)j; + return 1; + } + } + ctr += (uint64_t)g; + b0lo = _mm_add_epi64(b0lo, _mm_set_epi64x(0, (long long)g)); // advance the low 64 bits (no carry) + b1lo = _mm_add_epi64(b1lo, _mm_set_epi64x(0, (long long)g)); + } + *in_out_counter = CTR_MAX; // no good counter within [initial, 2^32) + return 0; +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle_special_ref.c b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle_special_ref.c new file mode 100644 index 0000000000..e5d0e88341 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rijndael256_ctrle_special_ref.c @@ -0,0 +1,48 @@ +#include + +#include "rijndael256.h" +#include "rijndael256_ctrle.h" + +/* -------- batched key schedule (ref: just loop the scalar x1) -------- */ +EXPORT void rijndael256_key_schedule_x1_ref(void* rk0, const void* k0) { rijndael256_key_schedule_ref(rk0, k0); } +EXPORT void rijndael256_key_schedule_x2_ref(void* rk0, void* rk1, const void* k0, const void* k1) { + rijndael256_key_schedule_ref(rk0, k0); + rijndael256_key_schedule_ref(rk1, k1); +} +EXPORT void rijndael256_key_schedule_x3_ref(void* rk0, void* rk1, void* rk2, // + const void* k0, const void* k1, const void* k2) { + rijndael256_key_schedule_ref(rk0, k0); + rijndael256_key_schedule_ref(rk1, k1); + rijndael256_key_schedule_ref(rk2, k2); +} +EXPORT void rijndael256_key_schedule_x4_ref(void* rk0, void* rk1, void* rk2, void* rk3, // + const void* k0, const void* k1, const void* k2, const void* k3) { + rijndael256_key_schedule_ref(rk0, k0); + rijndael256_key_schedule_ref(rk1, k1); + rijndael256_key_schedule_ref(rk2, k2); + rijndael256_key_schedule_ref(rk3, k3); +} + +/* -------- no-carry CTR encryption (ref) -------- + * block i uses the counter with only its low 64 bits incremented by i; no carry + * into the upper bits (caller's guarantee). */ +static inline void rijndael256_nocarry_ref_impl(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + ctr256_t ctr; + uint8_t* oo = (uint8_t*)out; + memcpy(ctr.v8, ctr_block, 32); + for (uint64_t i = 0; i < nblocks; ++i) { + rijndael256_encrypt_1block_ref(oo + 32 * i, ctr.v8, (const rijndael256_rk_t*)round_keys); + ctr.v64[0] += 1; // low-64 increment only, no middle carry + } +} +EXPORT void rijndael256_ctrle_nocarry_1block_ref(void* out, const void* round_keys, const void* ctr_block) { + rijndael256_nocarry_ref_impl(out, round_keys, ctr_block, 1); +} +EXPORT void rijndael256_ctrle_nocarry_2block_ref(void* out, const void* round_keys, const void* ctr_block) { + rijndael256_nocarry_ref_impl(out, round_keys, ctr_block, 2); +} +EXPORT void rijndael256_ctrle_nocarry_nblocks_ref(void* out, const void* round_keys, const void* ctr_block, + uint64_t nblocks) { + rijndael256_nocarry_ref_impl(out, round_keys, ctr_block, nblocks); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/rsd.c b/src/sig/sdith/sdith_sdith_common_avx2/rsd.c new file mode 100644 index 0000000000..b2007302e4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/rsd.c @@ -0,0 +1,282 @@ +#include +#include + +#include "sdith_prng.h" +#include "sdith_rsd.h" +#include "vole_private.h" + +EXPORT uint64_t rsd_generate_random_instance_tmp_bytes(const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim) { + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, vole_params->LAMBDA, rsd_codim); + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, h_row, 32, rsd_codim_slice); + COMP_SPACE_RETURN(); +} + +/** generate a random rsd instance out of the master key entropy. + * Constant-time in the solution it produces, except for the rejection loop of + * the position sampler (see below). tmp_space holds one expanded H row on + * return: the caller must scrub it. */ +EXPORT void rsd_generate_random_instance_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // prng + matrix-prng family + bitvec_t* y, uint64_t y_bytes, // out: syndrome (ceil(rsd_codim/8) bytes are set) + uint32_t* solution, // out: rsd_w integers in [0,n/w-1] + const seed_t* sk_seed, // in: secret key seed (lambda bits) + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + uint8_t* tmp_space // scratch space +) { + const uint64_t col_bytes = (rsd_codim + 7) >> 3; + CREQUIRE(rsd_n != 0, "empty rsd_n (%" PRId64 ")", rsd_n); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(y_bytes >= col_bytes, "y_bytes too small (%" PRId64 " vs %" PRId64 ")", y_bytes, col_bytes); + CREQUIRE(rsd_n % rsd_w == 0, "rsd_n (%" PRId64 ") is not a multiple of rsd_w (%" PRId64 ")", rsd_n, rsd_w); + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, vole_params->LAMBDA, rsd_codim); + CASSERT(col_bytes <= rsd_codim_slice, "invalid rsd_codim_slice"); + // one H row at a time: the matrix prng draws any row independently, so the + // rsd_w rows y needs cost rsd_w cipher calls instead of the whole matrix. + TMP_SPACE_MAP_ALIGNED(uint8_t*, h_row, 32, rsd_codim_slice); + // sample the solution positions from the keygen prng (the ctr keystream of the + // secret-key seed, read as little-endian uint32s). + keygen_rng_ctx sk_rng; + vole_params->keygen_rng.init(&sk_rng, sk_seed); + // generate the solution vector + const uint32_t npw = rsd_n / rsd_w; + // hit and miss version (the rejection loop is not ct, but a rejected draw is + // discarded and independent of the accepted one, so its count says nothing + // about the solution). The reduction of the accepted draw is ct: it is the + // secret itself. + const uint32_t npw_max = UINT32_MAX - (UINT32_MAX % npw); + for (uint64_t i = 0; i < rsd_w; i++) { + uint32_t pos; + do { + pos = vole_params->keygen_rng.next_u32(&sk_rng); + } while (pos >= npw_max); + uint32_t quo; + vole_params->ct.div_rem_u32(&quo, &solution[i], pos, npw); + } + vole_params->keygen_rng.release(&sk_rng); + // prepare the pk_rng to draw rows of h (row-wise matrix prng) + matrix_rng_t pk_rng; + vole_params->matrix_prg.matrix_rng_init(&pk_rng, pk_seed, rsd_codim); + // Compute y. The plain form of the loop body is: + // if (real_index < rsd_codim) { + // yy ^= single_bit_at(real_index) // the identity block of H + // } else { + // yy ^= get_pk_row(real_index - rsd_codim) // the random block of H + // } + // but real_index is secret, so the test may not be branched on: both arms run + // for every i, and a mask keeps the one that counts. The extra cost is one + // cipher row per identity-block hit -- a handful. + memset(y, 0, y_bytes); + for (uint64_t i = 0; i < rsd_w; i++) { + const uint64_t real_index = i * npw + solution[i]; + const uint64_t in_id = vole_params->ct.mask_lt(real_index, rsd_codim); // ~0 on the identity block + const uint64_t in_rnd = ~in_id; // ~0 on the random block + // else-arm: draw the row unconditionally (index clamped to 0 when unused, + // so the draw itself reveals nothing) and xor it under the mask + vole_params->matrix_prg.matrix_rng_get_row(&pk_rng, h_row, (real_index - rsd_codim) & in_rnd); + vole_params->ct.bitvec_xor_to_masked(y, col_bytes, h_row, in_rnd); + // then-arm: flip bit real_index, at a secret position (clamped to 0 when + // unused, the same way as the else-arm: the xor is a no-op under a zero + // mask, but the position must stay inside y for the debug range check) + vole_params->ct.bitvec_xorbit(y, col_bytes, real_index & in_id, in_id); + } + vole_params->matrix_prg.matrix_rng_release(&pk_rng); +} + +/** expand the public key from the pubkey seed */ +EXPORT void rsd_expand_public_key_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // matrix-prng family + bitmat_t* h, uint64_t h_slice_bytes, // out: (rsd_n - rsd_codim) x rsd_n matrix + const seed_t* h_seed // in: pubkey seed (lambda bits) +) { + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, lambda, rsd_codim); + const uint64_t row_out_bytes = rsd_codim_limbs * lambda_bytes; // matrix_prg row size + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + CREQUIRE(h_slice_bytes >= row_out_bytes, // + "h_slice_bytes too small (%" PRId64 " vs %" PRId64 ")", h_slice_bytes, row_out_bytes); + const uint64_t n_minus_k = rsd_n - rsd_codim; + memset(h, 0, n_minus_k * h_slice_bytes); + // Each H row is one matrix_prg row (rsd_codim bits, bits beyond that masked to + // zero, padded to rsd_codim_limbs limbs). The rows are independent, so we + // write each directly into its (block-aligned) slice of h. + matrix_rng_t h_rng; + vole_params->matrix_prg.matrix_rng_init(&h_rng, h_seed, rsd_codim); + uint8_t* const hh = (uint8_t*)h; + if (h_slice_bytes == rsd_codim_slice) { + // the prng rows tile h exactly: the whole matrix is a single batch, written + // in place (h holds the expanded matrix anyway, so this costs no extra RAM). + vole_params->matrix_prg.matrix_rng_get_rows(&h_rng, hh, 0, n_minus_k); + } else { + // h is laid out with wider slices than the prng row size: one row at a time + // so the extra padding bytes of each slice stay zero. + for (uint64_t i = 0; i < n_minus_k; i++) { + vole_params->matrix_prg.matrix_rng_get_row(&h_rng, hh + h_slice_bytes * i, i); + } + } + vole_params->matrix_prg.matrix_rng_release(&h_rng); +} + +EXPORT uint64_t rsd_public_key_times_challenge_tmp_bytes(const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim) { + CREQUIRE(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + const uint64_t lambda = vole_params->LAMBDA; + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, lambda, rsd_codim); + // the scratch holds the pre-processed challenge, which y_full aliases, so it + // must also be wide enough for one slice. + const uint64_t scratch_bytes = matrix_rng_prep_chall_nelems(rsd_codim) * vole_params->lambda_bytes; + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint8_t*, scratch, 32, scratch_bytes < rsd_codim_slice ? rsd_codim_slice : scratch_bytes); + COMP_SPACE_RETURN(); +} + +/** expand and multiply the public key with challenge points */ +EXPORT void rsd_public_key_times_challenge_ref( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + flambda_t* chall_a_H, // out: n elements + flambda_t* chall_a_y, // out: 1 element + const flambda_t* chall_a, // in: rsd_codim_limbs elements + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + const bitvec_t* y, // in: pubkey y (rsd_codim bits padded with zeros) + uint8_t* tmp_space // scratch space +) { + static const uint64_t TWO[] = {2, 0, 0, 0}; + CASSERT(rsd_n >= rsd_codim, "rsd_n (%" PRId64 ") is not larger than codim (%" PRId64 ")", rsd_n, rsd_codim); + CASSERT(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CASSERT(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + uint64_t rsd_codim_limbs, rsd_codim_slice; + compute_rsd_codim_slice(&rsd_codim_limbs, &rsd_codim_slice, lambda, rsd_codim); + const uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + const uint64_t rsd_padding_bytes = rsd_codim_limbs * lambda_bytes - rsd_codim_bytes; + const uint64_t n_minus_k = rsd_n - rsd_codim; + const uint8_t h_last_mask = 0xFF >> ((-rsd_codim) & 7); + const uint64_t scratch_bytes = matrix_rng_prep_chall_nelems(rsd_codim) * lambda_bytes; + TMP_SPACE_MAP_ALIGNED(uint8_t*, scratch, 32, + scratch_bytes < rsd_codim_slice ? rsd_codim_slice : scratch_bytes); + uint8_t* y_full = scratch; // alias (y_full fits in rsd_codim_slice by definition) + +#ifndef NDEBUG + uint64_t leftover_bits = rsd_codim & 7; + uint8_t* y_u8 = (uint8_t*)y; + if (leftover_bits) { + uint64_t mask = ((1 << (8 - leftover_bits)) - 1) << leftover_bits; + uint64_t idx = ((rsd_codim + 7) >> 3) - 1; + CASSERT((y_u8[idx] & mask) == 0, "empty bits of y are not zero-ed out"); + } +#endif // NDEBUG + + // deal with y (chall_a_y = ) + memcpy(y_full, y, rsd_codim_bytes); + y_full[rsd_codim_bytes - 1] &= h_last_mask; + memset(y_full + rsd_codim_bytes, 0, rsd_padding_bytes); + vole_params->flambda_dot_product(chall_a_y, y_full, chall_a, rsd_codim_limbs); + // deal with the id block of H + uint8_t* dest = chall_a_H; + { + uint64_t s = rsd_codim; + for (uint64_t i = 0; i < rsd_codim_limbs; i++) { + uint64_t block_s = lambda < s ? lambda : s; + vole_params->flambda_set(dest, chall_a + i * lambda_bytes); + dest += lambda_bytes; + for (uint64_t j = 1; j < block_s; j++) { + vole_params->flambda_product(dest, dest - lambda_bytes, TWO); + dest += lambda_bytes; + } + s -= block_s; + } + CASSERT(dest == chall_a_H + rsd_codim * lambda_bytes, "bug!"); + CASSERT(s == 0, "bug!"); + } + // deal with the regular rows of H. H is never materialised: the whole block is + // one fused call that generates each row and multiplies it by the challenge + // without the row ever reaching memory. + matrix_rng_t h_rng; + vole_params->matrix_prg.matrix_rng_init(&h_rng, pk_seed, rsd_codim); + vole_params->matrix_prg.matrix_rng_preprocess_chall(&h_rng, scratch, chall_a); + vole_params->matrix_prg.matrix_rng_rows_times_chall(&h_rng, dest, scratch, 0, n_minus_k); + vole_params->matrix_prg.matrix_rng_release(&h_rng); +#ifndef NDEBUG + dest += n_minus_k * lambda_bytes; + CASSERT(dest == chall_a_H + rsd_n * lambda_bytes, "bug!"); +#endif // NDEBUG +} + +/** unary encoding of the solution (for mux circuits). Constant-time in the + * solution: the dimensions and the arities are public, only the coefficients + * are not. */ +EXPORT void rsd_encode_solution_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // ct helpers + uint64_t mux_depth, const uint64_t* mux_arities, // mux depth and arities + bitvec_t* encoded_solution, uint64_t encoded_solution_bytes, // encoded solution + const uint32_t* solution // in: solution coefficients +) { + CREQUIRE(rsd_n != 0, "empty rsd_n (%" PRId64 ")", rsd_n); + CREQUIRE(rsd_w != 0, "empty rsd_w (%" PRId64 ")", rsd_w); + CREQUIRE(rsd_codim != 0, "empty rsd_codim (%" PRId64 ")", rsd_codim); + CREQUIRE(mux_depth != 0, "empty mux_depth (%" PRId64 ")", mux_depth); + CREQUIRE(rsd_n % rsd_w == 0, "rsd_n (%" PRId64 ") is not a multiple of rsd_w (%" PRId64 ")", rsd_n, rsd_w); + const uint64_t npw = rsd_n / rsd_w; + uint64_t mux_size = 1; + uint64_t mux_inputs = 0; + for (uint64_t j = 0; j < mux_depth; j++) { + const uint64_t arj = mux_arities[j]; + CREQUIRE(arj >= 2, "mux_arity[%" PRId64 "]=%" PRId64 " too small", j, arj); + // the one-hot field of a level must fit in the uint32 bitvec_xoru32 takes + CREQUIRE(arj < 32, "mux_arity[%" PRId64 "]=%" PRId64 " too large", j, arj); + mux_inputs += arj - 1; + mux_size *= arj; + } + CREQUIRE(mux_size >= npw, "mux arities too small (max_tree_size: %" PRId64 " vs. %" PRId64 ")", mux_size, npw); + uint64_t encoded_solution_actual_bytes = (mux_inputs * rsd_w + 7) >> 3; + CREQUIRE(encoded_solution_bytes >= encoded_solution_actual_bytes, // + "encoded_solutions too small (size: %" PRId64 " vs. min size: %" PRId64 ")", // + encoded_solution_bytes, encoded_solution_actual_bytes); + uint8_t* const sol = encoded_solution; + memset(sol, 0, encoded_solution_bytes); + // Every (element, mux level) owns a field of arj-1 bits at a PUBLIC offset + // bitpos, since bitpos only ever advances by the public arj-1. Inside that + // field the plain form of the body is: + // if (sij != 0) { sol ^= single_bit_at(bitpos + sij - 1) } + // with sij secret. Rather than address that bit, we build the one-hot field + // as a value and xor the whole field in at its public offset: the address is + // public, only the bits are secret. + uint64_t bitpos = 0; + for (uint64_t i = 0; i < rsd_w; i++) { + uint32_t si = solution[i]; + for (uint64_t j = 0; j < mux_depth; j++) { + const uint64_t arj = mux_arities[j]; + uint32_t sij; + vole_params->ct.div_rem_u32(&si, &sij, si, (uint32_t)arj); + // (sij == 0) ? 0 : 1 << (sij - 1), with no test: the >> 1 turns the sij=0 + // case into 0 by itself. arj < 32 keeps the shift in range for every sij. + // The shift amount is secret, which is fine: a shift by a register count + // is data-independent on every target here (x86-64 SHL/SHR, aarch64 LSL). + const uint32_t one_hot = (UINT32_C(1) << sij) >> 1; + vole_params->ct.bitvec_xoru32(sol, encoded_solution_bytes, bitpos, arj - 1, one_hot); + bitpos += arj - 1; + } + CASSERT(si == 0, "bug"); + } + CASSERT(bitpos == rsd_w * mux_inputs, "bug"); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_algebra.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_algebra.h new file mode 100644 index 0000000000..110c3c2dbb --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_algebra.h @@ -0,0 +1,43 @@ +#ifndef SDITH_ALGEBRA_H +#define SDITH_ALGEBRA_H + +// This file contains the declaration of all algebra functions over vectors and matrices over F2 + +#include "commons.h" + +/** vector addition over F2 */ +EXPORT void bitvec_xor_to_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* b); +EXPORT void bitvec_xor_ref(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b); +EXPORT void bitvec_xor_to_avx2(uint64_t bytelen, bitvec_t* res, const bitvec_t* b); +EXPORT void bitvec_xor_avx2(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b); +/** cascade vector addition over F2 (b^=c then a^=b) */ +EXPORT void bitvec_cascade_xor_to_ref(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a); +EXPORT void bitvec_cascade_xor_to_avx2(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a); + +/** matrix vector product over F2 */ +// (expect nrows between 120 and 260, ncols can be restricted to a multiple of 8) +EXPORT void matrix_vector_product_f2_ref( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b); // bit vector of size ncols +EXPORT void matrix_vector_product_f2_avx2( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b); // bit vector of size ncols + +/** matrix vector product over F2 */ +// (expect nrows between 120 and 260, ncols can be restricted to a multiple of 8. lambda will be 128, 192, or 256) +EXPORT void matrix_f2_times_vector_flambda_ref( // + uint64_t lambda, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b); // vector of size ncols +EXPORT void matrix_f2_times_vector_flambda_avx2( // + uint64_t lambda, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b); // vector of size ncols + +#endif // SDITH_ALGEBRA_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_arithmetic.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_arithmetic.h new file mode 100644 index 0000000000..07e53aafe9 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_arithmetic.h @@ -0,0 +1,185 @@ +#ifndef SDITH_ARITHMETIC_H +#define SDITH_ARITHMETIC_H + +// This file contains the declaration of all aritmetic functions over F_2^128, F_2^192, and F_2^256 + +#include "commons.h" + +typedef union gf128_t gf128 __attribute((aligned(16))); +typedef union gf192_t gf192 __attribute((aligned(8))); +typedef union gf256_t gf256 __attribute((aligned(32))); + +/* res = a [requires a flambda_t version] */ +EXPORT void gf128_set_ref(gf128* res, const gf128* a); +EXPORT void gf192_set_ref(gf192* res, const gf192* a); +EXPORT void gf256_set_ref(gf256* res, const gf256* a); +EXPORT void gf128_flambda_set_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf192_flambda_set_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf256_flambda_set_ref(flambda_t* res, const flambda_t* a); + +/* res = a + b [requires a flambda_t version] */ +EXPORT void gf128_sum_ref(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf128_sum_avx2(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf256_sum_ref(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_sum_avx2(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf128_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf128_flambda_sum_avx2(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_sum_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_sum_avx2(flambda_t* res, const flambda_t* a, const flambda_t* b); + +/* res = a * b [requires a flambda_t version] */ +EXPORT void gf128_product_ref(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf128_product_f2_ref(gf128* res, const gf128* a, const gf128* b_f2); +EXPORT void gf128_product_pclmul(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf128_product_pclmul_f2(gf128* res, const gf128* a, const gf128* b); +EXPORT void gf192_product_ref(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf192_product_f2_ref(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf192_product_pclmul(gf192* res, const gf192* a, const gf192* b); +EXPORT void gf256_product_ref(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_product_f2_ref(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_product_pclmul(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf256_product_pclmul_f2(gf256* res, const gf256* a, const gf256* b); +EXPORT void gf128_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf128_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b_f2); +EXPORT void gf128_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf128_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf192_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_f2_ref(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_pclmul(flambda_t* res, const flambda_t* a, const flambda_t* b); +EXPORT void gf256_flambda_product_pclmul_f2(flambda_t* res, const flambda_t* a, const flambda_t* b); + +/* res = sum_{i=0}^{size-1} x[i] * y[i] [requires a flambda_t version] */ +EXPORT void gf128_dot_product_ref(gf128* res, const gf128* x, const gf128* y, const uint64_t size); +EXPORT void gf128_dot_product_pclmul(gf128* res, const gf128* x, const gf128* y, const uint64_t size); +EXPORT void gf192_dot_product_ref(gf192* res, const gf192* x, const gf192* y, const uint64_t size); +EXPORT void gf192_dot_product_pclmul(gf192* res, const gf192* x, const gf192* y, const uint64_t size); +EXPORT void gf256_dot_product_ref(gf256* res, const gf256* x, const gf256* y, const uint64_t size); +EXPORT void gf256_dot_product_pclmul(gf256* res, const gf256* x, const gf256* y, const uint64_t size); +EXPORT void gf128_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf128_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf192_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf192_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf256_flambda_dot_product_ref(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); +EXPORT void gf256_flambda_dot_product_pclmul(flambda_t* res, const flambda_t* x, const flambda_t* y, const uint64_t size); + +/* res += sum_{i=0}^{size-1} x[i . x_byte_slice] * y[i] (x is strided, y is contiguous) + * x_byte_slice is a byte stride, and must be a multiple of the element size. [requires a flambda_t version] */ +EXPORT void gf128_dot_product_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size); +EXPORT void gf128_dot_product_acc_pclmul(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y, + uint64_t size); +EXPORT void gf192_dot_product_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size); +EXPORT void gf192_dot_product_acc_pclmul(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y, + uint64_t size); +EXPORT void gf256_dot_product_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size); +EXPORT void gf256_dot_product_acc_pclmul(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y, + uint64_t size); +EXPORT void gf128_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf128_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf192_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf192_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf256_flambda_dot_product_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); +EXPORT void gf256_flambda_dot_product_acc_pclmul(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y, uint64_t size); + +/* res += sum_{i=0}^{size-1} x[i . x_byte_slice] * y_f2[i], where every y_f2[i] is 0 or 1. + * Same conventions as the *_acc dot products above. [requires a flambda_t version] */ +EXPORT void gf128_dot_product_f2_acc_ref(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size); +EXPORT void gf128_dot_product_f2_acc_avx2(gf128* res, const gf128* x, uint64_t x_byte_slice, const gf128* y_f2, + uint64_t size); +EXPORT void gf192_dot_product_f2_acc_ref(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size); +EXPORT void gf192_dot_product_f2_acc_avx2(gf192* res, const gf192* x, uint64_t x_byte_slice, const gf192* y_f2, + uint64_t size); +EXPORT void gf256_dot_product_f2_acc_ref(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size); +EXPORT void gf256_dot_product_f2_acc_avx2(gf256* res, const gf256* x, uint64_t x_byte_slice, const gf256* y_f2, + uint64_t size); +EXPORT void gf128_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf128_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf192_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf192_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf256_flambda_dot_product_f2_acc_ref(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +EXPORT void gf256_flambda_dot_product_f2_acc_avx2(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); + +/* res = a^-1 [requires a flambda_t version] */ +EXPORT void gf128_inverse_ref(gf128* res, const gf128* a); +EXPORT void gf128_inverse_pclmul(gf128* res, const gf128* a); +EXPORT void gf192_inverse_ref(gf192* res, const gf192* a); +EXPORT void gf192_inverse_pclmul(gf192* res, const gf192* a); +EXPORT void gf256_inverse_ref(gf256* res, const gf256* a); +EXPORT void gf256_inverse_pclmul(gf256* res, const gf256* a); +EXPORT void gf128_flambda_inverse_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf128_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a); +EXPORT void gf192_flambda_inverse_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf192_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a); +EXPORT void gf256_flambda_inverse_ref(flambda_t* res, const flambda_t* a); +EXPORT void gf256_flambda_inverse_pclmul(flambda_t* res, const flambda_t* a); + +/** Combine lambda bit Vole into a big field Vole */ +/** res = sum 2^i.x_i [requires a flambda_t version] */ +EXPORT void gf128_sum_pow2_naive(gf128* res, const gf128* x); +EXPORT void gf128_sum_pow2_ref(gf128* res, const gf128* x); +EXPORT void gf192_sum_pow2_naive(gf192* res, const gf192* x); +EXPORT void gf192_sum_pow2_ref(gf192* res, const gf192* x); +EXPORT void gf192_sum_pow2_avx2(gf192* res, const gf192* x); +EXPORT void gf256_sum_pow2_naive(gf256* res, const gf256* x); +EXPORT void gf256_sum_pow2_ref(gf256* res, const gf256* x); +EXPORT void gf128_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x); +// EXPORT void gf128_flambda_sum_pow2_avx2(flambda_t* res, const flambda_t* x); +EXPORT void gf192_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x); +// EXPORT void gf192_flambda_sum_pow2_avx2(flambda_t* res, const flambda_t* x); +EXPORT void gf256_flambda_sum_pow2_ref(flambda_t* res, const flambda_t* x); +// EXPORT void gf256_flambda_sum_pow2_avx2(flambda_t* res, const flambda_t* x); + +/** sum_{i=0 to k-1} x_i . 2^{k.i} [requires flambda version] */ +EXPORT void gf128_echelon_pow2_naive(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_echelon_pow2_ref(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_echelon_pow2_avx(uint64_t k, gf128* res, const gf128* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_echelon_pow2_naive(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_echelon_pow2_ref(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_echelon_pow2_avx(uint64_t k, gf192* res, const gf192* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_echelon_pow2_naive(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_echelon_pow2_ref(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_echelon_pow2_avx(uint64_t k, gf256* res, const gf256* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf128_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf192_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_flambda_echelon_pow2_ref(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); +EXPORT void gf256_flambda_echelon_pow2_avx(uint64_t k, flambda_t* res, const flambda_t* x, uint64_t x_size, uint64_t x_byte_slice); + +/** This function takes a matrix of B x B bits, and transposes it */ +EXPORT void transpose_128_128_naive(void* out, const void* in); +EXPORT void transpose_192_192_naive(void* out, const void* in); +EXPORT void transpose_256_256_naive(void* out, const void* in); +EXPORT void transpose_128_128_ref(void* x); +EXPORT void transpose_192_192_ref(void* x); +EXPORT void transpose_256_256_ref(void* x); +EXPORT void transpose_128_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_192_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_256_L_naive(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_128_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_192_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice); +EXPORT void transpose_256_L_ref(void* out, const void* in, uint64_t L, uint64_t Lslice); + +#endif // SDITH_ARITHMETIC_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_ct_utils.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_ct_utils.h new file mode 100644 index 0000000000..737cd7b559 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_ct_utils.h @@ -0,0 +1,108 @@ +#ifndef SDITH_CT_UTILS_H +#define SDITH_CT_UTILS_H + +// Constant-time helpers. +// +// Scope: this is a digital signature, so the verifier only ever touches public +// data and has nothing to protect. Only the prover side must be constant-time, +// and only with respect to the secret key (the rsd solution), the keygen +// entropy, and the root ggm seed. Everything derived from the public key, from +// the message, or from the parameters may branch and index freely. +// +// "Constant-time" here means: no branch and no memory address depends on a +// secret. Secret *values* may flow through arithmetic and through AES-NI, which +// are data-independent. The idiom is a mask -- 0 or ~0 (all ones) -- built from +// a secret comparison and then AND-ed into the value that would otherwise have +// been selected by an `if`. +// +// As everywhere else in this codebase there is a _ref and an _avx +// implementation of each function, and as everywhere else the _ref one is the +// readable definition rather than the fast (here: rather than the hardened) +// one: it is written the way the algorithm reads, and a C compiler is free to +// turn its masks back into branches. The _avx implementations are the ones that +// are actually constant-time -- they pin the mask arithmetic down in inline +// assembly, which the compiler cannot rewrite. The two agree bit for bit, so +// the _ref ones stay usable as the test oracle. +// +// Functions are suffixed _ct_ref / _ct_avx; inside the ct_utils struct the _ct +// is implied and dropped. + +#include "commons.h" + +// Naming convention below: an input that may carry a secret is prefixed +// secret_, one that is required to be public is prefixed public_. Lengths +// (bytelen) are public everywhere in this codebase and are left unprefixed. +// The distinction is load-bearing: bitvec_xoru32 may only be handed a PUBLIC +// bit position (it writes at that address), while bitvec_xorbit accepts a +// SECRET one (and pays a full sweep of the vector for it). + +/** mask_lt: -(a < b), i.e. ~0 when a < b and 0 otherwise (unsigned) */ +/** mask_eq: -(a == b), i.e. ~0 when a == b and 0 otherwise */ +typedef uint64_t CT_MASK_F(uint64_t secret_a, uint64_t secret_b); + +/** q = n / d and r = n % d. */ +typedef void CT_DIV_REM_U32_F(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d); + +/** res ^= b & mask, over bytelen bytes. mask is 0 or ~0 (a whole-vector select). */ +typedef void CT_BITVEC_XOR_TO_MASKED_F(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask); + +/** res[public_bitpos .. public_bitpos+public_nbits) ^= the low public_nbits + * bits of value (public_nbits <= 32). Only the value is secret. */ +typedef void CT_BITVEC_XORU32_F(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value); + +/** res[secret_bitpos] ^= 1, if mask is ~0 (nothing if mask is 0). */ +typedef void CT_BITVEC_XORBIT_F(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask); + +EXPORT uint64_t mask_lt_ct_ref(uint64_t secret_a, uint64_t secret_b); +EXPORT uint64_t mask_eq_ct_ref(uint64_t secret_a, uint64_t secret_b); +EXPORT void div_rem_u32_ct_ref(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d); +EXPORT void bitvec_xor_to_masked_ct_ref(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask); +EXPORT void bitvec_xoru32_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value); +EXPORT void bitvec_xorbit_ct_ref(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask); + +#ifdef __x86_64__ +EXPORT uint64_t mask_lt_ct_avx(uint64_t secret_a, uint64_t secret_b); +EXPORT uint64_t mask_eq_ct_avx(uint64_t secret_a, uint64_t secret_b); +EXPORT void div_rem_u32_ct_avx(uint32_t* q, uint32_t* r, uint32_t secret_n, uint32_t public_d); +EXPORT void bitvec_xor_to_masked_ct_avx(bitvec_t* res, uint64_t bytelen, const bitvec_t* secret_b, + uint64_t secret_mask); +EXPORT void bitvec_xoru32_ct_avx(bitvec_t* res, uint64_t bytelen, uint64_t public_bitpos, uint64_t public_nbits, + uint32_t secret_value); +EXPORT void bitvec_xorbit_ct_avx(bitvec_t* res, uint64_t bytelen, uint64_t secret_bitpos, uint64_t secret_mask); +#endif + +typedef struct ct_utils_t { + CT_MASK_F* mask_lt; + CT_MASK_F* mask_eq; + CT_DIV_REM_U32_F* div_rem_u32; + CT_BITVEC_XOR_TO_MASKED_F* bitvec_xor_to_masked; + CT_BITVEC_XORU32_F* bitvec_xoru32; + CT_BITVEC_XORBIT_F* bitvec_xorbit; +} ct_utils; + +static const ct_utils ct_utils_ref = { + mask_lt_ct_ref, // + mask_eq_ct_ref, // + div_rem_u32_ct_ref, // + bitvec_xor_to_masked_ct_ref, // + bitvec_xoru32_ct_ref, // + bitvec_xorbit_ct_ref, // +}; +// ONLY_REF_IMPLEMENTATION drops the *_avx2.c translation units, so this table +// would hold undefined references: it is only compiled with the avx2 backend. +#if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) +static const ct_utils ct_utils_avx = { + mask_lt_ct_avx, // + mask_eq_ct_avx, // + div_rem_u32_ct_avx, // + bitvec_xor_to_masked_ct_avx, // + bitvec_xoru32_ct_avx, // + bitvec_xorbit_ct_avx, // +}; +#endif + +#endif // SDITH_CT_UTILS_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_inline.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_inline.h new file mode 100644 index 0000000000..b55b41d2ca --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_inline.h @@ -0,0 +1,21 @@ +#ifndef sdith_inline_H +#define sdith_inline_H + +// Force inlining of a file-local helper. +// Designed to be behaviourally consistent across different compilers. +#if defined(_MSC_VER) +#define SDITH_ALWAYS_INLINE static __forceinline +#elif defined(__GNUC__) || defined(__clang__) +#define SDITH_ALWAYS_INLINE static inline __attribute__((__always_inline__)) +#else +#define SDITH_ALWAYS_INLINE static inline +#endif + +// Mark a variable as possibly unused, to suppress compiler warnings. +#if defined(__GNUC__) || defined(__clang__) +#define SDITH_MAYBE_UNUSED __attribute__((__unused__)) +#else +#define SDITH_MAYBE_UNUSED +#endif + +#endif // sdith_inline_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_namespace.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_namespace.h new file mode 100644 index 0000000000..8691c1c0e4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_namespace.h @@ -0,0 +1,528 @@ +#ifndef SDITH_NAMESPACE_H +#define SDITH_NAMESPACE_H + +/** + * Generated by integration/liboqs/gen_namespace.sh. Do not edit by hand. + * + * liboqs compiles the shared SDitH sources once and links every scheme variant + * against that single copy, so these symbols are global in liboqs' own library. + */ + +#ifdef APPLY_NAMESPACE + +#ifndef concat2 +#define _concat2(a, b) a##b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_NAMESPACE_FOR_LIBOQS(s) concat2(APPLY_NAMESPACE, s) + +#define CAT1_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_CIPHERPOW_PARAMETERS) +#define CAT1_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_PARAMETERS) +#define CAT1_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_CIPHERPOW_PARAMETERS) +#define CAT1_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_PARAMETERS) +#define CAT3_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_CIPHERPOW_PARAMETERS) +#define CAT3_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_PARAMETERS) +#define CAT3_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_CIPHERPOW_PARAMETERS) +#define CAT3_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_PARAMETERS) +#define CAT5_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_CIPHERPOW_PARAMETERS) +#define CAT5_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_PARAMETERS) +#define CAT5_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_CIPHERPOW_PARAMETERS) +#define CAT5_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_PARAMETERS) +#define FLAMBDA_2P32 SDITH_NAMESPACE_FOR_LIBOQS(FLAMBDA_2P32) +#define GF128_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF128_ONE) +#define GF128_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF128_ZERO) +#define GF192_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF192_ONE) +#define GF192_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF192_ZERO) +#define GF256_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF256_ONE) +#define GF256_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF256_ZERO) +#define HASH_AUX_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_AUX_PREFIX) +#define HASH_BAVC_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_BAVC_PREFIX) +#define HASH_LINES_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_LINES_PREFIX) +#define HASH_PIOP_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_PIOP_PREFIX) +#define PROOFOW_CTR_REVEALED_BYTES SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_CTR_REVEALED_BYTES) +#define PROOFOW_H0_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H0_PREFIX) +#define PROOFOW_H1_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H1_PREFIX) +#define aes128_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_avx2) +#define aes128_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_ref) +#define aes128_ctrle_nocarry_2blk_x4keys_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2blk_x4keys_avx2) +#define aes128_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_avx2) +#define aes128_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_ref) +#define aes128_ctrle_nocarry_3blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_avx2) +#define aes128_ctrle_nocarry_3blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_ref) +#define aes128_ctrle_nocarry_4blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_avx2) +#define aes128_ctrle_nocarry_4blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_ref) +#define aes128_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_avx2) +#define aes128_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_ref) +#define aes128_ctrle_set_key_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_set_key_avx2) +#define aes128_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_encrypt_1block_ref) +#define aes128_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_avx2) +#define aes128_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_ref) +#define aes128_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_avx2) +#define aes128_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_ref) +#define aes128_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_avx2) +#define aes128_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_ref) +#define aes128_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_avx2) +#define aes128_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_ref) +#define aes128_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(aes128_keyexp_x4_enclast) +#define aes128_prepare_rk_buffer SDITH_NAMESPACE_FOR_LIBOQS(aes128_prepare_rk_buffer) +#define aes128_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_proofow_grind_avx2) +#define aes128_release_key SDITH_NAMESPACE_FOR_LIBOQS(aes128_release_key) +#define aes128_set_key_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_ref) +#define aes128_set_key_reuse_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_reuse_ref) +#define binval_of SDITH_NAMESPACE_FOR_LIBOQS(binval_of) +#define binval_of_compat SDITH_NAMESPACE_FOR_LIBOQS(binval_of_compat) +#define bit_of SDITH_NAMESPACE_FOR_LIBOQS(bit_of) +#define bitmat_get_value SDITH_NAMESPACE_FOR_LIBOQS(bitmat_get_value) +#define bitvec_cascade_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_avx2) +#define bitvec_cascade_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_ref) +#define bitvec_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(bitvec_is_zero_nonct) +#define bitvec_xor_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_avx2) +#define bitvec_xor_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_ref) +#define bitvec_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_avx2) +#define bitvec_xor_to_masked_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_avx) +#define bitvec_xor_to_masked_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_ref) +#define bitvec_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_ref) +#define bitvec_xorbit_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_avx) +#define bitvec_xorbit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_ref) +#define bitvec_xoru32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_avx) +#define bitvec_xoru32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_ref) +#define both_vole_consistency_check_matrix SDITH_NAMESPACE_FOR_LIBOQS(both_vole_consistency_check_matrix) +#define bytes_of_proofow_ctx_cipher_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat1) +#define bytes_of_proofow_ctx_cipher_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat3) +#define bytes_of_proofow_ctx_cipher_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat5) +#define bytes_of_proofow_ctx_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat1) +#define bytes_of_proofow_ctx_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat3) +#define bytes_of_proofow_ctx_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat5) +#define ceil_log2i SDITH_NAMESPACE_FOR_LIBOQS(ceil_log2i) +#define compute_extended_parameters SDITH_NAMESPACE_FOR_LIBOQS(compute_extended_parameters) +#define compute_rsd_codim SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim) +#define compute_rsd_codim_slice SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim_slice) +#define compute_tweaked_salts SDITH_NAMESPACE_FOR_LIBOQS(compute_tweaked_salts) +#define delta1_from_delta0_ref SDITH_NAMESPACE_FOR_LIBOQS(delta1_from_delta0_ref) +#define delta2_from_delta1_ref SDITH_NAMESPACE_FOR_LIBOQS(delta2_from_delta1_ref) +#define div_rem_u32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_avx) +#define div_rem_u32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_ref) +#define estimate_topen SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen) +#define estimate_topen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen_tmp_bytes) +#define extend_leaf_seed_cat1_aes128_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_avx2) +#define extend_leaf_seed_cat1_aes128_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_ref) +#define extend_leaf_seed_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_avx2) +#define extend_leaf_seed_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_ref) +#define extend_leaf_seed_cat3_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_avx2) +#define extend_leaf_seed_cat3_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_ref) +#define extend_leaf_seed_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_avx2) +#define extend_leaf_seed_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_ref) +#define extend_leaf_seed_cat5_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_avx2) +#define extend_leaf_seed_cat5_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_ref) +#define extend_leaf_seed_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_avx2) +#define extend_leaf_seed_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_ref) +#define extended_node_seed_bytes_cat1_aes128 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat1_aes128) +#define extended_node_seed_bytes_cat3_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat3_rijndael256) +#define extended_node_seed_bytes_cat5_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat5_rijndael256) +#define extract_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(extract_kappabit_uint) +#define extseed_buf_noop SDITH_NAMESPACE_FOR_LIBOQS(extseed_buf_noop) +#define flambda_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(flambda_is_zero_nonct) +#define flambda_power SDITH_NAMESPACE_FOR_LIBOQS(flambda_power) +#define floor_log2i SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i) +#define floor_log2i_compat SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i_compat) +#define full_ggm_tree_open_sibling_path_from_root SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root) +#define full_ggm_tree_open_sibling_path_from_root_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root_tmp_bytes) +#define gf128_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_pclmul) +#define gf128_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_ref) +#define gf128_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_avx2) +#define gf128_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_ref) +#define gf128_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_pclmul) +#define gf128_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_ref) +#define gf128_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_avx) +#define gf128_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_naive) +#define gf128_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_ref) +#define gf128_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_pclmul) +#define gf128_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_ref) +#define gf128_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_avx2) +#define gf128_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_ref) +#define gf128_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_pclmul) +#define gf128_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_ref) +#define gf128_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_avx) +#define gf128_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_ref) +#define gf128_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_pclmul) +#define gf128_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_ref) +#define gf128_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_f2_ref) +#define gf128_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul) +#define gf128_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul_f2) +#define gf128_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_ref) +#define gf128_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_set_ref) +#define gf128_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_avx2) +#define gf128_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_pow2_ref) +#define gf128_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_ref) +#define gf128_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_pclmul) +#define gf128_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_ref) +#define gf128_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_f2_ref) +#define gf128_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul) +#define gf128_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul_f2) +#define gf128_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_ref) +#define gf128_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_set_ref) +#define gf128_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_avx2) +#define gf128_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_naive) +#define gf128_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_ref) +#define gf128_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_ref) +#define gf128p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_lsh) +#define gf128p_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128p_mul) +#define gf128p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_rsh) +#define gf128p_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128p_sum) +#define gf128v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf128v_bitof) +#define gf128v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf128v_equals) +#define gf128v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_lsh) +#define gf128v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128v_mul) +#define gf128v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_rsh) +#define gf128v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128v_sum) +#define gf192_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_pclmul) +#define gf192_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_ref) +#define gf192_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_avx2) +#define gf192_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_ref) +#define gf192_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_pclmul) +#define gf192_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_ref) +#define gf192_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_avx) +#define gf192_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_naive) +#define gf192_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_ref) +#define gf192_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_pclmul) +#define gf192_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_ref) +#define gf192_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_avx2) +#define gf192_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_ref) +#define gf192_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_pclmul) +#define gf192_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_ref) +#define gf192_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_avx) +#define gf192_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_ref) +#define gf192_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_pclmul) +#define gf192_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_ref) +#define gf192_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_f2_ref) +#define gf192_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_pclmul) +#define gf192_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_ref) +#define gf192_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_set_ref) +#define gf192_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_pow2_ref) +#define gf192_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_ref) +#define gf192_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_pclmul) +#define gf192_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_ref) +#define gf192_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_f2_ref) +#define gf192_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_pclmul) +#define gf192_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_ref) +#define gf192_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_set_ref) +#define gf192_sum_pow2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_avx2) +#define gf192_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_naive) +#define gf192_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_ref) +#define gf192_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_ref) +#define gf192p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_lsh) +#define gf192p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_rsh) +#define gf192v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf192v_bitof) +#define gf192v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf192v_equals) +#define gf192v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_lsh) +#define gf192v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf192v_mul) +#define gf192v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_rsh) +#define gf192v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf192v_sum) +#define gf256_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_pclmul) +#define gf256_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_ref) +#define gf256_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_avx2) +#define gf256_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_ref) +#define gf256_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_pclmul) +#define gf256_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_ref) +#define gf256_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_avx) +#define gf256_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_naive) +#define gf256_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_ref) +#define gf256_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_pclmul) +#define gf256_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_ref) +#define gf256_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_avx2) +#define gf256_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_ref) +#define gf256_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_pclmul) +#define gf256_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_ref) +#define gf256_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_avx) +#define gf256_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_ref) +#define gf256_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_pclmul) +#define gf256_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_ref) +#define gf256_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_f2_ref) +#define gf256_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul) +#define gf256_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul_f2) +#define gf256_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_ref) +#define gf256_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_set_ref) +#define gf256_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_avx2) +#define gf256_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_pow2_ref) +#define gf256_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_ref) +#define gf256_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_pclmul) +#define gf256_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_ref) +#define gf256_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_f2_ref) +#define gf256_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul) +#define gf256_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul_f2) +#define gf256_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_ref) +#define gf256_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_set_ref) +#define gf256_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_avx2) +#define gf256_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_naive) +#define gf256_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_ref) +#define gf256_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_ref) +#define gf256p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_lsh) +#define gf256p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_rsh) +#define gf256v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf256v_bitof) +#define gf256v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf256v_equals) +#define gf256v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_lsh) +#define gf256v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf256v_mul) +#define gf256v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_rsh) +#define gf256v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf256v_sum) +#define gfprod128 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128) +#define gfprod128_f2 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128_f2) +#define ggm_commit_rng_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_avx2) +#define ggm_commit_rng_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_ref) +#define ggm_commit_rng_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_avx2) +#define ggm_commit_rng_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_ref) +#define ggm_commit_rng_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_avx2) +#define ggm_commit_rng_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_avx2) +#define ggm_seed_rng_lr_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_ref) +#define ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2) +#define ggm_seed_rng_lr_ext_cat1_aes128_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_ref) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_avx2) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_avx2) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref) +#define grey_of SDITH_NAMESPACE_FOR_LIBOQS(grey_of) +#define hidden_leaves_indexes SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes) +#define hidden_leaves_indexes2 SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes2) +#define inv_grey_of SDITH_NAMESPACE_FOR_LIBOQS(inv_grey_of) +#define keygen_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_avx) +#define keygen_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_ref) +#define keygen_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_avx) +#define keygen_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_ref) +#define keygen_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_avx) +#define keygen_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_ref) +#define keygen_rng_next_u32_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_avx) +#define keygen_rng_next_u32_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_ref) +#define keygen_rng_next_u32_rijndael256_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_avx) +#define keygen_rng_next_u32_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_ref) +#define keygen_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_aes128_cat1_ref) +#define keygen_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_noop) +#define map_public_key SDITH_NAMESPACE_FOR_LIBOQS(map_public_key) +#define map_secret_key SDITH_NAMESPACE_FOR_LIBOQS(map_secret_key) +#define map_signature SDITH_NAMESPACE_FOR_LIBOQS(map_signature) +#define mask_eq_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_avx) +#define mask_eq_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_ref) +#define mask_lt_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_avx) +#define mask_lt_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_ref) +#define matrix_f2_times_vector_flambda_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_avx2) +#define matrix_f2_times_vector_flambda_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_ref) +#define matrix_rng_get_row_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_avx) +#define matrix_rng_get_row_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_ref) +#define matrix_rng_get_row_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_avx) +#define matrix_rng_get_row_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_ref) +#define matrix_rng_get_row_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_avx) +#define matrix_rng_get_row_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_ref) +#define matrix_rng_get_rows_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_avx) +#define matrix_rng_get_rows_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_ref) +#define matrix_rng_get_rows_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_avx) +#define matrix_rng_get_rows_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_ref) +#define matrix_rng_get_rows_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_avx) +#define matrix_rng_get_rows_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_ref) +#define matrix_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_avx) +#define matrix_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_ref) +#define matrix_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_avx) +#define matrix_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_ref) +#define matrix_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_avx) +#define matrix_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_ref) +#define matrix_rng_preprocess_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_avx) +#define matrix_rng_preprocess_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_ref) +#define matrix_rng_preprocess_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_avx) +#define matrix_rng_preprocess_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_ref) +#define matrix_rng_preprocess_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_avx) +#define matrix_rng_preprocess_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_ref) +#define matrix_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_aes128_cat1_ref) +#define matrix_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_noop) +#define matrix_rng_rows_times_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_avx) +#define matrix_rng_rows_times_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_ref) +#define matrix_rng_rows_times_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_avx) +#define matrix_rng_rows_times_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_ref) +#define matrix_rng_rows_times_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_avx) +#define matrix_rng_rows_times_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_ref) +#define matrix_vector_product_f2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_avx2) +#define matrix_vector_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_ref) +#define partition SDITH_NAMESPACE_FOR_LIBOQS(partition) +#define prepare_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(prepare_extseed_buf_cat1_aes128_ref) +#define proofow_grind_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_avx) +#define proofow_grind_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_ref) +#define proofow_grind_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_avx) +#define proofow_grind_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_ref) +#define proofow_grind_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_avx) +#define proofow_grind_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_ref) +#define proofow_grind_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1) +#define proofow_grind_w_shake_cat1_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1_4way) +#define proofow_grind_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3) +#define proofow_grind_w_shake_cat3_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3_4way) +#define proofow_grind_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5) +#define proofow_grind_w_shake_cat5_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5_4way) +#define proofow_init_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_avx) +#define proofow_init_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_ref) +#define proofow_init_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_avx) +#define proofow_init_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_ref) +#define proofow_init_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_avx) +#define proofow_init_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_ref) +#define proofow_init_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat1) +#define proofow_init_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat3) +#define proofow_init_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat5) +#define proofow_release_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_cipher_cat1_ref) +#define proofow_release_noop SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_noop) +#define proofow_verify_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_avx) +#define proofow_verify_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_ref) +#define proofow_verify_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_avx) +#define proofow_verify_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_ref) +#define proofow_verify_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_avx) +#define proofow_verify_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_ref) +#define proofow_verify_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat1) +#define proofow_verify_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat3) +#define proofow_verify_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat5) +#define prover_cst_check_unitary_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref) +#define prover_cst_check_unitary_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref_tmp_bytes) +#define prover_cst_mux_circuit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref) +#define prover_cst_mux_circuit_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref_tmp_bytes) +#define prover_cst_vole_check_zero_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_check_zero_gate_ct_ref) +#define prover_cst_vole_echelon_pow2_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_echelon_pow2_ct_ref) +#define prover_cst_vole_mul_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_mul_gate_ct_ref) +#define prover_cst_vole_packed_secret_input_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_packed_secret_input_ct_ref) +#define prover_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_ctrl_bytes) +#define prover_cst_vole_qary_mux_gate_ct_f2_prep SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_prep) +#define prover_cst_vole_qary_mux_gate_ct_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref) +#define prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes) +#define prover_cst_vole_qary_mux_gate_ct_naive SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_naive) +#define prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes) +#define prover_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_prepare_ctrl) +#define prover_cst_vole_xor_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_xor_gate_ct_ref) +#define prover_f2_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_std_to_cst_vole_ct_ref) +#define prover_f2_to_flambda_deg1_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_to_flambda_deg1_std_vole_ct_ref) +#define prover_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_deg1_to_degd_vole_ref) +#define prover_flambda_degd_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_degd_std_to_cst_vole_ct_ref) +#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref) +#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes) +#define prover_midsize_to_fullsize_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_midsize_to_fullsize_std_vole_ct_ref) +#define prover_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(prover_vole_consistency_check) +#define quickSort SDITH_NAMESPACE_FOR_LIBOQS(quickSort) +#define release_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(release_extseed_buf_cat1_aes128_ref) +#define rijndael256_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_avx2) +#define rijndael256_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_ref) +#define rijndael256_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_avx2) +#define rijndael256_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_ref) +#define rijndael256_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_avx2) +#define rijndael256_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_ref) +#define rijndael256_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_encrypt_1block_ref) +#define rijndael256_key_schedule_avx SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_avx) +#define rijndael256_key_schedule_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_ref) +#define rijndael256_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_avx2) +#define rijndael256_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_ref) +#define rijndael256_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_avx2) +#define rijndael256_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_ref) +#define rijndael256_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_avx2) +#define rijndael256_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_ref) +#define rijndael256_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_avx2) +#define rijndael256_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_ref) +#define rijndael256_keyexp_x1_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x1_enclast) +#define rijndael256_keyexp_x2_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x2_enclast) +#define rijndael256_keyexp_x3_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x3_enclast) +#define rijndael256_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x4_enclast) +#define rijndael256_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_proofow_grind_avx2) +#define rijndaelEncrypt SDITH_NAMESPACE_FOR_LIBOQS(rijndaelEncrypt) +#define rijndaelKeySetupEnc SDITH_NAMESPACE_FOR_LIBOQS(rijndaelKeySetupEnc) +#define rsd_encode_solution_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_encode_solution_ref) +#define rsd_expand_public_key_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_expand_public_key_ref) +#define rsd_generate_random_instance_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_ref) +#define rsd_generate_random_instance_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_tmp_bytes) +#define rsd_public_key_times_challenge_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_ref) +#define rsd_public_key_times_challenge_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_tmp_bytes) +#define sdith_keygen SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen) +#define sdith_keygen_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_entropy_bytes) +#define sdith_keygen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_tmp_bytes) +#define sdith_public_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_public_key_bytes) +#define sdith_secret_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_secret_key_bytes) +#define sdith_sign SDITH_NAMESPACE_FOR_LIBOQS(sdith_sign) +#define sdith_signature_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_bytes) +#define sdith_signature_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_entropy_bytes) +#define sdith_signature_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_tmp_bytes) +#define sdith_verify SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify) +#define sdith_verify_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify_tmp_bytes) +#define swap SDITH_NAMESPACE_FOR_LIBOQS(swap) +#define tmp_bytes_init SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_init) +#define tmp_bytes_reserve_call SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_call) +#define tmp_bytes_reserve_local_var SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var) +#define tmp_bytes_reserve_local_var_aligned SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var_aligned) +#define transpose_128_128_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_naive) +#define transpose_128_128_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_ref) +#define transpose_128_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_naive) +#define transpose_128_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_ref) +#define transpose_192_192_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_naive) +#define transpose_192_192_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_ref) +#define transpose_192_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_naive) +#define transpose_192_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_ref) +#define transpose_256_256_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_naive) +#define transpose_256_256_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_ref) +#define transpose_256_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_naive) +#define transpose_256_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_ref) +#define verifier_cst_check_unitary_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref) +#define verifier_cst_check_unitary_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref_tmp_bytes) +#define verifier_cst_mux_circuit_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref) +#define verifier_cst_mux_circuit_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref_tmp_bytes) +#define verifier_cst_vole_check_zero_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_check_zero_gate_ref) +#define verifier_cst_vole_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_echelon_pow2_ref) +#define verifier_cst_vole_mul_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_mul_gate_ref) +#define verifier_cst_vole_packed_secret_input_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_packed_secret_input_ref) +#define verifier_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_ctrl_bytes) +#define verifier_cst_vole_qary_mux_gate_prep SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_prep) +#define verifier_cst_vole_qary_mux_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref) +#define verifier_cst_vole_qary_mux_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref_tmp_bytes) +#define verifier_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_prepare_ctrl) +#define verifier_cst_vole_xor_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_xor_gate_ref) +#define verifier_f2_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_std_to_cst_vole_ref) +#define verifier_f2_to_flambda_deg1_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_to_flambda_deg1_std_vole_ref) +#define verifier_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_deg1_to_degd_vole_ref) +#define verifier_flambda_degd_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_degd_std_to_cst_vole_ref) +#define verifier_midsize_to_fullsize_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_midsize_to_fullsize_std_vole_ref) +#define verifier_open_midsize_grey_vole_from_seeds_bfs_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_ref) +#define verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes) +#define verifier_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(verifier_vole_consistency_check) +#define vole_consistency_check_matrix_ncols SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_ncols) +#define vole_consistency_check_matrix_nrows SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_nrows) +#define vole_parameters_init SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init) +#define vole_parameters_init_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_avx) +#define vole_parameters_init_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_ref) +#define vole_parameters_init_with_variant SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant) +#define vole_parameters_init_with_variant_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_avx) +#define vole_parameters_init_with_variant_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_ref) +#define vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2) +#define vole_rng_ext_cat1_aes128_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_ref) +#define vole_rng_ext_cat3_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_avx2) +#define vole_rng_ext_cat3_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_ref) +#define vole_rng_ext_cat5_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_avx2) +#define vole_rng_ext_cat5_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_ref) +#define xof_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake128) +#define xof_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake256) +#define xof_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake128) +#define xof_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake256) +#define xof_finalize_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake128) +#define xof_finalize_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake256) +#define xof_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake128) +#define xof_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake256) +#define xof_init_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake128) +#define xof_init_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake256) +#define xof_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake128) +#define xof_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake256) +#define xof_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake128) +#define xof_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake256) +#define xof_vector_ctx_bytes_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake128) +#define xof_vector_ctx_bytes_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake256) +#define xof_vector_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake128) +#define xof_vector_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake256) +#define xof_vector_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake128) +#define xof_vector_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake256) +#define xof_vector_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake128) +#define xof_vector_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake256) +#define xof_vector_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake128) +#define xof_vector_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake256) +#define xorto_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(xorto_kappabit_uint) + +#endif // APPLY_NAMESPACE + +#endif // SDITH_NAMESPACE_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_piop_circuits.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_piop_circuits.h new file mode 100644 index 0000000000..079db91fc7 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_piop_circuits.h @@ -0,0 +1,333 @@ +#ifndef SDITH_PIOP_CIRCUITS_H +#define SDITH_PIOP_CIRCUITS_H + +#include "vole_parameters.h" + +// vole circuit gates + +/** + * prover packed secret input gate (degree 1) + */ +EXPORT void prover_cst_vole_packed_secret_input_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + bitvec_t* out_pub, // [out] output publication (packed over f2) + fpoly_t* out_f, // [out] poly of degree 1 (cst term over f2) + const bitvec_t* in_value, // [in] secret bit values (packed over f2) + const bitvec_t* in_rvp_u, // [in] packed u terms + const flambda_t* in_rvp_v); // [in] packed v terms + +/** + * verifier packed secret input gate (degree 1) + */ +EXPORT void verifier_cst_vole_packed_secret_input_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_inputs, // number of inputs to process + fpoly_t* out_q, // [out] vole evaluations + const bitvec_t* in_pub, // [in] publications (packed over f2) + const flambda_t* in_rvp_q, // [in] packed v terms + const flambda_t* delta2); // [in] verifier's point + +/** + * prover check-zero gate (degree d) + */ +EXPORT void prover_cst_vole_check_zero_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + fpoly_t* out_pub, // [out] output publication (degree d-1) + const fpoly_t* in_f, // [in] input (degree d) + const fpoly_t* in_rvp_f); // [in] rvp (degree d-1) + +/** + * verifier check-zero gate (degree d) + */ +EXPORT uint8_t verifier_cst_vole_check_zero_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // input degree + flambda_t* out_value, // [out] deduced output value + const fpoly_t* in_pub, // [in] publication (degree d-1) + const flambda_t* in_q, // [in] input (degree d) + const flambda_t* in_rvp_q, // [in] rvp (degree d-1) + const flambda_t* delta2); // [in] verifier's point + +/** + * prover xor gate + */ +EXPORT void prover_cst_vole_xor_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree); // [in] b + +/** + * verifier xor gate + */ +EXPORT void verifier_cst_vole_xor_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_f, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_f, uint64_t a_degree, // [in] a + const flambda_t* b_f, uint64_t b_degree, // [in] b + const flambda_t* delta2); // [in] verifier's point (unused) + +/** + * prover mul gate + */ +EXPORT void prover_cst_vole_mul_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + fpoly_t* res_f, // [out] poly of degree 1 (cst term over f2) + const fpoly_t* a_f, uint64_t a_degree, // [in] a + const fpoly_t* b_f, uint64_t b_degree); // [in] b + +/** + * verifier mul gate + */ +EXPORT void verifier_cst_vole_mul_gate_ref( // + const vole_parameters* vole_params, // dimensions + flambda_t* res_q, // [out] poly of degree 1 (cst term over f2) + const flambda_t* a_q, uint64_t a_degree, // [in] a + const flambda_t* b_q, uint64_t b_degree, // [in] b + const flambda_t* delta2); // [in] verifier's point (unused) + +/** + * prover echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void prover_cst_vole_echelon_pow2_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + fpoly_t* res_f, // [out] res of degree 1 + const fpoly_t* a_f); // [in] (arity) a of degree 1 + +/** + * verifier echelon-pow2 gate (degree 1): sum(2^{ki}.a[i]) + */ +EXPORT void verifier_cst_vole_echelon_pow2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, uint64_t k, // + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* delta2); // [in] verifier's point (unused) + +/** @brief number of scratch bytes necessary for prover_cst_vole_qary_mux_gate_ct_ref */ +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree // common input degree +); + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + * KEPT ONLY FOR TEST PURPOSES: since c is binary, use prover_cst_vole_qary_mux_gate_ct_f2_ref + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_naive( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (arity) values of deg d + uint8_t* tmp_space); // scratch space + +/** @brief bytes of the prepared control of a qary-mux gate of the given arity */ +EXPORT uint64_t prover_cst_vole_qary_mux_ctrl_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity); // mux arity >= 1 + +/** + * Rewrite the control bits of a qary-mux gate as two "extended control" vectors, so that the + * gate becomes a pair of plain dot products over its inputs (see below): + * res = a[0] + sum_{i>0} c[i-1] (a[i]-a[0]) + * = sum_{i>=0} ctrl0[i] a[i] + X . sum_{i>=0} ctrl1[i] a[i] + * with, writing c[i-1] = c0[i] + c1[i].X for i > 0, + * ctrl0[i] = c0[i], ctrl1[i] = c1[i] (i > 0) + * ctrl0[0] = 1 + sum_{i>0} c0[i], ctrl1[0] = sum_{i>0} c1[i] (the "- a[0]" of every term) + * The ctrl0[i] stay in F2 (the c0[i] are bits), so the first dot product is a bit-select. + * The control is shared by every gate of a mux-circuit layer: prepare it once per layer. + * ctrl is the concatenation of ctrl0 (arity elements) and ctrl1 (arity elements). + */ +EXPORT void prover_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (2 x arity) extended control + const fpoly_t* c_f); // [in] (arity-1) control bits of deg. 1 + +/** + * prover qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const flambda_t* ctrl, // [in] (2 x arity) prepared control + const fpoly_t* a_f); // [in] (arity) values of deg d + +/** @brief number of scratch bytes necessary for prover_cst_vole_qary_mux_gate_ct_f2_ref */ +EXPORT uint64_t prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity); // mux arity >= 1 + +/** + * prover qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) using product_f2 + * One-shot form: it derives the control into tmp_space on every call. A caller that applies + * several gates sharing the same c_f (a mux-circuit layer) should instead prepare the control + * once with prover_cst_vole_qary_mux_prepare_ctrl and call ..._f2_prep. + */ +EXPORT void prover_cst_vole_qary_mux_gate_ct_f2_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + fpoly_t* res_f, // [out] poly of degree d+1 + const fpoly_t* c_f, // [in] (arity-1) control bits of deg. 1 + const fpoly_t* a_f, // [in] (arity) values of deg d + uint8_t* tmp_space); // scratch space + +/** @brief bytes of the prepared control of a verifier qary-mux gate of the given arity */ +EXPORT uint64_t verifier_cst_vole_qary_mux_ctrl_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity); // mux arity >= 1 + +/** + * Rewrite the control values of a qary-mux gate as one "extended control" vector, so that the + * gate becomes a plain dot product over its inputs: + * res = a[0] + sum_{i>0} c[i-1] (a[i]-a[0]) = sum_{i>=0} ctrl[i] a[i] + * with ctrl[i] = c[i-1] for i > 0, and the i == 0 entry absorbing the "- a[0]" of every term: + * ctrl[0] = 1 + sum_{i>0} c[i-1]. + * This is the verifier counterpart of prover_cst_vole_qary_mux_prepare_ctrl: everything here is + * an evaluation at delta2, so there is a single vector (no degree-0/degree-1 split) and no F2 + * fast path (see the note below). + * The control is shared by every gate of a mux-circuit layer: prepare it once per layer. + */ +EXPORT void verifier_cst_vole_qary_mux_prepare_ctrl( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* ctrl, // [out] (arity) extended control + const flambda_t* c_q, // [in] (arity-1) control values + const flambda_t* delta2); // [in] verifier's point (unused) + +/** + * verifier qary-mux gate on a prepared control: res = a[0] + sum(c[i-1] (a[i]-a[0])) + */ +EXPORT void verifier_cst_vole_qary_mux_gate_prep( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* res_q, // [out] evaluation of the poly of degree d+1 + const flambda_t* ctrl, // [in] (arity) prepared control + const flambda_t* a_q, // [in] (arity) values of deg d + const flambda_t* delta2); // [in] verifier's point (unused) + +/** @brief number of scratch bytes necessary*/ +EXPORT uint64_t verifier_cst_vole_qary_mux_gate_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree // common input degree +); + +/** + * verifier qary-mux gate: res = a[0] + sum(c[i-1] (a[i]-a[0])) + * One-shot form: it derives the control into tmp_space on every call. A caller that applies + * several gates sharing the same c_q (a mux-circuit layer) should instead prepare the control + * once with verifier_cst_vole_qary_mux_prepare_ctrl and call ..._gate_prep. + */ +EXPORT void verifier_cst_vole_qary_mux_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + uint64_t in_degree, // common input degree + flambda_t* res_q, // [out] poly of degree d+1 + const flambda_t* c_q, // [in] (arity-1) control bits of deg. 1 + const flambda_t* a_q, // [in] (arity) values of deg d + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space); // scratch space + +/* + * There is no verifier-side F2-optimized mux gate. The prover's product_f2 fast + * path (prover_cst_vole_qary_mux_gate_ct_f2_ref) is only valid because the + * control bits are plaintext over F2 there (they are the constant term of u), so + * c*(a[i]-a[0]) reduces to a bit-select. On the verifier side the control bits + * are full-q values evaluated at delta2, so the mux gate must use full q-products + * throughout: the extended-control rewriting above applies to both sides, but the + * verifier's two dot products collapse into one and neither of them is over F2. + */ + +/** + * scratch bytes required by prover_cst_check_unitary_gate_ct_ref + */ +EXPORT uint64_t prover_cst_check_unitary_gate_ct_ref_tmp_bytes(const vole_parameters* vole_params); + +/** + * prover check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void prover_cst_check_unitary_gate_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // arity >= 1 + fpoly_t* res_f, // [out] res of degree 2 + const fpoly_t* a_f, // [in] (arity) a of deg 1 + const flambda_t* coeff, // [in] challenge coeff + uint8_t* tmp_space); // scratch space + +/** + * scratch bytes required by verifier_cst_check_unitary_gate_ref + */ +EXPORT uint64_t verifier_cst_check_unitary_gate_ref_tmp_bytes(const vole_parameters* vole_params); + +/** + * verifier check unitary gate: + * res = coeff * (sum a[i].2^{i}) * (sum a[i].2^{ki}) + (sum a[i].2^{(k+1)i}) where k = arity + */ +EXPORT void verifier_cst_check_unitary_gate_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t arity, // mux arity >= 1 + flambda_t* res_q, // [out] res + const flambda_t* a_q, // [in] (arity) a + const flambda_t* coeff, // [in] challenge coeff + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space); // scratch space + +/** + * scratch space required by prover_cst_mux_circuit_ct_ref + */ +EXPORT uint64_t prover_cst_mux_circuit_ct_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs); // scratch space + +/** + * prover mux-circuit: + */ +EXPORT void prover_cst_mux_circuit_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + fpoly_t* res_f, // [out] res of degree depth + const fpoly_t* c_f, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge coeff for unitary tests (unused if all muxes are binary) + uint8_t* tmp_space); // [tmp] scratch space + +/** + * scratch space required by verifier_cst_mux_circuit_ref + */ +EXPORT uint64_t verifier_cst_mux_circuit_ref_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs); // scratch space + +/** + * verifier mux-circuit: + */ +EXPORT void verifier_cst_mux_circuit_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t depth, // circuit depth + const uint64_t* arities, // (depth) arities (preferably in decreasing order) + uint64_t num_inputs, // number of inputs (<= product of arities) + flambda_t* res_q, // [out] res of degree depth + const flambda_t* c_q, // [in] (sum (arity[i]-1)) ctrl bits of deg 1 + const flambda_t* a, // [in] challenge input values + const flambda_t* chall_c, // [in] challenge coeff for unitary tests (unused if all muxes are binary) + const flambda_t* delta2, // [in] verifier's point (unused) + uint8_t* tmp_space); // [tmp] scratch space + +#endif // SDITH_PIOP_CIRCUITS_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng.c b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng.c new file mode 100644 index 0000000000..743a82e4a5 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng.c @@ -0,0 +1,1152 @@ +#include "sdith_prng.h" + +#include +#include + +#ifdef SDITH3_FOR_LIBOQS +#include "aes128_ctrle.h" +#include "aes_ansi_ref.h" +#include "fips202_glue.h" +#include "fips202x4_glue.h" +#else +#include "../aes/aes128_ctrle.h" +#include "../aes/aes_ansi_ref.h" +#include "../sha3/KeccakHash.h" +#include "../sha3/KeccakHashtimes4.h" +#endif + +#include "rijndael256_ctrle.h" +#include "sdith_prng_private.h" +#include "vole_private.h" + +#define STATIC_ASSERT(assert_name, condition) \ + uint8_t assert_name[(condition)?1:-1] + +// ggm seed rng, extended-seed variants (ref): consume the expanded round keys via +// encrypt_nblocks instead of scheduling the key inside oneshot. Same domain sep as +// the raw variant (node_idx, not node_idx<<1), so byte-identical to the raw output. +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_ref(void* lr_out256, const void* salt128, const void* extkey128, + uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + aesblk ctr = {.v64 = {0, 0}}; + CASSERT(domain_sep_check(salt128, node_idx, 2, theta), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt128, 16, node_idx); + aes128_ctrle_nocarry_2block_ref(lr_out256, extkey128, ctr.v64); +} +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_ref( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + uint8_t out512[64] = {}; + ctr256_t ctr256 = {.v8 = {}}; + CASSERT(domain_sep_check(salt192, node_idx, 2, theta), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt192, 24, node_idx); + rijndael256_ctrle_nocarry_2block_ref(out512, extkey, ctr256.v8); + // cat3 Enc = LSB_192(Rijndael-256): keep the low 24 bytes of each block + memcpy(lr_out384, out512, 24); + memcpy((uint8_t*)lr_out384 + 24, out512 + 32, 24); +} +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_ref( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + ctr256_t ctr256 = {.v8 = {}}; + CASSERT(domain_sep_check(salt256, node_idx, 2, theta), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt256, 32, node_idx); + rijndael256_ctrle_nocarry_2block_ref(lr_out512, extkey, ctr256.v8); +} + +// I8: naive x4 wrappers (ref). LR_STRIDE = 2 * lambda_bytes, EXT_STRIDE = one extended key. +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat1_aes128_x4_ref, // + ggm_seed_rng_lr_ext_cat1_aes128_ref, 32, 16 * 11) +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref, // + ggm_seed_rng_lr_ext_cat3_rijndael256_ref, 48, RIJNDAEL256_RK_BYTES) +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref, // + ggm_seed_rng_lr_ext_cat5_rijndael256_ref, 64, RIJNDAEL256_RK_BYTES) + +// --------------------------------------------------------------------------- +// Extended leaf seed: run the key schedule once, share it across commit + vole. +// For aes/rijndael the extended seed is the expanded round keys; the pad/schedule +// mirrors the raw commit/vole paths exactly, so outputs stay byte-identical. +// --------------------------------------------------------------------------- +EXPORT void extend_leaf_seed_cat1_aes128_ref(void* extended_seed_out, const void* seed128) { + // When building for liboqs, this allows allows key schedule reuse (see `aes_ansi_ref.h`) + // Requires the buffer to have been passed to aes128_prepare_rk_buffer first. + aes128_set_key_reuse_ref(extended_seed_out, seed128); +} +EXPORT void extend_leaf_seed_cat3_rijndael256_ref(void* extended_seed_out, const void* seed192) { + uint8_t key256[32] = {}; // k || 0^64 + memcpy(key256, seed192, 24); + rijndael256_key_schedule_x1_ref(extended_seed_out, key256); +} +EXPORT void extend_leaf_seed_cat5_rijndael256_ref(void* extended_seed_out, const void* seed256) { + rijndael256_key_schedule_x1_ref(extended_seed_out, seed256); +} + +// 4x leaf-seed expansion (ref): run the 1x schedule four times with shifted +// pointers. Seeds/outputs are packed at their natural stride, so the result is +// byte-identical to four separate 1x calls (KAT-preserving). +EXPORT void extend_leaf_seed_cat1_aes128_4x_ref(void* extended_seed_out, const void* seeds) { + uint8_t* out = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + for (int i = 0; i < 4; i++) extend_leaf_seed_cat1_aes128_ref(out + i * (16 * 11), s + i * 16); +} +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_ref(void* extended_seed_out, const void* seeds) { + uint8_t* out = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + for (int i = 0; i < 4; i++) extend_leaf_seed_cat3_rijndael256_ref(out + i * RIJNDAEL256_RK_BYTES, s + i * 24); +} +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_ref(void* extended_seed_out, const void* seeds) { + uint8_t* out = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + for (int i = 0; i < 4; i++) extend_leaf_seed_cat5_rijndael256_ref(out + i * RIJNDAEL256_RK_BYTES, s + i * 32); +} + +EXPORT void prepare_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes) { + aes128_prepare_rk_buffer(buf, nslots, slot_bytes); +} +EXPORT void release_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes) { + uint8_t* p = (uint8_t*) buf; + for (uint64_t i = 0; i < nslots; ++i) aes128_release_key(p + i * slot_bytes); +} +EXPORT void extseed_buf_noop(void* buf, uint64_t nslots, uint64_t slot_bytes) { + (void) buf; (void) nslots; (void) slot_bytes; // rijndael256: schedule is in-place +} + +EXPORT uint64_t extended_node_seed_bytes_cat1_aes128(void) { return 16 * 11; } +EXPORT uint64_t extended_node_seed_bytes_cat3_rijndael256(void) { return RIJNDAEL256_RK_BYTES; } +EXPORT uint64_t extended_node_seed_bytes_cat5_rijndael256(void) { return RIJNDAEL256_RK_BYTES; } + +// commit rng, extended-seed cores: take the expanded round keys and encrypt. +EXPORT void ggm_commit_rng_ext_cat1_aes128_ref(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx) { + aesblk ctr = {.v64 = {0, 0}}; + CASSERT(domain_sep_check(salt128, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt128, 16, node_idx << 1); + aes128_ctrle_nocarry_2block_ref(output256, extkey128, ctr.v64); +} +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_ref( // + void* output384, const void* salt192, const void* extkey, uint64_t node_idx) { + uint8_t output512[64] = {}; // pad with zeroes + ctr256_t ctr256 = {.v8 = {}}; // pad with zeroes + CASSERT(domain_sep_check(salt192, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt192, 24, node_idx << 1); + rijndael256_ctrle_nocarry_2block_ref(output512, extkey, ctr256.v8); + // cat3 Enc = LSB_192(Rijndael-256): keep the low 24 bytes of each block + memcpy(output384, output512, 24); + memcpy((uint8_t*)output384 + 24, output512 + 32, 24); +} +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_ref( // + void* output512, const void* salt256, const void* extkey, uint64_t node_idx) { + ctr256_t ctr256 = {.v8 = {}}; + CASSERT(domain_sep_check(salt256, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + domain_sep_ptx_lo2(ctr256.v64, salt256, 32, node_idx << 1); + rijndael256_ctrle_nocarry_2block_ref(output512, extkey, ctr256.v8); +} + +// vole rng, extended-seed cores: adopt the precomputed round keys, no schedule. +// The counter starts at the salt tweaked by the repetition index (see +// VOLE_RNG_REPET_SHIFT), and the domain_sep_check asserts that the last block of +// the stream still fits in the tweak field. +EXPORT void vole_rng_ext_cat1_aes128_ctrle_ref(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx) { + ctr128_t ctr = {}; + CASSERT((out_bytes & 15) == 0, "bug! out_bytes must be multiple of 16"); + CASSERT(domain_sep_check(salt128, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 4, GGM_TWEAK_BITS), + "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt128, 16, repet_idx << VOLE_RNG_REPET_SHIFT); + aes128_ctrle_nocarry_nblocks_ref(out, extseed, ctr.v64, out_bytes >> 4); +} +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx) { + ctr256_align32_t ctr = {}; + CASSERT((out_bytes & 31) == 0, "bug! out_bytes must be multiple of 32"); + CASSERT(domain_sep_check(salt192, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 5, GGM_TWEAK_BITS), + "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt192, 24, repet_idx << VOLE_RNG_REPET_SHIFT); + rijndael256_ctrle_nocarry_nblocks_ref(out, extseed, ctr.v64, out_bytes >> 5); +} +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx) { + ctr256_align32_t ctr = {}; + CASSERT((out_bytes & 31) == 0, "bug! out_bytes must be multiple of 32"); + CASSERT(domain_sep_check(salt256, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 5, GGM_TWEAK_BITS), + "bug! invalid separation"); + domain_sep_ptx_lo2(ctr.v64, salt256, 32, repet_idx << VOLE_RNG_REPET_SHIFT); + rijndael256_ctrle_nocarry_nblocks_ref(out, extseed, ctr.v64, out_bytes >> 5); +} + +EXPORT void xof_init_shake128(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE128(inst); +} +EXPORT void xof_init_shake256(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE256(inst); +} + +EXPORT void xof_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashUpdate(inst, in, in_bytes << 3); +} +EXPORT void xof_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashUpdate(inst, in, in_bytes << 3); +} + +EXPORT void xof_finalize_shake128(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); +} +EXPORT void xof_finalize_shake256(xof_ctx* xof) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); +} + +EXPORT void xof_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} +EXPORT void xof_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} + +// shortcut combo +EXPORT void xof_init_and_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE128(inst); + Keccak_HashUpdate(inst, in, in_bytes << 3); +} +EXPORT void xof_init_and_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashInitialize_SHAKE256(inst); + Keccak_HashUpdate(inst, in, in_bytes << 3); +} + +EXPORT void xof_finalize_and_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} +EXPORT void xof_finalize_and_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes) { + Keccak_HashInstance* const inst = (Keccak_HashInstance*)xof; + Keccak_HashFinal(inst, NULL); + Keccak_HashSqueeze(inst, out, out_bytes << 3); +} + +EXPORT void xof_ctx_release_shake128(xof_ctx* xof) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + #else + OQS_SHA3_shake128_inc_ctx_release(&xof->shake128_state); + #endif +} +EXPORT void xof_ctx_release_shake256(xof_ctx* xof) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + #else + OQS_SHA3_shake256_inc_ctx_release(&xof->shake256_state); + #endif +} + +// vector shake function + +static const uint64_t SINGLE_XOF_STRIDE = (sizeof(KeccakWidth1600_SpongeInstance) + 31) & UINT64_C(-32); +static const uint64_t BATCH_XOF_STRIDE = (sizeof(KeccakWidth1600times4_SpongeInstance) + 31) & UINT64_C(-32); +static const uint64_t XOF_RATE_SHAKE128 = 1344; +static const uint64_t XOF_RATE_SHAKE256 = 1088; +static const uint64_t XOF_CAPACITY_SHAKE128 = 256; +static const uint64_t XOF_CAPACITY_SHAKE256 = 512; +#define BATCH_XOF(base, idx) ((KeccakWidth1600times4_SpongeInstance*)((uint8_t*)(base) + (idx) * BATCH_XOF_STRIDE)) +#define SINGLE_XOF(base, idx) ((KeccakWidth1600_SpongeInstance*)((uint8_t*)(base) + (idx) * SINGLE_XOF_STRIDE)) + + +//typedef struct xof_vector_ctx_t xof_vector_ctx; + +//typedef uint64_t XOF_VECTOR_CTX_BYTES_F(uint64_t num_xofs); +EXPORT uint64_t xof_vector_ctx_bytes_shake128(uint64_t num_xofs) { + // use (num_xofs / 4) x batched shake and (num_xofs % 4) single ones + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + return num_batches * BATCH_XOF_STRIDE + num_remainder * SINGLE_XOF_STRIDE; +} +EXPORT uint64_t xof_vector_ctx_bytes_shake256(uint64_t num_xofs) { + return xof_vector_ctx_bytes_shake128(num_xofs); // same +} + +//typedef void XOF_VECTOR_INIT_AND_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); +EXPORT void xof_vector_init_and_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + const unsigned char* prefix_ptrs[4] = { + (const unsigned char*)data, (const unsigned char*)data, + (const unsigned char*)data, (const unsigned char*)data}; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeInitialize(inst, XOF_RATE_SHAKE128, XOF_CAPACITY_SHAKE128); + KeccakWidth1600times4_SpongeAbsorb(inst, prefix_ptrs, data_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeInitialize(inst, XOF_RATE_SHAKE128, XOF_CAPACITY_SHAKE128); + KeccakWidth1600_SpongeAbsorb(inst, data, data_bytes); + } +} + +EXPORT void xof_vector_init_and_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + const unsigned char* prefix_ptrs[4] = { + (const unsigned char*)data, (const unsigned char*)data, + (const unsigned char*)data, (const unsigned char*)data}; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeInitialize(inst, XOF_RATE_SHAKE256, XOF_CAPACITY_SHAKE256); + KeccakWidth1600times4_SpongeAbsorb(inst, prefix_ptrs, data_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeInitialize(inst, XOF_RATE_SHAKE256, XOF_CAPACITY_SHAKE256); + KeccakWidth1600_SpongeAbsorb(inst, data, data_bytes); + } +} + +//typedef void XOF_VECTOR_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); +EXPORT void xof_vector_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + unsigned char** dbase = data + num_batches * 4; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeAbsorb(inst, (const unsigned char **)(data + 4 * b), data_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeAbsorb(inst, dbase[r], data_bytes); + } +} +EXPORT void xof_vector_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes) { + xof_vector_seed_shake128(xof, num_xofs, data, data_bytes); // same +} + +//typedef void XOF_VECTOR_FINALIZE_AND_OUTPUT_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); +EXPORT void xof_vector_finalize_and_output_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes) { + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + unsigned char** dbase = out_hashes + num_batches * 4; + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + KeccakWidth1600times4_SpongeAbsorbLastFewBits(inst, 0x1F); + KeccakWidth1600times4_SpongeSqueeze(inst, out_hashes + b * 4, hash_bytes); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + KeccakWidth1600_SpongeAbsorbLastFewBits(inst, 0x1F); + KeccakWidth1600_SpongeSqueeze(inst, dbase[r], hash_bytes); + } +} +EXPORT void xof_vector_finalize_and_output_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes) { + xof_vector_finalize_and_output_shake128(xof, num_xofs, out_hashes, hash_bytes); // same +} + +EXPORT void xof_vector_ctx_release_shake128(xof_vector_ctx* xof, uint64_t num_xofs) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + (void)num_xofs; // no-op + #else + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + OQS_SHA3_shake128_x4_inc_ctx_release(&inst->shake128_state); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + OQS_SHA3_shake128_inc_ctx_release(&inst->shake128_state); + } + #endif +} +EXPORT void xof_vector_ctx_release_shake256(xof_vector_ctx* xof, uint64_t num_xofs) { + #ifndef SDITH3_FOR_LIBOQS + (void)xof; // no-op + (void)num_xofs; // no-op + #else + const uint64_t num_batches = num_xofs >> UINT64_C(2); + const uint64_t num_remainder = num_xofs & UINT64_C(3); + void* sbase = BATCH_XOF(xof, num_batches); + for (uint64_t b = 0; b < num_batches; ++b) { + KeccakWidth1600times4_SpongeInstance* const inst = BATCH_XOF(xof, b); + OQS_SHA3_shake256_x4_inc_ctx_release(&inst->shake256_state); + } + for (uint64_t r = 0; r < num_remainder; ++r) { + KeccakWidth1600_SpongeInstance* const inst = SINGLE_XOF(sbase, r); + OQS_SHA3_shake256_inc_ctx_release(&inst->shake256_state); + } + #endif +} + +// cipher-based proof of work + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat1() { return sizeof(struct proofow_state128_t); } + +EXPORT void proofow_init_cipher_cat1_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 32; + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake128(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake128(&xof); + xof_output_shake128(&xof, s->p, 64); // covers p0,p1,k0,k1 + xof_ctx_release_shake128(&xof); + s->p[0].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + aes128_key_schedule_x2_ref(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + static const uint64_t H_PIOP_BYTES = 32; // CAT1 + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + while (ctr < CTR_MAX) { + aes128_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + aes128_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) == 0) { + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake128(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake128(&xof); + *ctr_in_out = ctr; + return 1; + } + ++ctr; + ++s->p[0].v64[0]; + ++s->p[1].v64[0]; + } + return 0; +} + +EXPORT int proofow_verify_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 32; // CAT1 + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + aes128_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + aes128_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake128(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake128(&xof); + return 1; +} + +EXPORT void proofow_release_cipher_cat1_ref(proofow_ctx_t* proofow_state) { + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + aes128_release_key(s->rk[0]); + aes128_release_key(s->rk[1]); +} + +// Shared by every proof-of-work variant that holds no schedule of its own: the +// cat3/cat5 cipher ones expand rijndael256 in place, the avx cat1 one expands +// aes128 in place, and the shake ones run no cipher at all. +EXPORT void proofow_release_noop(proofow_ctx_t* proofow_state) { (void)proofow_state; } + +// cipher-based proof of work (cat5: rijndael256 block cipher + shake256 xof) + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat5() { return sizeof(struct proofow_state256_t); } + +EXPORT void proofow_init_cipher_cat5_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 64; // CAT5: 2*lambda = 512 bits + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) + xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + rijndael256_key_schedule_x2_ref(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + static const uint64_t H_PIOP_BYTES = 64; // CAT5 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + while (ctr < CTR_MAX) { + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) == 0) { + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } + ++ctr; + ++s->p[0].v64[0]; + ++s->p[1].v64[0]; + } + return 0; +} + +EXPORT int proofow_verify_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 64; // CAT5 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + return 1; +} + +// cipher-based proof of work (cat3: rijndael256 block cipher + shake256 xof). +// Identical to cat5 except h_piop is 2*lambda = 384 bits = 48 bytes, so the +// cat5 proofow_state256_t workspace (h_piop[64]) is reused as-is. + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat3() { return sizeof(struct proofow_state256_t); } + +EXPORT void proofow_init_cipher_cat3_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 48; // CAT3: 2*lambda = 384 bits + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) + xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + rijndael256_key_schedule_x2_ref(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + static const uint64_t H_PIOP_BYTES = 48; // CAT3 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + while (ctr < CTR_MAX) { + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) == 0) { + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; + } + ++ctr; + ++s->p[0].v64[0]; + ++s->p[1].v64[0]; + } + return 0; +} + +EXPORT int proofow_verify_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 48; // CAT3 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + rijndael256_ctrle_nocarry_1block_ref(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_ref(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + return 1; +} + +/// shake-based proof of work + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat1() { return sizeof(struct proofow_shake_cat1_t); } + +EXPORT void proofow_init_shake_cat1( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + struct proofow_shake_cat1_t* const s = (struct proofow_shake_cat1_t*)proofow_state; + memset(s->delta0_and_vgrind, 0, sizeof(s->delta0_and_vgrind)); + memcpy(s->h_piop, h_piop, (lambda * 2) >> 3); + s->w = proofow_w; + s->kappa_tau = kappa * tau; + s->delta0_and_vgrind_bytes = (s->kappa_tau + proofow_w + 7) >> 3; + s->delta0_out_bytes = (s->kappa_tau + 7) >> 3; +} + +EXPORT int proofow_grind_w_shake_cat1( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +) { + static const uint64_t H_PIOP_BYTES = 32; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + struct proofow_shake_cat1_t* const s = (struct proofow_shake_cat1_t*)proofow_state; + xof_ctx ctx __attribute((aligned(16))); + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake128(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&ctx, &ctr, 4); + xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake128(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; + } + } + // no good counter: pow has failed + return 0; +} + +EXPORT int proofow_verify_w_shake_cat1( // + proofow_ctx_t* proofow_state, // + void* delta0_out, // + const uint64_t ctr_value // +) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t H_PIOP_BYTES = 32; + struct proofow_shake_cat1_t* const s = (struct proofow_shake_cat1_t*)proofow_state; + const uint64_t ctr = ctr_value; + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake128(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&ctx, &ctr, 4); + xof_finalize_and_output_shake128(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake128(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; +} + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat3() { return sizeof(struct proofow_shake_cat3_t); } + +EXPORT void proofow_init_shake_cat3( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + struct proofow_shake_cat3_t* const s = (struct proofow_shake_cat3_t*)proofow_state; + memset(s->delta0_and_vgrind, 0, sizeof(s->delta0_and_vgrind)); + memcpy(s->h_piop, h_piop, (lambda * 2) >> 3); + s->w = proofow_w; + s->kappa_tau = kappa * tau; + s->delta0_and_vgrind_bytes = (s->kappa_tau + proofow_w + 7) >> 3; + s->delta0_out_bytes = (s->kappa_tau + 7) >> 3; +} + +EXPORT int proofow_grind_w_shake_cat3( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +) { + static const uint64_t H_PIOP_BYTES = 48; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + struct proofow_shake_cat3_t* const s = (struct proofow_shake_cat3_t*)proofow_state; + xof_ctx ctx __attribute((aligned(16))); + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; + } + } + // no good counter: pow has failed + return 0; +} + +EXPORT int proofow_verify_w_shake_cat3( // + proofow_ctx_t* proofow_state, // + void* delta0_out, // + const uint64_t ctr_value // +) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t H_PIOP_BYTES = 48; + struct proofow_shake_cat3_t* const s = (struct proofow_shake_cat3_t*)proofow_state; + const uint64_t ctr = ctr_value; + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) return 0; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; +} + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat5() { return sizeof(struct proofow_shake_cat5_t); } + +EXPORT void proofow_init_shake_cat5( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + struct proofow_shake_cat5_t* const s = (struct proofow_shake_cat5_t*)proofow_state; + memset(s->delta0_and_vgrind, 0, sizeof(s->delta0_and_vgrind)); + memcpy(s->h_piop, h_piop, (lambda * 2) >> 3); + s->w = proofow_w; + s->kappa_tau = kappa * tau; + s->delta0_and_vgrind_bytes = (s->kappa_tau + proofow_w + 7) >> 3; + s->delta0_out_bytes = (s->kappa_tau + 7) >> 3; +} + +EXPORT int proofow_grind_w_shake_cat5( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +) { + static const uint64_t H_PIOP_BYTES = 64; + static const uint64_t CTR_MAX = UINT64_C(1) << 32; + struct proofow_shake_cat5_t* const s = (struct proofow_shake_cat5_t*)proofow_state; + xof_ctx ctx __attribute((aligned(16))); + for (uint64_t ctr = *ctr_in_out; ctr < CTR_MAX; ctr++) { + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + xof_ctx_release_shake256(&ctx); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { + *ctr_in_out = ctr; + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + return 1; + } + } + // no good counter: pow has failed + return 0; +} + +EXPORT int proofow_verify_w_shake_cat5( // + proofow_ctx_t* proofow_state, // + void* delta0_out, // + const uint64_t ctr_value // +) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t H_PIOP_BYTES = 64; + struct proofow_shake_cat5_t* const s = (struct proofow_shake_cat5_t*)proofow_state; + const uint64_t ctr = ctr_value; + xof_ctx ctx __attribute((aligned(16))); + xof_init_and_seed_shake256(&ctx, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&ctx, &ctr, 4); + xof_finalize_and_output_shake256(&ctx, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) != 0) { + xof_ctx_release_shake256(&ctx); + return 0; + } + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); + xof_ctx_release_shake256(&ctx); + return 1; +} + +// 4-way batched SHAKE proof-of-work grind (AVX2 KeccakP-1600-times4). Drives 4 +// consecutive counters through one batched permutation instead of 4 scalar ones. The <4 tail near CTR_MAX falls back to the scalar path. +#define PROOFOW_GRIND_SHAKE_4WAY(CAT, SHAKE, HPB) \ + EXPORT int proofow_grind_w_shake_##CAT##_4way(proofow_ctx_t* proofow_state, \ + bitvec_t* delta0_out, uint64_t* ctr_in_out) {\ + static const uint64_t H_PIOP_BYTES = HPB; \ + static const uint64_t CTR_MAX = UINT64_C(1) << 32; \ + struct proofow_shake_##CAT##_t* const s = (struct proofow_shake_##CAT##_t*)proofow_state;\ + uint8_t xvbuf[sizeof(KeccakWidth1600times4_SpongeInstance) + 32] __attribute((aligned(64)));\ + xof_vector_ctx* const xv = (xof_vector_ctx*)xvbuf; \ + uint8_t buf[4][sizeof(s->delta0_and_vgrind)]; \ + uint32_t ctr32[4]; \ + uint8_t *ctr_ptrs[4], *out_ptrs[4]; \ + for (int j = 0; j < 4; j++) { \ + ctr_ptrs[j] = (uint8_t*)&ctr32[j]; \ + out_ptrs[j] = buf[j]; \ + } \ + uint64_t ctr = *ctr_in_out; \ + for (; ctr + 4 <= CTR_MAX; ctr += 4) { \ + for (int j = 0; j < 4; j++) ctr32[j] = (uint32_t)(ctr + j); \ + xof_vector_init_and_seed_##SHAKE(xv, 4, s->h_piop, H_PIOP_BYTES); \ + xof_vector_seed_##SHAKE(xv, 4, ctr_ptrs, 4); \ + xof_vector_finalize_and_output_##SHAKE(xv, 4, out_ptrs, s->delta0_and_vgrind_bytes); \ + for (int j = 0; j < 4; j++) \ + if (extract_kappabit_uint(s->w, s->kappa_tau, buf[j]) == 0) { \ + *ctr_in_out = ctr + j; \ + memcpy(delta0_out, buf[j], s->delta0_out_bytes); \ + xof_vector_ctx_release_##SHAKE(xv, 4); \ + return 1; \ + } \ + xof_vector_ctx_release_##SHAKE(xv, 4); \ + } \ + for (; ctr < CTR_MAX; ctr++) { /* <4 tail, byte-identical scalar path */ \ + xof_ctx c __attribute((aligned(16))); \ + xof_init_and_seed_##SHAKE(&c, s->h_piop, H_PIOP_BYTES); \ + xof_seed_##SHAKE(&c, &ctr, 4); \ + xof_finalize_and_output_##SHAKE(&c, s->delta0_and_vgrind, s->delta0_and_vgrind_bytes); \ + if (extract_kappabit_uint(s->w, s->kappa_tau, s->delta0_and_vgrind) == 0) { \ + *ctr_in_out = ctr; \ + memcpy(delta0_out, s->delta0_and_vgrind, s->delta0_out_bytes); \ + xof_ctx_release_##SHAKE(&c); \ + return 1; \ + } \ + xof_ctx_release_##SHAKE(&c); \ + } \ + return 0; \ + } +PROOFOW_GRIND_SHAKE_4WAY(cat1, shake128, 32) +PROOFOW_GRIND_SHAKE_4WAY(cat3, shake256, 48) +PROOFOW_GRIND_SHAKE_4WAY(cat5, shake256, 64) + +// set_2_b_minus_one (the last-block mask builder) is shared with the avx path, +// so it lives in sdith_prng_private.h. + +static inline void apply_last_blk_mask(uint64_t* res, const uint64_t* mask, uint64_t res_size) { + for (uint64_t i=0; irk, seed); + r->blocks_per_row = ((row_bit_size + 127) >> 7); // aes128 uses 128-bit block sizes + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 2, row_bit_size & 127); +} + +EXPORT void matrix_rng_init_rijndael256_cat3_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*) rng; + // the actual rijndael key is padded with zeroes + uint64_t key256[4] = {}; // ZERO + memcpy(key256, seed, 24); + rijndael256_key_schedule_x1_ref(r->rk, key256); + // we are using the full 256-bit rijndael block size, even if lambda is smaller. + r->blocks_per_row = ((row_bit_size + 255) >> 8); + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); +} + +EXPORT void matrix_rng_init_rijndael256_cat5_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*) rng; + rijndael256_key_schedule_x1_ref(r->rk, seed); + r->blocks_per_row = ((row_bit_size + 255) >> 8); // rijndael256 uses 256-bit block sizes + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); +} + +EXPORT void matrix_rng_release_aes128_cat1_ref(matrix_rng_t* rng) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + aes128_release_key(r->rk); +} + +// cat3/cat5 (and the avx cat1 path) expand their schedule inside the context. +EXPORT void matrix_rng_release_noop(matrix_rng_t* rng) { (void)rng; } + +EXPORT void matrix_rng_get_row_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); + ctr128_t* const cout = (ctr128_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr128_t ctr = {}; + ctr.v64[0] = row_index * bpr; + aes128_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask(cout[bpr - 1].v64, r->last_blk_mask.v64, 2); +} + +EXPORT void matrix_rng_get_row_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-bytes aligned"); + // cat3 is providing the same full rijndael256-ctr as cat 5 + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = row_index * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask(cout[bpr - 1].v64, r->last_blk_mask.v64, 4); +} + +EXPORT void matrix_rng_get_row_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = row_index * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask(cout[bpr - 1].v64, r->last_blk_mask.v64, 4); +} + +// Pre-processed challenge (see MATRIX_RNG_PREPROCESS_CHALL). With k = lambda/64, +// prep_chall[j] = chall[j / k] * X^(64 * (j % k)), +// so that = sum_j h_j * prep_chall[j] over the 64-bit words h_j of +// the row. The loop itself is preprocess_chall_generic in sdith_prng_private.h, +// shared with the avx path: only the field product differs, and both orderings +// of it give the very same table. + +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_aes128_cat1_t* r = (const struct matrix_rng_aes128_cat1_t*) rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), + 16, 2, gf128_flambda_product_ref); +} + +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_rijndael256_cat3_t* r = (const struct matrix_rng_rijndael256_cat3_t*) rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), + 24, 3, gf192_flambda_product_ref); +} + +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_rijndael256_cat5_t* r = (const struct matrix_rng_rijndael256_cat5_t*) rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), + 32, 4, gf256_flambda_product_ref); +} + +// Reference row-times-challenge (see MATRIX_RNG_ROWS_TIMES_CHALL). This is the +// definition transcribed literally: draw the row, split it into 64-bit words h_j, +// and accumulate sum_j h_j * prep_chall[j] with the ordinary field product and +// sum. Each h_j is a field element whose low 64 bits are the word and whose other +// bits are zero. No attempt is made to be quick: it is written to stay readable +// so it can serve as the oracle for the avx kernels, which are what the x86 +// build runs in production. +// +// Where there are no avx kernels this is the production path, and then the word +// decomposition does more work than it needs to. Writing k = lambda/64, the +// definition of the pre-processed challenge gives prep_chall[k*i] = chall[i] * +// X^0 = chall[i], so the sum collapses back to the plain limb dot product +// = sum_i row_limb[i] * prep_chall[k*i], +// running over the ceil(row_bits/lambda) limbs instead of the ceil(row_bits/64) +// words: k times fewer field products (k = 2, 3, 4 for cat1/cat3/cat5), and no +// change to the pre-processed challenge, so the two forms stay interchangeable. +// Reading whole limbs is in bounds because compute_rsd_codim_slice guarantees +// the row is wide enough to hold rsd_codim_limbs of them. Swap the inner loop +// for that form if a portable build ever needs the speed. +// +// The row is at most MATRIX_RNG_REF_MAX_ROW_BYTES; 2kB is a 16384-bit row, far +// above any rsd_codim. The buffer is 32-byte aligned as get_row requires. +#define MATRIX_RNG_REF_MAX_ROW_BYTES 2048 + +static void rows_times_chall_ref_generic( // + const matrix_rng_t* rng, flambda_t* dest, const flambda_t* prep_chall, // + const uint64_t first_row, const uint64_t nrows, // + const uint64_t row_bit_size, const uint64_t row_bytes, const uint64_t lambda_bytes, // + MATRIX_RNG_GET_ROW* get_row, FLAMBDA_PRODUCT_F* product, FLAMBDA_SUM_F* sum) { + CREQUIRE(row_bytes <= MATRIX_RNG_REF_MAX_ROW_BYTES, "row too wide (%ld bytes)", (long) row_bytes); + const uint64_t nwords = matrix_rng_prep_chall_nelems(row_bit_size); + const uint8_t* const pc = (const uint8_t*) prep_chall; + uint8_t* out = (uint8_t*) dest; + uint8_t row[MATRIX_RNG_REF_MAX_ROW_BYTES] __attribute__((aligned(32))); + for (uint64_t i = 0; i < nrows; ++i) { + get_row(rng, row, first_row + i); + flambda_max_t acc = {0, 0, 0, 0}; + for (uint64_t j = 0; j < nwords; ++j) { + // h_j: the j-th 64-bit word of the row, zero-extended to a field element + flambda_max_t h = {0, 0, 0, 0}; + memcpy(h, row + 8 * j, 8); + flambda_max_t term; + product(term, h, pc + j * lambda_bytes); + sum(acc, acc, term); + } + memcpy(out, acc, lambda_bytes); + out += lambda_bytes; + } +} + +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_aes128_cat1_t* r = (const struct matrix_rng_aes128_cat1_t*) rng; + rows_times_chall_ref_generic(rng, dest, prep_chall, first_row, nrows, // + r->row_bit_size, r->blocks_per_row * 16, 16, // + matrix_rng_get_row_aes128_cat1_ref, gf128_flambda_product_ref, + gf128_flambda_sum_ref); +} + +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_rijndael256_cat3_t* r = (const struct matrix_rng_rijndael256_cat3_t*) rng; + rows_times_chall_ref_generic(rng, dest, prep_chall, first_row, nrows, // + r->row_bit_size, r->blocks_per_row * 32, 24, // + matrix_rng_get_row_rijndael256_cat3_ref, gf192_flambda_product_ref, + gf192_flambda_sum_ref); +} + +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_rijndael256_cat5_t* r = (const struct matrix_rng_rijndael256_cat5_t*) rng; + rows_times_chall_ref_generic(rng, dest, prep_chall, first_row, nrows, // + r->row_bit_size, r->blocks_per_row * 32, 32, // + matrix_rng_get_row_rijndael256_cat5_ref, gf256_flambda_product_ref, + gf256_flambda_sum_ref); +} + +// Batched row generation. Rows first_row..first_row+nrows-1 occupy the counter +// range [first_row*bpr, (first_row+nrows)*bpr), which is contiguous, so the whole +// batch is one CTR call; only the per-row last-block masking is left to do. + +EXPORT void matrix_rng_get_rows_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*) rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); + ctr128_t* const cout = (ctr128_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr128_t ctr = {}; + ctr.v64[0] = first_row * bpr; + aes128_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask(cout[i * bpr + bpr - 1].v64, r->last_blk_mask.v64, 2); + } +} + +EXPORT void matrix_rng_get_rows_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-bytes aligned"); + // cat3 is providing the same full rijndael256-ctr as cat 5 + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = first_row * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask(cout[i * bpr + bpr - 1].v64, r->last_blk_mask.v64, 4); + } +} + +EXPORT void matrix_rng_get_rows_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*) rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*) out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = first_row * bpr; + rijndael256_ctrle_nocarry_nblocks_ref(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask(cout[i * bpr + bpr - 1].v64, r->last_blk_mask.v64, 4); + } +} + +// --- keygen prng (reference) ------------------------------------------------ +// The plain CTR keystream of the secret-key seed (see keygen_rng_ctx). Only the +// key differs between the three categories; the draw loop is the shared +// DEFINE_KEYGEN_RNG_NEXT_U32 body. + +EXPORT void keygen_rng_init_aes128_cat1_ref(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_aes128_cat1_t* s = (struct keygen_rng_aes128_cat1_t*) rng; + aes128_key_schedule_x1_ref(s->rk, sk_seed); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_init_rijndael256_cat3_ref(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_rijndael256_t* s = (struct keygen_rng_rijndael256_t*) rng; + // the 192-bit seed is padded with 64 zero bits in the MSB to make a rijndael256 key + uint64_t key256[4] = {}; // ZERO + memcpy(key256, sk_seed, 24); + rijndael256_key_schedule_x1_ref(s->rk, key256); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_init_rijndael256_cat5_ref(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_rijndael256_t* s = (struct keygen_rng_rijndael256_t*) rng; + rijndael256_key_schedule_x1_ref(s->rk, sk_seed); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_release_aes128_cat1_ref(keygen_rng_ctx* rng) { + struct keygen_rng_aes128_cat1_t* s = (struct keygen_rng_aes128_cat1_t*) rng; + aes128_release_key(s->rk); +} + +// cat3/cat5 (and the avx cat1 path) expand their schedule inside the context. +EXPORT void keygen_rng_release_noop(keygen_rng_ctx* rng) { (void)rng; } + +DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_aes128_cat1_ref, keygen_rng_aes128_cat1_t, ctr128_t, + aes128_ctrle_nocarry_nblocks_ref) +DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_rijndael256_ref, keygen_rng_rijndael256_t, ctr256_t, + rijndael256_ctrle_nocarry_nblocks_ref) diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng.h new file mode 100644 index 0000000000..e6bf87e415 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng.h @@ -0,0 +1,663 @@ +#ifndef AQ_VOLE_IMPL_RNG_H +#define AQ_VOLE_IMPL_RNG_H + +#include "commons.h" + +#ifdef SDITH3_FOR_LIBOQS +#include +#endif + +/** + * Domain separation of the GGM tree and vole PRNGs. + * + * compute_tweaked_salts derives, from the lambda-bit global salt, one masked + * salt per PRNG family: the two most significant bits carry the family prefix + * and the GGM_TWEAK_BITS least significant bits are cleared. Each PRNG call ORs + * its own tweak into that cleared field and uses the result as the lambda-bit + * initial CTR plaintext: + * - GGM seed / commit rng: the tweak is the node index (times 2, since each + * call consumes two consecutive counters), + * - vole rng: the tweak is repet_idx << VOLE_RNG_REPET_SHIFT, so the block + * counter of the call occupies the low VOLE_RNG_REPET_SHIFT bits. + */ +#define GGM_TWEAK_BITS 24 +#define VOLE_RNG_REPET_SHIFT 16 + +/** proof of work: state init */ +typedef struct proofow_ctx_t proofow_ctx_t; +typedef uint64_t BYTES_OF_PROOFOW_CTX_F(); +typedef void PROOFOW_INIT_F( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +typedef int PROOFOW_GRIND_W_F( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + uint64_t* ctr_in_out // +); +typedef int PROOFOW_VERIFY_W_F( // + proofow_ctx_t* proofow_state, // + bitvec_t* delta0_out, // + const uint64_t ctr_value // +); +/** proof of work: release whatever the init took hold of */ +typedef void PROOFOW_RELEASE_F(proofow_ctx_t* proofow_state); +// Only the cat1 cipher variant owns anything: its two aes128 schedules are heap +// contexts on the liboqs backend (see aes_ansi_ref.h). The cat3/cat5 cipher +// variants expand rijndael256 in place, the avx cat1 one expands aes128 in +// place, and the shake variants hold no cipher state at all, so all of those +// take proofow_release_noop. +EXPORT void proofow_release_cipher_cat1_ref(proofow_ctx_t* proofow_state); +EXPORT void proofow_release_noop(proofow_ctx_t* proofow_state); +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat1(); +EXPORT void proofow_init_cipher_cat1_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT void proofow_init_cipher_cat1_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat1_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); +EXPORT int proofow_verify_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat5(); +EXPORT void proofow_init_cipher_cat5_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat5_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); +EXPORT void proofow_init_cipher_cat5_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); + +// cipher-based proof of work (cat3: rijndael256 block cipher + shake256 xof, h_piop = 48 bytes) + +EXPORT uint64_t bytes_of_proofow_ctx_cipher_cat3(); +EXPORT void proofow_init_cipher_cat3_ref( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat3_ref(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); +EXPORT void proofow_init_cipher_cat3_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr); + +// shake-based proof of work + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat1(); +EXPORT void proofow_init_shake_cat1( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_shake_cat1(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_shake_cat1_4way(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_shake_cat1(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr_value); + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat3(); +EXPORT void proofow_init_shake_cat3( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_shake_cat3(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_shake_cat3_4way(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_shake_cat3(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr_value); + +EXPORT uint64_t bytes_of_proofow_ctx_shake_cat5(); +EXPORT void proofow_init_shake_cat5( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +); +EXPORT int proofow_grind_w_shake_cat5(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_grind_w_shake_cat5_4way(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out); +EXPORT int proofow_verify_w_shake_cat5(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr_value); + + +// ggm seed rng, extended-seed variants: same as ggm_seed_rng_lr_* but the +// node_seed points at the expanded round keys (skips the key schedule). Output +// is byte-identical to the raw variant fed the matching extend_leaf_seed output. +typedef void GGM_EXTSEED_RNG_LR_F(void* lr_out, const void* salt, const void* extended_seed, uint64_t node_idx, uint32_t theta); +// x4 variant (I8): expand 4 sibling parent nodes (node_idx0, +2, +4, +6) in one call. +// extended_seeds = 4 contiguous extended keys, lr_out = 4 contiguous 2-seed outputs. +// Byte-identical to four GGM_EXTSEED_RNG_LR_F calls (KAT-preserving). It is always set: +// the cat1 avx2 build uses a batched kernel (4 keys x 2 blocks = 8 cipher blocks run +// interleaved, saturating the AES-NI port); every other build uses a naive wrapper that +// just does the four single calls, so the loop can always call this with no branch. +typedef void GGM_EXTSEED_RNG_LR_X4_F(void* lr_out, const void* salt, const void* extended_seeds, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2( // batched kernel + void* lr_out, const void* salt128, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_x4_ref( // naive four calls + void* lr_out, const void* salt128, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref( // naive four calls + void* lr_out, const void* salt192, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2( // naive four calls + void* lr_out, const void* salt192, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref( // naive four calls + void* lr_out, const void* salt256, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2( // naive four calls + void* lr_out, const void* salt256, const void* extkeys4, uint64_t node_idx0, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_ref( // + void* lr_out256, const void* salt128, const void* extkey128, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_avx2( // + void* lr_out256, const void* salt128, const void* extkey128, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_ref( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_avx2( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_ref( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta); +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_avx2( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta); + + +/** + * Extended leaf seed: the AES/Rijndael key schedule is run once per leaf, and + * the resulting "extended seed" is shared by both the commit rng and the vole + * rng (saving the second, redundant key schedule). For aes/rijndael the + * extended seed is the expanded round keys; for shake it is just the raw seed. + * + * - EXTEND_LEAF_SEED_F turns a raw node_seed into an extended_seed. + * - EXTENDED_NODE_SEED_BYTES_F returns the byte size of the extended seed. + * - the ggm_commit_rng_ext_* / vole_rng_ext_* variants consume the extended + * seed (key/node_seed points at the round keys instead of the raw seed). + * + * The original ggm_commit_rng_* / vole_rng_* symbols are retained as raw-seed + * shims (extend + ext), so callers passing a raw seed still get identical bytes. + */ +typedef void EXTEND_LEAF_SEED_F(void* extended_seed_out, const void* node_seed); +typedef uint64_t EXTENDED_NODE_SEED_BYTES_F(void); + +/** + * 4x leaf-seed expansion: extend four contiguous node_seeds into four contiguous + * extended_seeds in one call, for the BFS ggm traversal. Inputs and outputs are + * packed at their natural stride (node_seed size in, extended_seed size out). + * Output is byte-identical to calling EXTEND_LEAF_SEED_F four times, so it is + * KAT-preserving. The _ref variants call the 1x function four times; the _avx2 + * variants dispatch to the batched key-schedule kernels (aes128 x4, rijndael x2). + */ +typedef void EXTEND_LEAF_SEED_4X_F(void* extended_seed_out, const void* node_seed); + +EXPORT void extend_leaf_seed_cat1_aes128_ref(void* extended_seed_out, const void* seed128); + +/** When building for liboqs, cat1 aes128 uses the liboqs backend, which requires + * the extended-seed buffer to be prepared/released. See aes_ansi_ref.h for details. */ +typedef void EXTSEED_BUF_F(void* buf, uint64_t nslots, uint64_t slot_bytes); + +EXPORT void prepare_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes); +EXPORT void release_extseed_buf_cat1_aes128_ref(void* buf, uint64_t nslots, uint64_t slot_bytes); +EXPORT void extseed_buf_noop(void* buf, uint64_t nslots, uint64_t slot_bytes); +EXPORT void extend_leaf_seed_cat1_aes128_avx2(void* extended_seed_out, const void* seed128); +EXPORT void extend_leaf_seed_cat3_rijndael256_ref(void* extended_seed_out, const void* seed192); +EXPORT void extend_leaf_seed_cat3_rijndael256_avx2(void* extended_seed_out, const void* seed192); +EXPORT void extend_leaf_seed_cat5_rijndael256_ref(void* extended_seed_out, const void* seed256); +EXPORT void extend_leaf_seed_cat5_rijndael256_avx2(void* extended_seed_out, const void* seed256); + +EXPORT void extend_leaf_seed_cat1_aes128_4x_ref(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat1_aes128_4x_avx2(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_ref(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_avx2(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_ref(void* extended_seed_out, const void* seeds); +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_avx2(void* extended_seed_out, const void* seeds); + +EXPORT uint64_t extended_node_seed_bytes_cat1_aes128(void); +EXPORT uint64_t extended_node_seed_bytes_cat3_rijndael256(void); +EXPORT uint64_t extended_node_seed_bytes_cat5_rijndael256(void); + +// commit rng, extended-seed variants (key points at the expanded round keys). +// The masked salt produced by compute_tweaked_salts reserves the low +// GGM_TWEAK_BITS bits for the tweak, so theta is that constant and is not an argument. +typedef void GGM_EXTSEED_RNG_COMMIT_F( + void* out, + const void* salt, + const void* extended_seed, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat1_aes128_ref(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat1_aes128_avx2(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_ref(void* output384, const void* salt192, const void* extkey, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_avx2(void* output384, const void* salt192, const void* extkey, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_ref(void* output512, const void* salt256, const void* extkey, + uint64_t node_idx); +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_avx2(void* output512, const void* salt256, const void* extkey, + uint64_t node_idx); + +// vole rng, extended-seed variants (node_seed points at the expanded round keys). +// +// The CTR stream starts at the tweaked salt of the repetition: the lambda-bit +// initial counter is +// vole_masked_salt | (repet_idx << VOLE_RNG_REPET_SHIFT) +// (vole_masked_salt comes from compute_tweaked_salts and has its low +// GGM_TWEAK_BITS bits cleared, so the OR is a plain field write). The block +// counter therefore lives in the low VOLE_RNG_REPET_SHIFT bits, which bounds a +// single call to 2^VOLE_RNG_REPET_SHIFT blocks; debug builds assert it via +// domain_sep_check so the last block can never spill into the next repetition. +typedef void VOLE_EXTSEED_RNG_F(void* out, uint64_t out_bytes, const void* vole_masked_salt, + const void* extended_seed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat1_aes128_ctrle_ref(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx); + +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_ref(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx); +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx); + + +#ifndef SDITH3_FOR_LIBOQS +typedef struct xof_ctx_t { + uint64_t DUMMY[224 / 8]; +} xof_ctx; +#else +typedef struct xof_ctx_t { + uint32_t shake; // 128 or 256, set by Keccak_HashInitialize_SHAKE* + union { + OQS_SHA3_shake128_inc_ctx shake128_state; + OQS_SHA3_shake256_inc_ctx shake256_state; + }; +} xof_ctx; +#endif + +typedef void XOF_INIT_F(xof_ctx* xof); +EXPORT void xof_init_shake128(xof_ctx* xof); +EXPORT void xof_init_shake256(xof_ctx* xof); + +typedef void XOF_SEED_F(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes); + +typedef void XOF_FINALIZE_F(xof_ctx* xof); +EXPORT void xof_finalize_shake128(xof_ctx* xof); +EXPORT void xof_finalize_shake256(xof_ctx* xof); + +typedef void XOF_OUTPUT_F(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes); + +// shortcut combo +typedef void XOF_INIT_AND_SEED_F(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_init_and_seed_shake128(xof_ctx* xof, const void* in, uint64_t in_bytes); +EXPORT void xof_init_and_seed_shake256(xof_ctx* xof, const void* in, uint64_t in_bytes); + +typedef void XOF_FINALIZE_AND_OUTPUT_F(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_finalize_and_output_shake128(xof_ctx* xof, void* out, uint64_t out_bytes); +EXPORT void xof_finalize_and_output_shake256(xof_ctx* xof, void* out, uint64_t out_bytes); + +// liboqs requires context be released. When not using liboqs, context is on the stack and this is a no-op. +typedef void XOF_CTX_RELEASE_F(xof_ctx* xof); +EXPORT void xof_ctx_release_shake128(xof_ctx* xof); +EXPORT void xof_ctx_release_shake256(xof_ctx* xof); + +typedef struct xof_functions_t { + XOF_INIT_F* xof_init; + XOF_SEED_F* xof_seed; + XOF_FINALIZE_F* xof_finalize; + XOF_OUTPUT_F* xof_output; + XOF_INIT_AND_SEED_F* xof_init_and_seed; + XOF_FINALIZE_AND_OUTPUT_F* xof_finalize_and_output; + XOF_CTX_RELEASE_F* xof_ctx_release; +} xof_functions; + +static const xof_functions xof_shake128 = { + xof_init_shake128, // + xof_seed_shake128, // + xof_finalize_shake128, // + xof_output_shake128, // + xof_init_and_seed_shake128, // + xof_finalize_and_output_shake128, // + xof_ctx_release_shake128 // +}; +static const xof_functions xof_shake256 = { + xof_init_shake256, // + xof_seed_shake256, // + xof_finalize_shake256, // + xof_output_shake256, // + xof_init_and_seed_shake256, // + xof_finalize_and_output_shake256, // + xof_ctx_release_shake256 // +}; + +typedef struct xof_vector_ctx_t xof_vector_ctx; + +typedef uint64_t XOF_VECTOR_CTX_BYTES_F(uint64_t num_xofs); +EXPORT uint64_t xof_vector_ctx_bytes_shake128(uint64_t num_xofs); +EXPORT uint64_t xof_vector_ctx_bytes_shake256(uint64_t num_xofs); + +typedef void XOF_VECTOR_INIT_AND_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); +EXPORT void xof_vector_init_and_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); +EXPORT void xof_vector_init_and_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, const uint8_t* data, uint64_t data_bytes); + +typedef void XOF_VECTOR_SEED_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); +EXPORT void xof_vector_seed_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); +EXPORT void xof_vector_seed_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** data, uint64_t data_bytes); + +typedef void XOF_VECTOR_FINALIZE_AND_OUTPUT_F(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); +EXPORT void xof_vector_finalize_and_output_shake128(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); +EXPORT void xof_vector_finalize_and_output_shake256(xof_vector_ctx* xof, uint64_t num_xofs, uint8_t** out_hashes, uint64_t hash_bytes); + +// liboqs requires context be released. When not using liboqs, context is on the stack and this is a no-op. +typedef void XOF_VECTOR_CTX_RELEASE_F(xof_vector_ctx* xof, uint64_t num_xofs); +EXPORT void xof_vector_ctx_release_shake128(xof_vector_ctx* xof, uint64_t num_xofs); +EXPORT void xof_vector_ctx_release_shake256(xof_vector_ctx* xof, uint64_t num_xofs); + +typedef struct xof_vector_functions_t { + XOF_VECTOR_CTX_BYTES_F* ctx_bytes; + XOF_VECTOR_INIT_AND_SEED_F* init_and_seed; + XOF_VECTOR_SEED_F* seed; + XOF_VECTOR_FINALIZE_AND_OUTPUT_F* finalize_and_output; + XOF_VECTOR_CTX_RELEASE_F* ctx_release; +} xof_vector_functions; + +static const xof_vector_functions xof_vector_shake128 = { + xof_vector_ctx_bytes_shake128, // + xof_vector_init_and_seed_shake128, // + xof_vector_seed_shake128, // + xof_vector_finalize_and_output_shake128, // + xof_vector_ctx_release_shake128 // +}; + +static const xof_vector_functions xof_vector_shake256 = { + xof_vector_ctx_bytes_shake256, // + xof_vector_init_and_seed_shake256, // + xof_vector_seed_shake256, // + xof_vector_finalize_and_output_shake256, // + xof_vector_ctx_release_shake256 // +}; + + +typedef struct matrix_rng_t { + uint8_t DUMMY[1024]; // large enough t +} __attribute((aligned(32))) matrix_rng_t; + +typedef void MATRIX_RNG_INIT(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_aes128_cat1_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_aes128_cat1_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat3_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat3_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat5_ref(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); +EXPORT void matrix_rng_init_rijndael256_cat5_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size); + +// Releases whatever matrix_rng_init took hold of. +// Only active in the cat1 aes128 ref path when building for liboqs, where key schedules +// are heap-allocated (see aes_ansi_ref.h for details). +// The avx and rijndael256 paths expand in place, so they take matrix_rng_release_noop. +typedef void MATRIX_RNG_RELEASE(matrix_rng_t* rng); +EXPORT void matrix_rng_release_aes128_cat1_ref(matrix_rng_t* rng); +EXPORT void matrix_rng_release_noop(matrix_rng_t* rng); + +typedef void MATRIX_RNG_GET_ROW(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat3_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t row_index); +EXPORT void matrix_rng_get_row_rijndael256_cat5_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index); + +// Batched counterpart of MATRIX_RNG_GET_ROW: draws the nrows consecutive rows +// first_row, first_row+1, ..., first_row+nrows-1 and writes them back to back in +// out (no gap: the stride is the natural row size bpr*block_bytes, which is the +// rsd_codim_slice of compute_rsd_codim_slice). Because row i is the bpr cipher +// blocks at counter i*bpr, a run of consecutive rows is one contiguous stretch +// of the CTR keystream, so the whole batch is a single cipher call. Output is +// byte-identical to nrows successive get_row calls (KAT-preserving); the point +// is to amortise the per-row call and counter-setup glue, which costs as much as +// the AES itself at these row sizes. +typedef void MATRIX_RNG_GET_ROWS(const matrix_rng_t* rng, void* out, const uint64_t first_row, const uint64_t nrows); +EXPORT void matrix_rng_get_rows_aes128_cat1_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat3_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat3_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat5_ref(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_get_rows_rijndael256_cat5_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows); + +// Fused row generation + challenge multiplication. +// +// rows_times_chall computes dest[i] = for nrows +// consecutive rows, without ever materialising the rows. Generating a row and +// reducing it against the challenge use disjoint execution ports (the cipher +// rounds vs the carry-less multiplier), so fusing them into one loop hides the +// whole field reduction behind the cipher; splitting it across two calls, as a +// get_rows + flambda_dot_product pair must, makes the two costs additive. +// +// The challenge is passed pre-processed. Writing k = lambda/64 and splitting a +// row into 64-bit words h_j, the definition = sum_i H_i * chall_i +// rearranges into sum_j h_j * prep_chall[j] with +// prep_chall[j] = chall[j / k] * X^(64 * (j % k)), +// which is what preprocess_chall builds (once per challenge, reused for every +// row). Each h_j is then a field element with only its low 64 bits populated, so +// each term is a 64-by-lambda multiply: fewer accumulators than the balanced +// Karatsuba form, and the accumulated high part is only 64 bits, so the final +// reduction is a single carry-less multiply instead of a chained fold. It also +// shortens the vector: prep_chall has ceil(row_bits/64) entries rather than the +// ceil(row_bits/lambda)*k words the limb form has to pad up to. +// +// Both take the row bit size from the rng context (stored by init), so the +// pre-processed challenge and the kernel can never disagree on its length. +// dest holds nrows field elements; prep_chall holds matrix_rng_prep_chall_nelems +// of them. Output is identical to the get_rows + flambda_dot_product pair. +typedef void MATRIX_RNG_PREPROCESS_CHALL(const matrix_rng_t* rng, flambda_t* prep_chall, const flambda_t* chall); +typedef void MATRIX_RNG_ROWS_TIMES_CHALL(const matrix_rng_t* rng, flambda_t* dest, const flambda_t* prep_chall, + const uint64_t first_row, const uint64_t nrows); + +/** number of field elements in the pre-processed challenge, for a given row bit size */ +static inline uint64_t matrix_rng_prep_chall_nelems(const uint64_t row_bit_size) { return (row_bit_size + 63) >> 6; } + +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_avx(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_avx(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_ref(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_avx(const matrix_rng_t* rng, flambda_t* dest, + const flambda_t* prep_chall, const uint64_t first_row, + const uint64_t nrows); + +// A matrix prng: init once from a seed for a fixed row bit size, then draw any +// row independently via get_row (row i = the ceil(row_bits/lambda) cipher blocks +// at counter i*bpr, with bits beyond row_bits masked to zero). +// +// Every entry is mandatory: each category has both a ref and an avx +// implementation of the fused rows_times_chall, so callers use it unconditionally +// rather than falling back to the get_rows + flambda_dot_product pair. +typedef struct matrix_rng_functions_t { + MATRIX_RNG_INIT* matrix_rng_init; + MATRIX_RNG_RELEASE* matrix_rng_release; + MATRIX_RNG_GET_ROW* matrix_rng_get_row; + MATRIX_RNG_GET_ROWS* matrix_rng_get_rows; + MATRIX_RNG_PREPROCESS_CHALL* matrix_rng_preprocess_chall; + MATRIX_RNG_ROWS_TIMES_CHALL* matrix_rng_rows_times_chall; +} matrix_rng_functions; + +static const matrix_rng_functions matrix_rng_cat1_aes128_ref = { + matrix_rng_init_aes128_cat1_ref, // + matrix_rng_release_aes128_cat1_ref, // + matrix_rng_get_row_aes128_cat1_ref, // + matrix_rng_get_rows_aes128_cat1_ref, // + matrix_rng_preprocess_chall_aes128_cat1_ref, // + matrix_rng_rows_times_chall_aes128_cat1_ref, // +}; +static const matrix_rng_functions matrix_rng_cat3_rijndael256_ref = { + matrix_rng_init_rijndael256_cat3_ref, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat3_ref, // + matrix_rng_get_rows_rijndael256_cat3_ref, // + matrix_rng_preprocess_chall_rijndael256_cat3_ref, // + matrix_rng_rows_times_chall_rijndael256_cat3_ref, // +}; +static const matrix_rng_functions matrix_rng_cat5_rijndael256_ref = { + matrix_rng_init_rijndael256_cat5_ref, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat5_ref, // + matrix_rng_get_rows_rijndael256_cat5_ref, // + matrix_rng_preprocess_chall_rijndael256_cat5_ref, // + matrix_rng_rows_times_chall_rijndael256_cat5_ref, // +}; +// ONLY_REF_IMPLEMENTATION drops the *_avx2.c translation units, so these tables +// would hold undefined references: they are only compiled with the avx2 backend. +#if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) +static const matrix_rng_functions matrix_rng_cat1_aes128_avx = { + matrix_rng_init_aes128_cat1_avx, // + matrix_rng_release_noop, // + matrix_rng_get_row_aes128_cat1_avx, // + matrix_rng_get_rows_aes128_cat1_avx, // + matrix_rng_preprocess_chall_aes128_cat1_avx, // + matrix_rng_rows_times_chall_aes128_cat1_avx, // +}; +static const matrix_rng_functions matrix_rng_cat3_rijndael256_avx = { + matrix_rng_init_rijndael256_cat3_avx, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat3_avx, // + matrix_rng_get_rows_rijndael256_cat3_avx, // + matrix_rng_preprocess_chall_rijndael256_cat3_avx, // + matrix_rng_rows_times_chall_rijndael256_cat3_avx, // +}; +static const matrix_rng_functions matrix_rng_cat5_rijndael256_avx = { + matrix_rng_init_rijndael256_cat5_avx, // + matrix_rng_release_noop, // + matrix_rng_get_row_rijndael256_cat5_avx, // + matrix_rng_get_rows_rijndael256_cat5_avx, // + matrix_rng_preprocess_chall_rijndael256_cat5_avx, // + matrix_rng_rows_times_chall_rijndael256_cat5_avx, // +}; +#endif + +// The keygen prng: the secret-key seed expanded into the little-endian uint32 +// stream the rsd position sampler draws from. It is a plain block-cipher CTR +// keystream with a zero IV, nothing more: +// cat1: aes128, key = the 16-byte seed +// cat3: rijndael256, key = the 24-byte seed padded with 64 zero bits in the MSB +// cat5: rijndael256, key = the 32-byte seed +// The counter is little-endian over the low 64 bits (the same no-carry CTR the +// rest of the prngs use), so block i is enc(i) and the stream is the blocks +// concatenated. lambda/8 is a multiple of 4 for every category, so a draw never +// straddles a block boundary. +typedef struct keygen_rng_ctx_t { + uint8_t DUMMY[1024]; // large enough for any category +} __attribute((aligned(32))) keygen_rng_ctx; + +typedef void KEYGEN_RNG_INIT(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_aes128_cat1_ref(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_aes128_cat1_avx(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat3_ref(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat3_avx(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat5_ref(keygen_rng_ctx* rng, const seed_t* sk_seed); +EXPORT void keygen_rng_init_rijndael256_cat5_avx(keygen_rng_ctx* rng, const seed_t* sk_seed); + +typedef uint32_t KEYGEN_RNG_NEXT_U32(keygen_rng_ctx* rng); +EXPORT uint32_t keygen_rng_next_u32_aes128_cat1_ref(keygen_rng_ctx* rng); +EXPORT uint32_t keygen_rng_next_u32_aes128_cat1_avx(keygen_rng_ctx* rng); +// cat3 and cat5 only differ in the key they are initialised with, so they share +// their draw function: the rijndael256 one. +EXPORT uint32_t keygen_rng_next_u32_rijndael256_ref(keygen_rng_ctx* rng); +EXPORT uint32_t keygen_rng_next_u32_rijndael256_avx(keygen_rng_ctx* rng); + +// Releases whatever keygen_rng_init took hold of: as for matrix_rng, only the +// cat1 aes128 ref path owns a schedule. +typedef void KEYGEN_RNG_RELEASE(keygen_rng_ctx* rng); +EXPORT void keygen_rng_release_aes128_cat1_ref(keygen_rng_ctx* rng); +EXPORT void keygen_rng_release_noop(keygen_rng_ctx* rng); + +typedef struct keygen_rng_functions_t { + KEYGEN_RNG_INIT* init; + KEYGEN_RNG_RELEASE* release; + KEYGEN_RNG_NEXT_U32* next_u32; +} keygen_rng_functions; + +static const keygen_rng_functions keygen_rng_cat1_aes128_ref = { + keygen_rng_init_aes128_cat1_ref, // + keygen_rng_release_aes128_cat1_ref, // + keygen_rng_next_u32_aes128_cat1_ref, // +}; +static const keygen_rng_functions keygen_rng_cat3_rijndael256_ref = { + keygen_rng_init_rijndael256_cat3_ref, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_ref, // +}; +static const keygen_rng_functions keygen_rng_cat5_rijndael256_ref = { + keygen_rng_init_rijndael256_cat5_ref, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_ref, // +}; +#if defined(__x86_64__) && !defined(ONLY_REF_IMPLEMENTATION) +static const keygen_rng_functions keygen_rng_cat1_aes128_avx = { + keygen_rng_init_aes128_cat1_avx, // + keygen_rng_release_noop, // + keygen_rng_next_u32_aes128_cat1_avx, // +}; +static const keygen_rng_functions keygen_rng_cat3_rijndael256_avx = { + keygen_rng_init_rijndael256_cat3_avx, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_avx, // +}; +static const keygen_rng_functions keygen_rng_cat5_rijndael256_avx = { + keygen_rng_init_rijndael256_cat5_avx, // + keygen_rng_release_noop, // + keygen_rng_next_u32_rijndael256_avx, // +}; +#endif + +#endif // AQ_VOLE_IMPL_RNG_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng_avx2.c new file mode 100644 index 0000000000..552a369d14 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng_avx2.c @@ -0,0 +1,907 @@ +#include +#include +#include +#include + +#include "sdith_prng_private.h" +#include "vole_private.h" + + + +// ggm seed rng, extended-seed variants (avx2): encrypt with the precomputed round +// keys (encrypt_nblocks) instead of scheduling in oneshot. Same domain sep as the +// raw variant (node_idx, not node_idx<<1), so byte-identical to the raw output. +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_avx2(void* lr_out256, const void* salt128, const void* extkey128, + uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + CASSERT(domain_sep_check(salt128, node_idx, 2, theta), "bug! invalid separation"); + __m128i ctr = domain_sep_ptx_lo2_m128(salt128, node_idx); + aes128_ctrle_nocarry_2block_avx2(lr_out256, extkey128, &ctr); +} +// I8: batched 4-node variant. Expands parents node_idx0, +2, +4, +6 in one interleaved +// 8-block encrypt so the AES-NI port stays saturated. extkeys4 = 4 contiguous extended +// keys (176 B each); lr_out = 4 contiguous 2-seed outputs. Byte-identical to four calls of +// ggm_seed_rng_lr_ext_cat1_aes128_avx2 (KAT-preserving). +EXPORT void ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2(void* lr_out, const void* salt128, + const void* extkeys4, uint64_t node_idx0, uint32_t theta) { + CASSERT((node_idx0 & 1) == 0, "bug! this function must be called on the left child index"); + __m128i ctr[4]; + for (int i = 0; i < 4; i++) { + CASSERT(domain_sep_check(salt128, node_idx0 + 2 * i, 2, theta), "bug! invalid separation"); + ctr[i] = domain_sep_ptx_lo2_m128(salt128, node_idx0 + 2 * i); + } + aes128_ctrle_nocarry_2blk_x4keys_avx2(lr_out, extkeys4, ctr); +} +EXPORT void ggm_seed_rng_lr_ext_cat3_rijndael256_avx2( // + void* lr_out384, const void* salt192, const void* extkey, uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + uint8_t out512[64] = {}; + CASSERT(domain_sep_check(salt192, node_idx, 2, theta), "bug! invalid separation"); + ctr256_vec ctr = domain_sep_ptx_lo2_m256_from192(salt192, node_idx); + rijndael256_ctrle_nocarry_2block_avx2(out512, extkey, &ctr); + // cat3 Enc = LSB_192(Rijndael-256): keep the low 24 bytes of each block + memcpy(lr_out384, out512, 24); + memcpy((uint8_t*)lr_out384 + 24, out512 + 32, 24); +} +EXPORT void ggm_seed_rng_lr_ext_cat5_rijndael256_avx2( // + void* lr_out512, const void* salt256, const void* extkey, uint64_t node_idx, uint32_t theta) { + CASSERT((node_idx & 1) == 0, "bug! this function must be called on the left child index"); + CASSERT(domain_sep_check(salt256, node_idx, 2, theta), "bug! invalid separation"); + ctr256_vec ctr = domain_sep_ptx_lo2_m256(salt256, node_idx); + rijndael256_ctrle_nocarry_2block_avx2(lr_out512, extkey, &ctr); +} +// I8: naive x4 wrappers (avx2). cat3/cat5 rijndael has no batched key trick on this +// box (no vaes), so these just do the four single calls. cat1 avx2 uses the batched +// kernel above. LR_STRIDE = 2 * lambda_bytes, EXT_STRIDE = one extended key. +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2, // + ggm_seed_rng_lr_ext_cat3_rijndael256_avx2, 48, RIJNDAEL256_RK_BYTES) +GGM_EXTSEED_RNG_LR_X4_NAIVE(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2, // + ggm_seed_rng_lr_ext_cat5_rijndael256_avx2, 64, RIJNDAEL256_RK_BYTES) + +// extended leaf seed (avx2): run the key schedule once, share commit + vole. +EXPORT void extend_leaf_seed_cat1_aes128_avx2(void* extended_seed_out, const void* seed128) { + aes128_key_schedule_x1_avx2(extended_seed_out, seed128); +} +EXPORT void extend_leaf_seed_cat3_rijndael256_avx2(void* extended_seed_out, const void* seed192) { + uint8_t key256[32] = {}; // k || 0^64 + memcpy(key256, seed192, 24); + rijndael256_key_schedule_x1_avx2(extended_seed_out, key256); +} +EXPORT void extend_leaf_seed_cat5_rijndael256_avx2(void* extended_seed_out, const void* seed256) { + rijndael256_key_schedule_x1_avx2(extended_seed_out, seed256); +} + +// 4x leaf-seed expansion (avx2): dispatch to the batched key-schedule kernels. +// Seeds/outputs are packed at their natural stride; output is byte-identical to +// four 1x calls (KAT-preserving). All three use an x4 kernel that interleaves the +// four independent keys to hide the SubWord (aesenclast) latency. +EXPORT void extend_leaf_seed_cat1_aes128_4x_avx2(void* extended_seed_out, const void* seeds) { + uint8_t* o = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + aes128_key_schedule_x4_avx2(o, o + 176, o + 352, o + 528, s, s + 16, s + 32, s + 48); +} +EXPORT void extend_leaf_seed_cat3_rijndael256_4x_avx2(void* extended_seed_out, const void* seeds) { + uint8_t* o = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + uint8_t k[4][32] = {}; // each seed padded to k || 0^64 + for (int i = 0; i < 4; i++) memcpy(k[i], s + i * 24, 24); + rijndael256_key_schedule_x4_avx2(o, o + 480, o + 960, o + 1440, k[0], k[1], k[2], k[3]); +} +EXPORT void extend_leaf_seed_cat5_rijndael256_4x_avx2(void* extended_seed_out, const void* seeds) { + uint8_t* o = (uint8_t*)extended_seed_out; + const uint8_t* s = (const uint8_t*)seeds; + rijndael256_key_schedule_x4_avx2(o, o + 480, o + 960, o + 1440, s, s + 32, s + 64, s + 96); +} + +// commit rng, extended-seed cores (avx2): encrypt with the precomputed round keys. +EXPORT void ggm_commit_rng_ext_cat1_aes128_avx2(void* output256, const void* salt128, const void* extkey128, + uint64_t node_idx) { + CASSERT(domain_sep_check(salt128, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + __m128i ctr = domain_sep_ptx_lo2_m128(salt128, node_idx << 1); + aes128_ctrle_nocarry_2block_avx2(output256, extkey128, &ctr); +} +EXPORT void ggm_commit_rng_ext_cat3_rijndael256_avx2( // + void* output384, const void* salt192, const void* extkey, uint64_t node_idx) { + uint8_t output512[64] = {}; // pad with zeroes + CASSERT(domain_sep_check(salt192, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + ctr256_vec ctr = domain_sep_ptx_lo2_m256_from192(salt192, node_idx << 1); + rijndael256_ctrle_nocarry_2block_avx2(output512, extkey, &ctr); + // cat3 Enc = LSB_192(Rijndael-256): keep the low 24 bytes of each block + memcpy(output384, output512, 24); + memcpy((uint8_t*)output384 + 24, output512 + 32, 24); +} +EXPORT void ggm_commit_rng_ext_cat5_rijndael256_avx2( // + void* output512, const void* salt256, const void* extkey, uint64_t node_idx) { + CASSERT(domain_sep_check(salt256, node_idx << 1, 2, GGM_TWEAK_BITS), "bug! invalid separation"); + ctr256_vec ctr = domain_sep_ptx_lo2_m256(salt256, node_idx << 1); + rijndael256_ctrle_nocarry_2block_avx2(output512, extkey, &ctr); +} + +// vole rng, extended-seed cores (avx2): adopt the precomputed round keys. +// The counter starts at the salt tweaked by the repetition index (see +// VOLE_RNG_REPET_SHIFT), and the domain_sep_check asserts that the last block of +// the stream still fits in the tweak field. +EXPORT void vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2(void* out, uint64_t out_bytes, const void* salt128, + const void* extseed, uint64_t repet_idx) { + CASSERT((out_bytes & 15)==0, "bug! out_bytes must be multiple of 16"); + CASSERT(domain_sep_check(salt128, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 4, GGM_TWEAK_BITS), + "bug! invalid separation"); + __m128i ctr = domain_sep_ptx_lo2_m128(salt128, repet_idx << VOLE_RNG_REPET_SHIFT); + aes128_ctrle_nocarry_nblocks_avx2(out, extseed, &ctr, out_bytes >> 4); +} +EXPORT void vole_rng_ext_cat3_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt192, + const void* extseed, uint64_t repet_idx) { + CASSERT((out_bytes & 31)==0, "bug! out_bytes must be multiple of 32"); + CASSERT(domain_sep_check(salt192, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 5, GGM_TWEAK_BITS), + "bug! invalid separation"); + ctr256_vec ctr = domain_sep_ptx_lo2_m256_from192(salt192, repet_idx << VOLE_RNG_REPET_SHIFT); + rijndael256_ctrle_nocarry_nblocks_avx2(out, extseed, &ctr, out_bytes >> 5); +} +EXPORT void vole_rng_ext_cat5_rijndael256_ctrle_avx2(void* out, uint64_t out_bytes, const void* salt256, + const void* extseed, uint64_t repet_idx) { + CASSERT((out_bytes & 31)==0, "bug! out_bytes must be multiple of 32"); + CASSERT(domain_sep_check(salt256, repet_idx << VOLE_RNG_REPET_SHIFT, out_bytes >> 5, GGM_TWEAK_BITS), + "bug! invalid separation"); + ctr256_vec ctr = domain_sep_ptx_lo2_m256(salt256, repet_idx << VOLE_RNG_REPET_SHIFT); + rijndael256_ctrle_nocarry_nblocks_avx2(out, extseed, &ctr, out_bytes >> 5); +} + +EXPORT void proofow_init_cipher_cat1_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 32; + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake128(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake128(&xof); + xof_output_shake128(&xof, s->p, 64); // covers p0,p1,k0,k1 + xof_ctx_release_shake128(&xof); + s->p[0].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[1] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + aes128_key_schedule_x2_avx2(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 32; // CAT1 + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + // low-level 2-key grind: fills s->c and ctr with the first winning candidate. + if (!aes128_proofow_grind_avx2(s->c, &ctr, s->p, s->rk, s->mask_w)) return 0; + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake128(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake128(&xof); + *ctr_in_out = ctr; + return 1; +} + +EXPORT int proofow_verify_w_cipher_cat1_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 32; // CAT1 + struct proofow_state128_t* const s = (struct proofow_state128_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + aes128_ctrle_nocarry_1block_avx2(s->c[0].v64, s->rk[0], s->p[0].v64); + aes128_ctrle_nocarry_1block_avx2(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake128(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake128(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake128(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake128(&xof, s->c, 32); // covers c0, c1 + xof_finalize_and_output_shake128(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake128(&xof); + return 1; +} + +// cipher-based proof of work (cat5: rijndael256 block cipher + shake256 xof), avx2 variant. +// Mirrors the cat1 avx trio: the grind delegates its inner loop to the low-level +// rijndael256_proofow_grind_avx2 (the rijndael256 analogue of aes128_proofow_grind_avx2). + +EXPORT void proofow_init_cipher_cat5_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 64; // CAT5: 2*lambda = 512 bits + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) + xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + rijndael256_key_schedule_x2_avx2(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 64; // CAT5 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + // low-level 2-key grind: fills s->c and ctr with the first winning candidate. + if (!rijndael256_proofow_grind_avx2(s->c, &ctr, s->p, s->rk, s->mask_w)) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; +} + +EXPORT int proofow_verify_w_cipher_cat5_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 64; // CAT5 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + rijndael256_ctrle_nocarry_1block_avx2(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_avx2(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + return 1; +} + +// cipher-based proof of work (cat3: rijndael256 + shake256), avx2 variant. Identical to +// cat5_avx except h_piop is 48 bytes; reuses the same proofow_state256_t workspace and the +// same low-level rijndael256_proofow_grind_avx2. + +EXPORT void proofow_init_cipher_cat3_avx( // + proofow_ctx_t* proofow_state, // + const uint64_t lambda, const uint64_t kappa, const uint64_t tau, // vole params + const uint64_t proofow_w, // dims + const hash_t* h_piop // input +) { + static const uint64_t H_PIOP_BYTES = 48; // CAT3: 2*lambda = 384 bits + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + memcpy(s->h_piop, h_piop, H_PIOP_BYTES); + s->delta0_out_bytes = (tau * kappa + 7) >> 3; + CASSERT(proofow_w > 0 && proofow_w < 64, "invalid proofow_w"); + // each iteration runs the block cipher twice, so 2^(w-1) iterations already cost 2^w + // cipher calls: the check must cover w-1 bits, not w. + s->mask_w = (UINT64_C(1) << (proofow_w - 1)) - 1; // 2^(w-1) - 1 + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H0_PREFIX, 1); + xof_seed_shake256(&xof, h_piop, H_PIOP_BYTES); + xof_finalize_shake256(&xof); + xof_output_shake256(&xof, s->p, 128); // covers p0,p1,k0,k1 (32 bytes each) + xof_ctx_release_shake256(&xof); + s->p[0].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p0 is 1 + s->p[1].v64[3] |= UINT64_C(1) << 63; // ensures the msb of p1 is 1 + s->k[0].v64[0] &= UINT64_C(-2); // ensures the lsb of k0 is 0 + s->k[1].v64[0] |= UINT64_C(1); // ensures the lsb of k1 is 1 + rijndael256_key_schedule_x2_avx2(s->rk[0], s->rk[1], s->k[0].v64, s->k[1].v64); +} + +EXPORT int proofow_grind_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, uint64_t* ctr_in_out) { + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 48; // CAT3 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + uint64_t ctr = *ctr_in_out; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + // low-level 2-key grind: fills s->c and ctr with the first winning candidate. + if (!rijndael256_proofow_grind_avx2(s->c, &ctr, s->p, s->rk, s->mask_w)) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + *ctr_in_out = ctr; + return 1; +} + +EXPORT int proofow_verify_w_cipher_cat3_avx(proofow_ctx_t* proofow_state, bitvec_t* delta0_out, const uint64_t ctr) { + // Verification checks the single provided counter (no grind loop). + static const uint64_t MASK_ELL_HI = UINT64_C(-1) << 32; + static const uint64_t H_PIOP_BYTES = 48; // CAT3 + struct proofow_state256_t* const s = (struct proofow_state256_t*)proofow_state; + s->p[0].v64[0] = (s->p[0].v64[0] & MASK_ELL_HI) | ctr; + s->p[1].v64[0] = (s->p[1].v64[0] & MASK_ELL_HI) | ctr; + rijndael256_ctrle_nocarry_1block_avx2(s->c[0].v64, s->rk[0], s->p[0].v64); + rijndael256_ctrle_nocarry_1block_avx2(s->c[1].v64, s->rk[1], s->p[1].v64); + if (((s->c[0].v64[0] ^ s->c[1].v64[0]) & s->mask_w) != 0) return 0; + xof_ctx xof; + xof_init_and_seed_shake256(&xof, &PROOFOW_H1_PREFIX, 1); + xof_seed_shake256(&xof, s->h_piop, H_PIOP_BYTES); + xof_seed_shake256(&xof, &ctr, PROOFOW_CTR_REVEALED_BYTES); // always 4 bytes + xof_seed_shake256(&xof, s->c, 64); // covers c0, c1 (32 bytes each) + xof_finalize_and_output_shake256(&xof, delta0_out, s->delta0_out_bytes); + xof_ctx_release_shake256(&xof); + return 1; +} +// --- matrix_rng (avx2) --------------------------------------------------------- +// avx2 counterpart of the matrix_rng_* ref functions. The struct layout, the +// blocks_per_row computation and the last-block mask (set_2_b_minus_one) are all +// shared with the ref path; only the key schedule / CTR encryption and the +// last-block masking use the avx2 kernels. The avx2 key schedule is bit-identical +// to the ref one, so a context built by either init works with either get_row. + +// AND the last PRG block with the stored mask using vector intrinsics. +static inline void apply_last_blk_mask_m128(void* blk, const void* mask) { + const __m128i b = _mm_loadu_si128((const __m128i*)blk); + const __m128i m = _mm_loadu_si128((const __m128i*)mask); + _mm_storeu_si128((__m128i*)blk, _mm_and_si128(b, m)); +} +static inline void apply_last_blk_mask_m256(void* blk, const void* mask) { + const __m256i b = _mm256_loadu_si256((const __m256i*)blk); + const __m256i m = _mm256_loadu_si256((const __m256i*)mask); + _mm256_storeu_si256((__m256i*)blk, _mm256_and_si256(b, m)); +} + +EXPORT void matrix_rng_init_aes128_cat1_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*)rng; + aes128_key_schedule_x1_avx2(r->rk, seed); + r->blocks_per_row = ((row_bit_size + 127) >> 7); // aes128 uses 128-bit block sizes + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 2, row_bit_size & 127); +} + +EXPORT void matrix_rng_init_rijndael256_cat3_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*)rng; + // the actual rijndael key is padded with zeroes + uint64_t key256[4] = {}; // ZERO + memcpy(key256, seed, 24); + rijndael256_key_schedule_x1_avx2(r->rk, key256); + // cat3 use the full 256-bit outputs of rijndael256 + r->blocks_per_row = ((row_bit_size + 255) >> 8); + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); +} + +EXPORT void matrix_rng_init_rijndael256_cat5_avx(matrix_rng_t* rng, const seed_t* seed, const uint64_t row_bit_size) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*)rng; + rijndael256_key_schedule_x1_avx2(r->rk, seed); + r->blocks_per_row = ((row_bit_size + 255) >> 8); // rijndael256 uses 256-bit block sizes + r->row_bit_size = row_bit_size; + set_2_b_minus_one(r->last_blk_mask.v64, 4, row_bit_size & 255); +} + +EXPORT void matrix_rng_get_row_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*)rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); + ctr128_t* const cout = (ctr128_t*)out; + const uint64_t bpr = r->blocks_per_row; + ctr128_t ctr = {}; + ctr.v64[0] = row_index * bpr; + aes128_ctrle_nocarry_nblocks_avx2(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask_m128(cout[bpr - 1].v8, r->last_blk_mask.v8); +} + +EXPORT void matrix_rng_get_row_rijndael256_cat3_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*)rng; + // cat3 and cat5 produce identical outputs + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*)out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = row_index * bpr; + rijndael256_ctrle_nocarry_nblocks_avx2(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask_m256(cout[bpr - 1].v8, r->last_blk_mask.v8); +} + +EXPORT void matrix_rng_get_row_rijndael256_cat5_avx(const matrix_rng_t* rng, void* out, const uint64_t row_index) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*)rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*)out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = row_index * bpr; + rijndael256_ctrle_nocarry_nblocks_avx2(out, r->rk, ctr.v64, bpr); + apply_last_blk_mask_m256(cout[bpr - 1].v8, r->last_blk_mask.v8); +} + +// Batched row generation (see MATRIX_RNG_GET_ROWS). Consecutive rows are a +// contiguous stretch of the CTR keystream, so the batch is one cipher call +// followed by the per-row last-block masking. Byte-identical to a get_row loop. + +EXPORT void matrix_rng_get_rows_aes128_cat1_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_aes128_cat1_t* r = (struct matrix_rng_aes128_cat1_t*)rng; + CASSERT((((uint64_t)out) & 15) == 0, "out must be 16-byte aligned"); + ctr128_t* const cout = (ctr128_t*)out; + const uint64_t bpr = r->blocks_per_row; + ctr128_t ctr = {}; + ctr.v64[0] = first_row * bpr; + aes128_ctrle_nocarry_nblocks_avx2(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask_m128(cout[i * bpr + bpr - 1].v8, r->last_blk_mask.v8); + } +} + +EXPORT void matrix_rng_get_rows_rijndael256_cat3_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_rijndael256_cat3_t* r = (struct matrix_rng_rijndael256_cat3_t*)rng; + // cat3 and cat5 produce identical outputs + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*)out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = first_row * bpr; + rijndael256_ctrle_nocarry_nblocks_avx2(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask_m256(cout[i * bpr + bpr - 1].v8, r->last_blk_mask.v8); + } +} + +// --- fused row generation x challenge (cat1: aes128 + gf128, avx2) ---------- +// +// See MATRIX_RNG_ROWS_TIMES_CHALL. This is the one place where the matrix prng +// and the field meet: the aes rounds issue on the cipher port and the carry-less +// multiplies on the vector-shuffle port, so emitting them in a single loop lets +// the field reduction of one row run underneath the encryption of the next. Kept +// here rather than in a new file because everything it needs is already in +// scope: the prng context layout (sdith_prng_private.h) and GF128_PV +// (vole_private.h). +// +// Row generation is bit-identical to matrix_rng_get_row_aes128_cat1_avx (same +// counters, same last-block mask) and the reduction is the rearrangement +// documented on MATRIX_RNG_PREPROCESS_CHALL, so the result is identical to the +// get_rows + gf128_flambda_dot_product pair. + +// clmul operand selectors (same encoding as the ones in the gf*_avx2 sources) +#define PCLMUL_LO_X_LO 0x00 +#define PCLMUL_LO_X_HI 0x10 + +/** the bpr aes128 blocks of one row, last block masked. Kept as values so that, + * when bpr is a compile-time constant, the row never reaches memory. */ +#define AES128_ROW_GEN(out, rk, ctr, bpr, lastmask) \ + do { \ + const __m128i k0_ = _mm_loadu_si128((const __m128i*)(rk)); \ + uint64_t t_ = 0; \ + for (; t_ + 4 <= (bpr); t_ += 4) { \ + __m128i s0_ = _mm_xor_si128(_mm_set_epi64x(0, (long long)((ctr) + t_ + 0)), k0_); \ + __m128i s1_ = _mm_xor_si128(_mm_set_epi64x(0, (long long)((ctr) + t_ + 1)), k0_); \ + __m128i s2_ = _mm_xor_si128(_mm_set_epi64x(0, (long long)((ctr) + t_ + 2)), k0_); \ + __m128i s3_ = _mm_xor_si128(_mm_set_epi64x(0, (long long)((ctr) + t_ + 3)), k0_); \ + for (int o_ = 16; o_ <= 144; o_ += 16) { \ + const __m128i kk_ = _mm_loadu_si128((const __m128i*)((const uint8_t*)(rk) + o_)); \ + s0_ = _mm_aesenc_si128(s0_, kk_); \ + s1_ = _mm_aesenc_si128(s1_, kk_); \ + s2_ = _mm_aesenc_si128(s2_, kk_); \ + s3_ = _mm_aesenc_si128(s3_, kk_); \ + } \ + const __m128i kl_ = _mm_loadu_si128((const __m128i*)((const uint8_t*)(rk) + 160)); \ + (out)[t_ + 0] = _mm_aesenclast_si128(s0_, kl_); \ + (out)[t_ + 1] = _mm_aesenclast_si128(s1_, kl_); \ + (out)[t_ + 2] = _mm_aesenclast_si128(s2_, kl_); \ + (out)[t_ + 3] = _mm_aesenclast_si128(s3_, kl_); \ + } \ + for (; t_ < (bpr); t_++) { \ + __m128i s_ = _mm_xor_si128(_mm_set_epi64x(0, (long long)((ctr) + t_)), k0_); \ + for (int o_ = 16; o_ <= 144; o_ += 16) \ + s_ = _mm_aesenc_si128(s_, _mm_loadu_si128((const __m128i*)((const uint8_t*)(rk) + o_))); \ + (out)[t_] = _mm_aesenclast_si128(s_, _mm_loadu_si128((const __m128i*)((const uint8_t*)(rk) + 160))); \ + } \ + (out)[(bpr) - 1] = _mm_and_si128((out)[(bpr) - 1], (lastmask)); \ + } while (0) + +/** sum_j h_j * prep_chall[j], h_j the 64-bit words of the row. The high part of + * the accumulator is 64 bits wide, so X^128 == GF128_PV folds in one clmul. */ +#define GF128_ROW_REDUCE(dst, rowwords, pc, nw) \ + do { \ + const __m128i pv_ = _mm_set_epi64x(0, GF128_PV); \ + __m128i a0_ = _mm_setzero_si128(), a1_ = _mm_setzero_si128(); \ + for (uint64_t j_ = 0; j_ < (nw); ++j_) { \ + const __m128i h_ = _mm_loadl_epi64((const __m128i*)((const uint64_t*)(rowwords) + j_)); \ + const __m128i c_ = _mm_loadu_si128((const __m128i*)(pc) + j_); \ + a0_ = _mm_xor_si128(a0_, _mm_clmulepi64_si128(h_, c_, PCLMUL_LO_X_LO)); \ + a1_ = _mm_xor_si128(a1_, _mm_clmulepi64_si128(h_, c_, PCLMUL_LO_X_HI)); \ + } \ + __m128i u_ = _mm_xor_si128(a0_, _mm_slli_si128(a1_, 8)); \ + const __m128i hi_ = _mm_srli_si128(a1_, 8); \ + (dst) = _mm_xor_si128(u_, _mm_clmulepi64_si128(hi_, pv_, PCLMUL_LO_X_LO)); \ + } while (0) + +/** the fused loop, software-pipelined: row i is generated while row i-1 reduces. */ +#define AES128_GF128_ROWS_TIMES_CHALL(dest, rk, bpr, lastmask, pc, nw, first_row, nrows, NBLK) \ + do { \ + __m128i row_[2][NBLK]; \ + AES128_ROW_GEN(row_[0], rk, (first_row) * (bpr), bpr, lastmask); \ + for (uint64_t i_ = 1; i_ < (nrows); ++i_) { \ + AES128_ROW_GEN(row_[i_ & 1], rk, ((first_row) + i_) * (bpr), bpr, lastmask); \ + GF128_ROW_REDUCE((dest)[i_ - 1], row_[(i_ - 1) & 1], pc, nw); \ + } \ + GF128_ROW_REDUCE((dest)[(nrows) - 1], row_[((nrows) - 1) & 1], pc, nw); \ + } while (0) + +// Specialisations. nwords fixes both the reduction length and bpr = ceil(nwords/2), +// so one constant drives the whole kernel; with it fixed the two row buffers stay +// in registers instead of spilling, which is worth as much as the reduction +// rewrite itself. NWORDS 1..16 covers row_bit_size up to 1024. +#define DEFINE_ROWS_TIMES_CHALL_CAT1(NW) \ + static void rows_times_chall_cat1_nw##NW(const struct matrix_rng_aes128_cat1_t* r, __m128i* dest, \ + const void* pc, uint64_t first_row, uint64_t nrows) { \ + const __m128i lm = _mm_loadu_si128((const __m128i*)r->last_blk_mask.v8); \ + AES128_GF128_ROWS_TIMES_CHALL(dest, r->rk, ((NW) + 1) / 2, lm, pc, NW, first_row, nrows, ((NW) + 1) / 2); \ + } +DEFINE_ROWS_TIMES_CHALL_CAT1(1) +DEFINE_ROWS_TIMES_CHALL_CAT1(2) +DEFINE_ROWS_TIMES_CHALL_CAT1(3) +DEFINE_ROWS_TIMES_CHALL_CAT1(4) +DEFINE_ROWS_TIMES_CHALL_CAT1(5) +DEFINE_ROWS_TIMES_CHALL_CAT1(6) +DEFINE_ROWS_TIMES_CHALL_CAT1(7) +DEFINE_ROWS_TIMES_CHALL_CAT1(8) +DEFINE_ROWS_TIMES_CHALL_CAT1(9) +DEFINE_ROWS_TIMES_CHALL_CAT1(10) +DEFINE_ROWS_TIMES_CHALL_CAT1(11) +DEFINE_ROWS_TIMES_CHALL_CAT1(12) +DEFINE_ROWS_TIMES_CHALL_CAT1(13) +DEFINE_ROWS_TIMES_CHALL_CAT1(14) +DEFINE_ROWS_TIMES_CHALL_CAT1(15) +DEFINE_ROWS_TIMES_CHALL_CAT1(16) +#define ROWS_TIMES_CHALL_CAT1_MAX_NWORDS 16 + +typedef void ROWS_TIMES_CHALL_CAT1_FN(const struct matrix_rng_aes128_cat1_t*, __m128i*, const void*, uint64_t, + uint64_t); +static ROWS_TIMES_CHALL_CAT1_FN* const ROWS_TIMES_CHALL_CAT1[ROWS_TIMES_CHALL_CAT1_MAX_NWORDS + 1] = { + 0, + rows_times_chall_cat1_nw1, rows_times_chall_cat1_nw2, rows_times_chall_cat1_nw3, + rows_times_chall_cat1_nw4, rows_times_chall_cat1_nw5, rows_times_chall_cat1_nw6, + rows_times_chall_cat1_nw7, rows_times_chall_cat1_nw8, rows_times_chall_cat1_nw9, + rows_times_chall_cat1_nw10, rows_times_chall_cat1_nw11, rows_times_chall_cat1_nw12, + rows_times_chall_cat1_nw13, rows_times_chall_cat1_nw14, rows_times_chall_cat1_nw15, + rows_times_chall_cat1_nw16, +}; + +/** generic fallback for row sizes beyond the specialised set (rows go via memory). + * The two row buffers are bounded rather than sized at runtime: 128 blocks is a + * 16384-bit row, far above any rsd_codim, and keeps the stack use fixed at 4kB. */ +#define ROWS_TIMES_CHALL_CAT1_MAX_BLOCKS 128 +static void rows_times_chall_cat1_generic(const struct matrix_rng_aes128_cat1_t* r, __m128i* dest, const void* pc, + uint64_t nwords, uint64_t first_row, uint64_t nrows) { + const __m128i lm = _mm_loadu_si128((const __m128i*)r->last_blk_mask.v8); + const uint64_t bpr = r->blocks_per_row; + CREQUIRE(bpr <= ROWS_TIMES_CHALL_CAT1_MAX_BLOCKS, "row too wide (%ld blocks)", (long)bpr); + __m128i row[2 * ROWS_TIMES_CHALL_CAT1_MAX_BLOCKS]; + AES128_ROW_GEN(row, r->rk, first_row * bpr, bpr, lm); + for (uint64_t i = 1; i < nrows; ++i) { + AES128_ROW_GEN(row + (i & 1) * bpr, r->rk, (first_row + i) * bpr, bpr, lm); + GF128_ROW_REDUCE(dest[i - 1], row + ((i - 1) & 1) * bpr, pc, nwords); + } + GF128_ROW_REDUCE(dest[nrows - 1], row + ((nrows - 1) & 1) * bpr, pc, nwords); +} + +EXPORT void matrix_rng_rows_times_chall_aes128_cat1_avx(const matrix_rng_t* rng, void* dest, const void* prep_chall, + const uint64_t first_row, const uint64_t nrows) { + const struct matrix_rng_aes128_cat1_t* r = (const struct matrix_rng_aes128_cat1_t*)rng; + if (nrows == 0) return; + const uint64_t nwords = matrix_rng_prep_chall_nelems(r->row_bit_size); + if (nwords <= ROWS_TIMES_CHALL_CAT1_MAX_NWORDS) { + ROWS_TIMES_CHALL_CAT1[nwords](r, (__m128i*)dest, prep_chall, first_row, nrows); + } else { + rows_times_chall_cat1_generic(r, (__m128i*)dest, prep_chall, nwords, first_row, nrows); + } +} + +// --- fused row generation x challenge (cat3/cat5: rijndael256 + gf192/gf256) -- +// +// Same contract as the cat1 kernel above, but the port profile is different and +// so is the shape. Rijndael-256's ShiftRows crosses the two 128-bit halves, so +// each round needs two pshufb per block on top of the two aesenc -- and pshufb +// issues on the same port as the carry-less multiplier. The cipher therefore +// already occupies the port the reduction wants, and there is no free overlap to +// win: software-pipelining the rows measured no better than reducing each row +// straight after generating it (unlike cat1, where it is worth 20%). So these +// keep a single row buffer, which halves the live vector registers and lets the +// wider specialisations stay in registers. +// +// The gain here comes from specialisation: the row is held in registers instead +// of going out to memory and back through two calls. + +enum { RIJ256_ROUNDS = 14 }; + +/** one row as 2*bpr halves: row[2t] = low half of block t, row[2t+1] = high half. + * Rounds mirror sdith_rij_encN in lib/aes (bit-identical output); the counter + * block's high half is zero, so round 0 leaves it at the round key. */ +#define RIJ256_ROW_GEN(row, rk, ctr, bpr, lmlo, lmhi) \ + do { \ + const __m128i RMASK_ = _mm_set_epi32(0x03020d0c, 0x0f0e0908, 0x0b0a0504, 0x07060100); \ + const __m128i BMASK_ = _mm_set_epi32(0x80000000, 0x80800000, 0x80800000, 0x80808000); \ + const uint8_t* const rkb_ = (const uint8_t*)(rk); \ + const __m128i kk0_ = _mm_loadu_si128((const __m128i*)rkb_); \ + const __m128i kk1_ = _mm_loadu_si128((const __m128i*)(rkb_ + 16)); \ + for (uint64_t t_ = 0; t_ < (bpr); ++t_) { \ + (row)[2 * t_] = _mm_xor_si128(_mm_set_epi64x(0, (long long)((ctr) + t_)), kk0_); \ + (row)[2 * t_ + 1] = kk1_; \ + } \ + for (int r_ = 1; r_ < RIJ256_ROUNDS; ++r_) { \ + const __m128i rk0_ = _mm_loadu_si128((const __m128i*)(rkb_ + 32 * r_)); \ + const __m128i rk1_ = _mm_loadu_si128((const __m128i*)(rkb_ + 32 * r_ + 16)); \ + for (uint64_t t_ = 0; t_ < (bpr); ++t_) { \ + const __m128i l_ = (row)[2 * t_], h_ = (row)[2 * t_ + 1]; \ + (row)[2 * t_] = \ + _mm_aesenc_si128(_mm_shuffle_epi8(_mm_blendv_epi8(l_, h_, BMASK_), RMASK_), rk0_); \ + (row)[2 * t_ + 1] = \ + _mm_aesenc_si128(_mm_shuffle_epi8(_mm_blendv_epi8(h_, l_, BMASK_), RMASK_), rk1_); \ + } \ + } \ + { \ + const __m128i rk0_ = _mm_loadu_si128((const __m128i*)(rkb_ + 32 * RIJ256_ROUNDS)); \ + const __m128i rk1_ = _mm_loadu_si128((const __m128i*)(rkb_ + 32 * RIJ256_ROUNDS + 16)); \ + for (uint64_t t_ = 0; t_ < (bpr); ++t_) { \ + const __m128i l_ = (row)[2 * t_], h_ = (row)[2 * t_ + 1]; \ + (row)[2 * t_] = \ + _mm_aesenclast_si128(_mm_shuffle_epi8(_mm_blendv_epi8(l_, h_, BMASK_), RMASK_), rk0_); \ + (row)[2 * t_ + 1] = \ + _mm_aesenclast_si128(_mm_shuffle_epi8(_mm_blendv_epi8(h_, l_, BMASK_), RMASK_), rk1_); \ + } \ + } \ + (row)[2 * (bpr) - 2] = _mm_and_si128((row)[2 * (bpr) - 2], (lmlo)); \ + (row)[2 * (bpr) - 1] = _mm_and_si128((row)[2 * (bpr) - 1], (lmhi)); \ + } while (0) + +// Word j of the row is qword (j & 1) of register row[j >> 1]. Rather than +// extracting it (a shuffle, on the contended port), the words are consumed two at +// a time from one register and the qword is picked by the clmul selector, which +// costs nothing. ASEL is 0 for an even word, 1 for an odd one. +#define GF192_ACC(w, pcj, ASEL) \ + do { \ + const __m128i e01_ = _mm_loadu_si128((const __m128i*)(pcj)); \ + const __m128i e2_ = _mm_loadl_epi64((const __m128i*)((const uint8_t*)(pcj) + 16)); \ + a0_ = _mm_xor_si128(a0_, _mm_clmulepi64_si128((w), e01_, (ASEL) | 0x00)); \ + a1_ = _mm_xor_si128(a1_, _mm_clmulepi64_si128((w), e01_, (ASEL) | 0x10)); \ + a2_ = _mm_xor_si128(a2_, _mm_clmulepi64_si128((w), e2_, (ASEL) | 0x00)); \ + } while (0) + +/** sum_j h_j * prep_chall[j] in gf192. The accumulated value spans 256 bits, so + * its 64-bit tail folds through X^192 == GF192_PV in a single clmul. */ +#define GF192_ROW_REDUCE(dst, row, pc, nw) \ + do { \ + const __m128i pv_ = _mm_set_epi64x(0, GF192_PV); \ + const uint8_t* const pcb_ = (const uint8_t*)(pc); \ + __m128i a0_ = _mm_setzero_si128(), a1_ = _mm_setzero_si128(), a2_ = _mm_setzero_si128(); \ + uint64_t j_ = 0; \ + for (; j_ + 2 <= (nw); j_ += 2) { \ + const __m128i w_ = (row)[j_ >> 1]; \ + GF192_ACC(w_, pcb_ + 24 * j_, 0x00); \ + GF192_ACC(w_, pcb_ + 24 * (j_ + 1), 0x01); \ + } \ + if (j_ < (nw)) GF192_ACC((row)[j_ >> 1], pcb_ + 24 * j_, 0x00); \ + const __m128i u01_ = _mm_xor_si128(a0_, _mm_slli_si128(a1_, 8)); \ + const __m128i u23_ = _mm_xor_si128(a2_, _mm_srli_si128(a1_, 8)); \ + _mm_storeu_si128((__m128i*)(dst), _mm_xor_si128(u01_, _mm_clmulepi64_si128(u23_, pv_, 0x01))); \ + ((uint64_t*)(dst))[2] = (uint64_t)_mm_cvtsi128_si64(u23_); \ + } while (0) + +#define GF256_ACC(w, pcj, ASEL) \ + do { \ + const __m128i e01_ = _mm_loadu_si128((const __m128i*)(pcj)); \ + const __m128i e23_ = _mm_loadu_si128((const __m128i*)((const uint8_t*)(pcj) + 16)); \ + a0_ = _mm_xor_si128(a0_, _mm_clmulepi64_si128((w), e01_, (ASEL) | 0x00)); \ + a1_ = _mm_xor_si128(a1_, _mm_clmulepi64_si128((w), e01_, (ASEL) | 0x10)); \ + a2_ = _mm_xor_si128(a2_, _mm_clmulepi64_si128((w), e23_, (ASEL) | 0x00)); \ + a3_ = _mm_xor_si128(a3_, _mm_clmulepi64_si128((w), e23_, (ASEL) | 0x10)); \ + } while (0) + +/** sum_j h_j * prep_chall[j] in gf256; 320-bit accumulator, 64-bit tail folded + * through X^256 == GF256_PV in a single clmul. */ +#define GF256_ROW_REDUCE(dst, row, pc, nw) \ + do { \ + const __m128i pv_ = _mm_set_epi64x(0, GF256_PV); \ + const uint8_t* const pcb_ = (const uint8_t*)(pc); \ + __m128i a0_ = _mm_setzero_si128(), a1_ = _mm_setzero_si128(); \ + __m128i a2_ = _mm_setzero_si128(), a3_ = _mm_setzero_si128(); \ + uint64_t j_ = 0; \ + for (; j_ + 2 <= (nw); j_ += 2) { \ + const __m128i w_ = (row)[j_ >> 1]; \ + GF256_ACC(w_, pcb_ + 32 * j_, 0x00); \ + GF256_ACC(w_, pcb_ + 32 * (j_ + 1), 0x01); \ + } \ + if (j_ < (nw)) GF256_ACC((row)[j_ >> 1], pcb_ + 32 * j_, 0x00); \ + const __m128i u01_ = _mm_xor_si128(a0_, _mm_slli_si128(a1_, 8)); \ + const __m128i u23_ = \ + _mm_xor_si128(_mm_xor_si128(a2_, _mm_srli_si128(a1_, 8)), _mm_slli_si128(a3_, 8)); \ + const __m128i w4_ = _mm_srli_si128(a3_, 8); \ + _mm_storeu_si128((__m128i*)(dst), _mm_xor_si128(u01_, _mm_clmulepi64_si128(w4_, pv_, 0x00))); \ + _mm_storeu_si128((__m128i*)((uint8_t*)(dst) + 16), u23_); \ + } while (0) + +// Specialisations, indexed by the row word count. As for cat1 one constant drives +// the kernel: bpr = ceil(nwords/4) for a 256-bit block. NW 1..16 covers +// row_bit_size up to 1024, i.e. every rsd_codim in use. +#define DEFINE_ROWS_TIMES_CHALL_RIJ(CAT, NW, CTXT, REDUCE, LB) \ + static void rows_times_chall_##CAT##_nw##NW(const struct CTXT* r, uint8_t* dest, const void* pc, \ + uint64_t first_row, uint64_t nrows) { \ + const __m128i lmlo = _mm_loadu_si128((const __m128i*)r->last_blk_mask.v8); \ + const __m128i lmhi = _mm_loadu_si128((const __m128i*)(r->last_blk_mask.v8 + 16)); \ + enum { BPR = ((NW) + 3) / 4 }; \ + __m128i row[2 * BPR]; \ + for (uint64_t i = 0; i < nrows; ++i) { \ + RIJ256_ROW_GEN(row, r->rk, (first_row + i) * BPR, BPR, lmlo, lmhi); \ + REDUCE(dest + i * (LB), row, pc, NW); \ + } \ + } + +#define DEFINE_ROWS_TIMES_CHALL_CAT3(NW) \ + DEFINE_ROWS_TIMES_CHALL_RIJ(cat3, NW, matrix_rng_rijndael256_cat3_t, GF192_ROW_REDUCE, 24) +#define DEFINE_ROWS_TIMES_CHALL_CAT5(NW) \ + DEFINE_ROWS_TIMES_CHALL_RIJ(cat5, NW, matrix_rng_rijndael256_cat5_t, GF256_ROW_REDUCE, 32) + +#define DEFINE_ROWS_TIMES_CHALL_ALL(M) \ + M(1) M(2) M(3) M(4) M(5) M(6) M(7) M(8) M(9) M(10) M(11) M(12) M(13) M(14) M(15) M(16) +DEFINE_ROWS_TIMES_CHALL_ALL(DEFINE_ROWS_TIMES_CHALL_CAT3) +DEFINE_ROWS_TIMES_CHALL_ALL(DEFINE_ROWS_TIMES_CHALL_CAT5) +#define ROWS_TIMES_CHALL_RIJ_MAX_NWORDS 16 +#define ROWS_TIMES_CHALL_RIJ_TABLE(CAT) \ + {0, \ + rows_times_chall_##CAT##_nw1, rows_times_chall_##CAT##_nw2, rows_times_chall_##CAT##_nw3, \ + rows_times_chall_##CAT##_nw4, rows_times_chall_##CAT##_nw5, rows_times_chall_##CAT##_nw6, \ + rows_times_chall_##CAT##_nw7, rows_times_chall_##CAT##_nw8, rows_times_chall_##CAT##_nw9, \ + rows_times_chall_##CAT##_nw10, rows_times_chall_##CAT##_nw11, rows_times_chall_##CAT##_nw12, \ + rows_times_chall_##CAT##_nw13, rows_times_chall_##CAT##_nw14, rows_times_chall_##CAT##_nw15, \ + rows_times_chall_##CAT##_nw16} + +typedef void ROWS_TIMES_CHALL_CAT3_FN(const struct matrix_rng_rijndael256_cat3_t*, uint8_t*, const void*, uint64_t, + uint64_t); +typedef void ROWS_TIMES_CHALL_CAT5_FN(const struct matrix_rng_rijndael256_cat5_t*, uint8_t*, const void*, uint64_t, + uint64_t); +static ROWS_TIMES_CHALL_CAT3_FN* const ROWS_TIMES_CHALL_CAT3[ROWS_TIMES_CHALL_RIJ_MAX_NWORDS + 1] = + ROWS_TIMES_CHALL_RIJ_TABLE(cat3); +static ROWS_TIMES_CHALL_CAT5_FN* const ROWS_TIMES_CHALL_CAT5[ROWS_TIMES_CHALL_RIJ_MAX_NWORDS + 1] = + ROWS_TIMES_CHALL_RIJ_TABLE(cat5); + +// Generic fallback for rows wider than the specialised set. Correctness path +// only: with a runtime block count the row spills and this is slower than the +// get_rows + flambda_dot_product pair it replaces, but no rsd_codim in use gets +// anywhere near it. Bounded to keep the stack use fixed (2kB). +#define ROWS_TIMES_CHALL_RIJ_MAX_BLOCKS 64 +#define DEFINE_ROWS_TIMES_CHALL_RIJ_GENERIC(CAT, CTXT, REDUCE, LB) \ + static void rows_times_chall_##CAT##_generic(const struct CTXT* r, uint8_t* dest, const void* pc, \ + uint64_t nwords, uint64_t first_row, uint64_t nrows) { \ + const __m128i lmlo = _mm_loadu_si128((const __m128i*)r->last_blk_mask.v8); \ + const __m128i lmhi = _mm_loadu_si128((const __m128i*)(r->last_blk_mask.v8 + 16)); \ + const uint64_t bpr = r->blocks_per_row; \ + CREQUIRE(bpr <= ROWS_TIMES_CHALL_RIJ_MAX_BLOCKS, "row too wide (%ld blocks)", (long)bpr); \ + __m128i row[2 * ROWS_TIMES_CHALL_RIJ_MAX_BLOCKS]; \ + for (uint64_t i = 0; i < nrows; ++i) { \ + RIJ256_ROW_GEN(row, r->rk, (first_row + i) * bpr, bpr, lmlo, lmhi); \ + REDUCE(dest + i * (LB), row, pc, nwords); \ + } \ + } +DEFINE_ROWS_TIMES_CHALL_RIJ_GENERIC(cat3, matrix_rng_rijndael256_cat3_t, GF192_ROW_REDUCE, 24) +DEFINE_ROWS_TIMES_CHALL_RIJ_GENERIC(cat5, matrix_rng_rijndael256_cat5_t, GF256_ROW_REDUCE, 32) + +// Pre-processed challenge, avx path: same loop as the ref one (in +// sdith_prng_private.h), with the pclmul product instead of the bit-by-bit +// reference. It is only ceil(row_bits/64) products, but the ref product is a +// 192/256-iteration shift-and-xor loop, which is enough to show up next to the +// row reductions it feeds. +EXPORT void matrix_rng_preprocess_chall_aes128_cat1_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_aes128_cat1_t* r = (const struct matrix_rng_aes128_cat1_t*)rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), // + 16, 2, gf128_flambda_product_pclmul); +} + +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat3_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_rijndael256_cat3_t* r = (const struct matrix_rng_rijndael256_cat3_t*)rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), // + 24, 3, gf192_flambda_product_pclmul); +} + +EXPORT void matrix_rng_preprocess_chall_rijndael256_cat5_avx(const matrix_rng_t* rng, flambda_t* prep_chall, + const flambda_t* chall) { + const struct matrix_rng_rijndael256_cat5_t* r = (const struct matrix_rng_rijndael256_cat5_t*)rng; + preprocess_chall_generic(prep_chall, chall, matrix_rng_prep_chall_nelems(r->row_bit_size), // + 32, 4, gf256_flambda_product_pclmul); +} + +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat3_avx(const matrix_rng_t* rng, void* dest, + const void* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_rijndael256_cat3_t* r = (const struct matrix_rng_rijndael256_cat3_t*)rng; + if (nrows == 0) return; + const uint64_t nwords = matrix_rng_prep_chall_nelems(r->row_bit_size); + if (nwords <= ROWS_TIMES_CHALL_RIJ_MAX_NWORDS) { + ROWS_TIMES_CHALL_CAT3[nwords](r, (uint8_t*)dest, prep_chall, first_row, nrows); + } else { + rows_times_chall_cat3_generic(r, (uint8_t*)dest, prep_chall, nwords, first_row, nrows); + } +} + +EXPORT void matrix_rng_rows_times_chall_rijndael256_cat5_avx(const matrix_rng_t* rng, void* dest, + const void* prep_chall, const uint64_t first_row, + const uint64_t nrows) { + const struct matrix_rng_rijndael256_cat5_t* r = (const struct matrix_rng_rijndael256_cat5_t*)rng; + if (nrows == 0) return; + const uint64_t nwords = matrix_rng_prep_chall_nelems(r->row_bit_size); + if (nwords <= ROWS_TIMES_CHALL_RIJ_MAX_NWORDS) { + ROWS_TIMES_CHALL_CAT5[nwords](r, (uint8_t*)dest, prep_chall, first_row, nrows); + } else { + rows_times_chall_cat5_generic(r, (uint8_t*)dest, prep_chall, nwords, first_row, nrows); + } +} + +EXPORT void matrix_rng_get_rows_rijndael256_cat5_avx(const matrix_rng_t* rng, void* out, const uint64_t first_row, + const uint64_t nrows) { + struct matrix_rng_rijndael256_cat5_t* r = (struct matrix_rng_rijndael256_cat5_t*)rng; + CASSERT((((uint64_t)out) & 31) == 0, "out must be 32-byte aligned"); + ctr256_t* const cout = (ctr256_t*)out; + const uint64_t bpr = r->blocks_per_row; + ctr256_t ctr = {}; + ctr.v64[0] = first_row * bpr; + rijndael256_ctrle_nocarry_nblocks_avx2(out, r->rk, ctr.v64, nrows * bpr); + for (uint64_t i = 0; i < nrows; ++i) { + apply_last_blk_mask_m256(cout[i * bpr + bpr - 1].v8, r->last_blk_mask.v8); + } +} + +// --- keygen prng (avx2) ----------------------------------------------------- +// avx2 counterpart of the keygen_rng_* ref functions. The context layout and the +// draw loop are shared with the ref path (DEFINE_KEYGEN_RNG_NEXT_U32); only the +// key schedule and the CTR encryption use the avx2 kernels, which are +// bit-identical to the ref ones, so a context built by either init works with +// either draw function. + +EXPORT void keygen_rng_init_aes128_cat1_avx(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_aes128_cat1_t* s = (struct keygen_rng_aes128_cat1_t*)rng; + aes128_key_schedule_x1_avx2(s->rk, sk_seed); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_init_rijndael256_cat3_avx(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_rijndael256_t* s = (struct keygen_rng_rijndael256_t*)rng; + // the 192-bit seed is padded with 64 zero bits in the MSB to make a rijndael256 key + uint64_t key256[4] = {}; // ZERO + memcpy(key256, sk_seed, 24); + rijndael256_key_schedule_x1_avx2(s->rk, key256); + KEYGEN_RNG_INIT_EMPTY(s); +} + +EXPORT void keygen_rng_init_rijndael256_cat5_avx(keygen_rng_ctx* rng, const seed_t* sk_seed) { + struct keygen_rng_rijndael256_t* s = (struct keygen_rng_rijndael256_t*)rng; + rijndael256_key_schedule_x1_avx2(s->rk, sk_seed); + KEYGEN_RNG_INIT_EMPTY(s); +} + +DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_aes128_cat1_avx, keygen_rng_aes128_cat1_t, ctr128_t, + aes128_ctrle_nocarry_nblocks_avx2) +DEFINE_KEYGEN_RNG_NEXT_U32(keygen_rng_next_u32_rijndael256_avx, keygen_rng_rijndael256_t, ctr256_t, + rijndael256_ctrle_nocarry_nblocks_avx2) diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng_private.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng_private.h new file mode 100644 index 0000000000..22d5bb8d61 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_prng_private.h @@ -0,0 +1,293 @@ +#ifndef RNG_PRIVATE_H +#define RNG_PRIVATE_H + +#include + +#include "aes128_ctrle.h" // ctr128_t (also pulls in rijndael256_ctrle.h -> ctr256_t) +#include "rijndael256_ctrle.h" +#include "sdith_prng.h" +#include "vole_private.h" + +// union that represents an aes128 little endian counter +typedef union { + __uint128_t u128; + uint64_t v64[2]; +} aesblk; + +/** + * @brief Domain-separated CTR plaintext, low 64 bits (round 3). + * will compute: MapToBitsLE(tweak, theta) || salt[theta:salt_bitsize] + */ +static inline void domain_sep_ptx_lo2( // + uint64_t* const outctr, // aesctr 32-bytes aligned + const void* const masked_salt, const uint64_t salt_bytes, // salt [no specific alignment] + const uint64_t tweak) +{ + memcpy(outctr, masked_salt, salt_bytes); + outctr[0] |= tweak; +} + +#ifdef __x86_64__ +#include + +/** + * @brief avx2 form of domain_sep_ptx_lo2, for a 128-bit CTR block. + * + * Same plaintext, built in a vector register: the caller stores it once with a + * single aligned 16-byte store, which is exactly the width the CTR kernel loads + * it back at. Going through memory in two 8-byte pieces instead (what the + * memcpy + scalar-or pair compiles to) makes the kernel's 16-byte load overlap + * two narrower stores, which costs a store-forwarding stall on every call -- + * about as much as encrypting five extra blocks. + */ +static inline __m128i domain_sep_ptx_lo2_m128( // + const void* const masked_salt, // salt [no specific alignment] + const uint64_t tweak) +{ + return _mm_or_si128(_mm_loadu_si128((const __m128i*)masked_salt), + _mm_cvtsi64_si128((long long)tweak)); +} + +/** + * @brief 256-bit CTR block held as the two halves the rijndael256 kernels read. + * Those kernels take the block as two 16-byte loads, so keeping it in two + * registers lets the caller answer them with two matching 16-byte stores. + */ +typedef struct { + __m128i lo; + __m128i hi; +} ctr256_vec; + +/** @brief 192-bit salt in a 256-bit block: the 8 bytes above the salt stay zero. */ +static inline ctr256_vec domain_sep_ptx_lo2_m256_from192( // + const void* const masked_salt, // 24-byte salt [no specific alignment] + const uint64_t tweak) +{ + const uint8_t* const s = (const uint8_t*)masked_salt; + uint64_t hi64; + memcpy(&hi64, s + 16, 8); + ctr256_vec res = {domain_sep_ptx_lo2_m128(s, tweak), _mm_cvtsi64_si128((long long)hi64)}; + return res; +} + +/** @brief 256-bit salt filling the whole 256-bit block. */ +static inline ctr256_vec domain_sep_ptx_lo2_m256( // + const void* const masked_salt, // 32-byte salt [no specific alignment] + const uint64_t tweak) +{ + const uint8_t* const s = (const uint8_t*)masked_salt; + ctr256_vec res = {domain_sep_ptx_lo2_m128(s, tweak), _mm_loadu_si128((const __m128i*)(s + 16))}; + return res; +} +#endif // __x86_64__ + +/** + * @brief Parameters sanity check: + * ensures that the tweak remains bounded by 2^theta and that the salt has its first + * theta bits to zero. + * These checks are meant to run in DEBUG mode only to catch bugs in the source code or + * in the parametrization of the signature, + * These checks do not need to run in production (calling in CASSERT is ok). + */ +static inline int domain_sep_check( // + const void* salt, + uint64_t tweak, + uint64_t nblocks, + uint64_t theta) +{ + uint64_t THETA_MASK = (UINT64_C(1) << theta) - 1; + uint64_t in_salt; + memcpy(&in_salt, salt, 8); + // check that the input salt and the mask are disjoint + if ((in_salt & THETA_MASK) != 0) return 0; + // check that the tweak won't overflow + if ((tweak & ~THETA_MASK) != 0) return 0; + if (((tweak + nblocks - 1) & ~THETA_MASK) != 0) return 0; + return 1; +} + +// I8: define a naive x4 LR expansion (four single PERNODE calls on parents +// node_idx0, +2, +4, +6). Used where there is no batched kernel (the ref build, +// and cat3/cat5 avx2). Byte-identical to the batched cat1 kernel, so the tree +// loop can always call the x4 pointer with no branch. LR_STRIDE = 2 * seed bytes +// (the 2-seed output per node), EXT_STRIDE = one extended key. +#define GGM_EXTSEED_RNG_LR_X4_NAIVE(NAME, PERNODE, LR_STRIDE, EXT_STRIDE) \ + EXPORT void NAME(void* lr_out, const void* salt, const void* extended_seeds, uint64_t node_idx0, \ + uint32_t theta) { \ + uint8_t* o = (uint8_t*)lr_out; \ + const uint8_t* e = (const uint8_t*)extended_seeds; \ + for (int i = 0; i < 4; i++) { \ + PERNODE(o + (uint64_t)i * (LR_STRIDE), salt, e + (uint64_t)i * (EXT_STRIDE), \ + node_idx0 + 2 * i, theta); \ + } \ + } + + +union proofow_ctr128_t { + uint8_t v8[16]; + uint64_t v64[2]; +} __attribute__((aligned(16))); + +struct proofow_state128_t { + union proofow_ctr128_t p[2]; // aes128 plaintext + union proofow_ctr128_t k[2]; // aes128 key + union proofow_ctr128_t c[2]; // aes128 ciphertext + union proofow_ctr128_t rk[2][11]; // 11 round keys of aes128 + uint8_t h_piop[32]; + uint64_t delta0_out_bytes; + uint64_t mask_w; +} __attribute__((aligned(32))); + +union proofow_ctr256_t { + uint8_t v8[32]; + uint64_t v64[4]; +} __attribute__((aligned(32))); + +struct proofow_state256_t { + union proofow_ctr256_t p[2]; // rijndael256 plaintext + union proofow_ctr256_t k[2]; // rijndael256 key + union proofow_ctr256_t c[2]; // rijndael256 ciphertext + union proofow_ctr256_t rk[2][15]; // 15 round keys of rijndael256 (RIJNDAEL256_RK_BYTES each) + uint8_t h_piop[64]; + uint64_t delta0_out_bytes; + uint64_t mask_w; +} __attribute__((aligned(32))); + +struct proofow_shake_cat1_t { + uint8_t delta0_and_vgrind[32]; // at least 16 + w + uint8_t h_piop[32]; + uint64_t delta0_and_vgrind_bytes; + uint64_t delta0_out_bytes; + uint64_t w; + uint64_t kappa_tau; +} __attribute__((aligned(32))); + +struct proofow_shake_cat3_t { + uint8_t delta0_and_vgrind[32]; // at least 24 + w + uint8_t h_piop[48]; + uint64_t delta0_and_vgrind_bytes; + uint64_t delta0_out_bytes; + uint64_t w; + uint64_t kappa_tau; +} __attribute__((aligned(32))); + +struct proofow_shake_cat5_t { + uint8_t delta0_and_vgrind[64]; // at least 32 + w + uint8_t h_piop[64]; + uint64_t delta0_and_vgrind_bytes; + uint64_t delta0_out_bytes; + uint64_t w; + uint64_t kappa_tau; +} __attribute__((aligned(32))); + +struct matrix_rng_aes128_cat1_t { + ctr128_t rk[11]; // round keys (11 blocks for aes128) + ctr128_t last_blk_mask; // AND mask to apply to the last PRG block + uint64_t blocks_per_row; // number of PRG blocks to generate per row + uint64_t row_bit_size; // bits per row (bits beyond it are masked off) +} __attribute__((aligned(32))); // + +struct matrix_rng_rijndael256_cat3_t { + ctr256_t rk[15]; // round keys (15 blocks for rijndael256) + ctr256_t last_blk_mask; // AND mask to apply to the last (256-bit) PRG block + uint64_t blocks_per_row; // number of PRG blocks to generate per row + uint64_t row_bit_size; // bits per row (bits beyond it are masked off) +} __attribute__((aligned(32))); // + +struct matrix_rng_rijndael256_cat5_t { + ctr256_t rk[15]; // round keys (15 blocks for rijndael256) + ctr256_t last_blk_mask; // AND mask to apply to the last PRG block + uint64_t blocks_per_row; // number of PRG blocks to generate per row + uint64_t row_bit_size; // bits per row (bits beyond it are masked off) +} __attribute__((aligned(32))); // + +// Fills res[0..res_size) with a little-endian bitmask keeping the low b bits. +// Special case: b == 0 means the last PRG block is entirely used (the row bit +// size is a multiple of the block bit size), so every bit is kept (all ones). +// Shared by the ref and avx matrix_rng init (mask setup is scalar either way). +static inline void set_2_b_minus_one(uint64_t* res, uint64_t res_size, uint64_t b) { + if (b == 0) { + for (uint64_t i=0; i= 64) { + res[i] = UINT64_C(-1); + b -= 64; + } else { + res[i] = (UINT64_C(1) << b) - 1; + b = 0; + } + } +} + +// Body of MATRIX_RNG_PREPROCESS_CHALL, parameterised by the field. With +// k = lambda/64, it builds prep_chall[j] = chall[j / k] * X^(64 * (j % k)). +// Shared by the ref and avx matrix_rng so the two tables can never disagree; +// only the product differs (ref bit loop vs pclmul). +static inline void preprocess_chall_generic(flambda_t* prep_chall, const flambda_t* chall, const uint64_t nelems, + const uint64_t lambda_bytes, const uint64_t k, + FLAMBDA_PRODUCT_F* product) { + uint8_t* const out = (uint8_t*) prep_chall; + const uint8_t* const in = (const uint8_t*) chall; + for (uint64_t j = 0; j < nelems; ++j) { + // X^(64*m) as a field element: the single bit at position 64*m + flambda_max_t xpow = {0, 0, 0, 0}; + xpow[j % k] = 1; + product(out + j * lambda_bytes, in + (j / k) * lambda_bytes, xpow); + } +} + +// --- keygen prng (see keygen_rng_ctx in sdith_prng.h) ----------------------- +// +// A pure CTR keystream read as little-endian uint32s. The blocks are produced a +// few at a time rather than one by one: the keystream is contiguous, so a batch +// is a single cipher call and the output is unchanged, but the per-call counter +// setup and (on avx2) the pipeline fill are amortised over the whole batch. The +// leftover of the last batch is simply never read. +#define KEYGEN_RNG_BUF_BLOCKS 4 + +struct keygen_rng_aes128_cat1_t { + ctr128_t buf[KEYGEN_RNG_BUF_BLOCKS]; // keystream buffer + ctr128_t rk[11]; // round keys (11 blocks for aes128) + uint64_t next_block; // counter of the next block to produce + uint64_t off; // read offset in buf (== buf size when empty) +} __attribute__((aligned(32))); + +// cat3 and cat5 share this layout and every function but the init: the only +// difference between them is the key the schedule is run on. +struct keygen_rng_rijndael256_t { + ctr256_t buf[KEYGEN_RNG_BUF_BLOCKS]; // keystream buffer + ctr256_t rk[15]; // round keys (15 blocks for rijndael256) + uint64_t next_block; // counter of the next block to produce + uint64_t off; // read offset in buf (== buf size when empty) +} __attribute__((aligned(32))); + +// Marks the buffer as empty, so that the first draw refills it from block 0. +#define KEYGEN_RNG_INIT_EMPTY(S) \ + do { \ + (S)->next_block = 0; \ + (S)->off = sizeof((S)->buf); \ + } while (0) + +// Body of the draw function, parameterised by the cipher (ref or avx2 kernel): +// refill the buffer when it runs dry, then hand out the next little-endian +// uint32. Shared by the ref and avx paths so the two can only ever differ in +// the cipher call itself. +#define DEFINE_KEYGEN_RNG_NEXT_U32(NAME, STATE_T, CTR_T, CTRLE_NBLOCKS) \ + EXPORT uint32_t NAME(keygen_rng_ctx* rng) { \ + struct STATE_T* const s = (struct STATE_T*)rng; \ + if (s->off == sizeof(s->buf)) { \ + CTR_T ctr = {}; \ + ctr.v64[0] = s->next_block; \ + CTRLE_NBLOCKS(s->buf, s->rk, ctr.v64, KEYGEN_RNG_BUF_BLOCKS); \ + s->next_block += KEYGEN_RNG_BUF_BLOCKS; \ + s->off = 0; \ + } \ + uint32_t out; \ + memcpy(&out, (const uint8_t*)s->buf + s->off, 4); \ + s->off += 4; \ + return out; \ + } + +#endif // RNG_PRIVATE_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_rsd.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_rsd.h new file mode 100644 index 0000000000..f2c2374e1a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_rsd.h @@ -0,0 +1,67 @@ +#ifndef SDITHER_RSD_H +#define SDITHER_RSD_H + +#include "vole_parameters.h" + +/// keygen stuff + +EXPORT uint64_t rsd_generate_random_instance_tmp_bytes( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim); + +/** generate a random rsd instance out of the master key entropy. + * Only the parts of the key that have to be stored are produced: the solution + * (from the sk_seed) and the syndrome y = H.e (from the pk_seed). H itself is + * the public key -- it is recoverable from pk_seed with + * rsd_expand_public_key_ref -- so it is never materialised here: y touches at + * most rsd_w of its rows, and those are drawn one at a time into the scratch. + * Output is identical to expanding H and xoring the selected rows out of it. + * Constant-time in the solution. tmp_space still holds one expanded H row on + * return: the caller must scrub it. */ +EXPORT void rsd_generate_random_instance_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // prng + matrix-prng family + bitvec_t* y, uint64_t y_bytes, // out: syndrome (ceil(rsd_codim/8) bytes are set) + uint32_t* solution, // out: rsd_w integers in [0,n/w-1] + const seed_t* sk_seed, // in: secret key seed (lambda bits) + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + uint8_t* tmp_space // scratch space +); + +/** expand the public key from the pubkey seed (rows via vole_params->matrix_prg). + * Each row occupies rsd_codim_limbs*lambda_bytes bytes; h_slice_bytes must be at + * least that and keep every row aligned to the cipher block (16/8/32 bytes). */ +EXPORT void rsd_expand_public_key_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // matrix-prng family + bitmat_t* h, uint64_t h_slice_bytes, // out: (rsd_n - rsd_codim) x rsd_n matrix + const seed_t* h_seed // in: pubkey seed (lambda bits) +); + +/** unary encoding of the solution (for mux circuits). + * Constant-time in the solution coefficients (mux_arities must be < 32). */ +EXPORT void rsd_encode_solution_ref( // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + const vole_parameters* vole_params, // ct helpers + uint64_t mux_depth, const uint64_t* mux_arities, // mux depth and arities + bitvec_t* encoded_solution, uint64_t encoded_solution_bytes, // encoded solution + const uint32_t* solution // in: solution coefficients +); + +EXPORT uint64_t rsd_public_key_times_challenge_tmp_bytes( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim); + +/** multiply the public key with challenge points */ +EXPORT void rsd_public_key_times_challenge_ref( // + const vole_parameters* vole_params, // + uint64_t rsd_w, uint64_t rsd_n, uint64_t rsd_codim, // rsd dimensions + flambda_t* chall_a_H, // out: n elements + flambda_t* chall_a_y, // out: 1 element + const flambda_t* chall_a, // in: rsd_codim_limbs elements + const seed_t* pk_seed, // in: pubkey seed (lambda bits) + const bitvec_t* y, // in: pubkey y (rsd_codim bits padded with zeros) + uint8_t* tmp_space // scratch space +); + +#endif // SDITHER_RSD_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature.c b/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature.c new file mode 100644 index 0000000000..a7f390003b --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature.c @@ -0,0 +1,806 @@ +#include + +#include "ggm.h" +#include "math.h" +#include "vole_private.h" + +const uint8_t HASH_BAVC_PREFIX = 1; +const uint8_t HASH_AUX_PREFIX = 2; +const uint8_t HASH_LINES_PREFIX = 3; +const uint8_t HASH_PIOP_PREFIX = 4; +const uint8_t PROOFOW_H0_PREFIX = 5; +const uint8_t PROOFOW_H1_PREFIX = 6; +const uint64_t PROOFOW_CTR_REVEALED_BYTES = 4; // we reveal this num of bytes of proofow ctr in the signature + +uint64_t compute_rsd_codim(uint64_t rsd_n, uint64_t rsd_w) { + // target density is 1/100 + static const double LOG2_INV_TARGET_DENSITY = 6.64385618977; // log2(100.); + const uint64_t rsd_nsw = rsd_n / rsd_w; // exact division + // smallest codim where density drops below TARGET_DENSITY + const uint64_t rsd_min_codim = ceil(rsd_w * log2(rsd_nsw) + LOG2_INV_TARGET_DENSITY); + // smallest multiple of 8 above that bound + return ((rsd_min_codim + 7) & UINT64_C(-8)); +} + + +EXPORT void compute_rsd_codim_slice( + uint64_t* rsd_codim_limbs, // [out] number of limbs + uint64_t* rsd_codim_slice, // [out] number of slice bytes to hold the prng blocks + const uint64_t lambda, const uint64_t rsd_codim) { + uint64_t prng_blk_bytes = lambda == 128 ? 16 : 32; // cat3 and cat5 use a 256-bit prng + *rsd_codim_limbs = (rsd_codim + lambda - 1) / lambda; + uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + uint64_t rsd_codim_prng_blks = (rsd_codim_bytes + prng_blk_bytes - 1) / prng_blk_bytes; + *rsd_codim_slice = rsd_codim_prng_blks * prng_blk_bytes; + CREQUIRE(*rsd_codim_slice >= *rsd_codim_limbs * (lambda >> 3), + "bug! invalid parameters rsd_codim_slice will not be able to hold all the limbs"); +} + +void compute_extended_parameters(extended_parameters_t* res, const signature_parameters* sig_params) { + // compute extended parameters + res->lambda = sig_params->lambda; + res->kappa = sig_params->kappa; + res->tau = sig_params->tau; + res->target_topen = sig_params->target_topen; + res->rsd_n = sig_params->rsd_n; + res->rsd_w = sig_params->rsd_w; + res->mux_depth = sig_params->mux_depth; + memcpy(res->mux_arities, sig_params->mux_arities, sizeof(uint64_t) * 8); + res->rsd_npw = sig_params->rsd_n / sig_params->rsd_w; // exact division + res->rsd_codim = compute_rsd_codim(res->rsd_n, res->rsd_w); + res->proofow_w = sig_params->proofow_w; + res->delta0_bits = res->kappa * res->tau + sig_params->proofow_w; + res->delta0_dwords = (res->delta0_bits + 63) >> 6; + res->delta0_bytess = (res->delta0_bits + 7) >> 3; + res->delta0_capacity = res->delta0_dwords << 3; + memset(&res->vole_params, 0, sizeof(vole_parameters)); + vole_parameters_init_with_variant(&res->vole_params, res->lambda, res->tau, res->kappa, sig_params->proofow_variant); + uint64_t mux_inputs = 0; + uint64_t chall_unitary_powers = 0; + { + for (uint64_t i = 0; i < res->mux_depth; ++i) { + mux_inputs += res->mux_arities[i] - 1; + if (res->mux_arities[i] > 2) chall_unitary_powers += 32; + } + } + CREQUIRE(chall_unitary_powers <= res->lambda, "Params error: too many non-binary arities"); + res->mux_inputs = mux_inputs; + res->chall_unitary_powers = chall_unitary_powers; + res->degree = res->mux_depth > 2 ? res->mux_depth : 2; + res->num_inputs_pairs = mux_inputs * res->rsd_w; + res->num_cchk_pairs = vole_consistency_check_matrix_nrows(&res->vole_params); + CREQUIRE((res->num_cchk_pairs & 7) == 0, "non mult of 8 cchk is not supported"); + res->num_cz_pairs = res->lambda * (res->degree - 1); + res->real_L = res->num_inputs_pairs + res->num_cchk_pairs + res->num_cz_pairs; + res->L = (res->real_L + 7) & UINT64_C(-8); // L must be an exact mult of 8 + res->Lbyte = res->L >> 3; + res->Lslice = (res->Lbyte + 31 ) & UINT64_C(-32); // Lslice must be an exact mult of 32 + res->lambda_bytes = res->lambda >> 3; + res->cchk_matrix_nrows = vole_consistency_check_matrix_nrows(&res->vole_params); + res->cchk_matrix_ncols = vole_consistency_check_matrix_ncols(&res->vole_params, res->L); + res->rsd_codim_bytes = (res->rsd_codim + 7) >> 3; + compute_rsd_codim_slice(&res->rsd_codim_limbs, &res->rsd_codim_slice, res->lambda, res->rsd_codim); +} + +EXPORT uint64_t sdith_signature_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + uint64_t sig_bytes = 0; + sig_bytes += par.lambda_bytes; // global_salt + sig_bytes += par.target_topen * par.lambda_bytes; // sibling path; + sig_bytes += par.tau * 2 * par.lambda_bytes; // ggm_hidden_leaf_cmt + sig_bytes += par.Lbyte * (par.tau - 1); // corr_u + sig_bytes += par.num_cchk_pairs >> 3; // cchk_u + sig_bytes += (par.num_inputs_pairs + 7) >> 3; // circuit_in_pub + sig_bytes += (par.degree - 1) * par.lambda_bytes; // circuit_cz_pub (alpha_1 omitted) + sig_bytes += 2 * par.lambda_bytes; // hash_piop + sig_bytes += 4; // proofow_ctr_reveal + return sig_bytes; +} + +EXPORT uint64_t sdith_signature_tmp_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(hash_t*, hash_com, 32, 2 * par.lambda_bytes); // commitment of the ggm tree + COMP_SPACE_MAP_ALIGNED(hash_t*, hash_aux, 32, + 2 * par.lambda_bytes); // (round1) ggm_cmt_hash + corr_terms :=> cchk matrix + // (round3) hash_aux + cchk_u + cchk_v + inputs_mask :=> chall + COMP_SPACE_MAP_ALIGNED(hash_t*, hash_lines, 32, 2 * par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(seed_t*, root_seed, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, u, 32, par.Lslice* par.tau); + COMP_SPACE_MAP_ALIGNED(uint8_t*, v, 32, par.Lslice* par.lambda); + COMP_SPACE_MAP_ALIGNED(uint8_t*, v2, 32, par.Lslice* par.lambda); // copy needed during transposition + COMP_SPACE_MAP_ALIGNED(uint8_t*, rvp_f_cz, 32, par.lambda_bytes* par.degree * 2); + COMP_SPACE_MAP_ALIGNED(uint8_t*, res_f, 32, par.lambda_bytes*(par.degree + 1)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_f, 32, par.lambda_bytes*(par.degree + 1)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + COMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_f, 32, par.lambda_bytes * 2 * par.num_inputs_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_unitary, 32, par.lambda_bytes* par.rsd_w); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_H, 32, par.lambda_bytes* par.rsd_n); + COMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_y, 32, par.lambda_bytes); + COMP_SPACE_MAP(uint8_t*, cchk_matrix, par.cchk_matrix_nrows* par.cchk_matrix_ncols >> 3); + COMP_SPACE_MAP_ALIGNED(uint8_t*, cchk_res_v, 32, par.lambda_bytes* par.cchk_matrix_nrows); + COMP_SPACE_MAP(uint8_t*, delta0, par.delta0_capacity); + COMP_SPACE_MAP_ALIGNED(uint8_t*, delta1, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + COMP_SPACE_MAP_CALL( + prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes(&par.vole_params, par.L)); + COMP_SPACE_MAP_CALL( + prover_cst_mux_circuit_ct_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + COMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + COMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + COMP_SPACE_MAP_CALL( + full_ggm_tree_open_sibling_path_from_root_tmp_bytes(&par.vole_params, par.target_topen) + ); + COMP_SPACE_RETURN(); +} + +EXPORT uint64_t sdith_signature_entropy_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + return 2 * lambda_bytes; +} + +EXPORT uint64_t sdith_secret_key_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + const uint64_t mux_depth = sig_params->mux_depth; + const uint64_t* mux_arities = sig_params->mux_arities; + const uint64_t rsd_w = sig_params->rsd_w; + const uint64_t rsd_codim = compute_rsd_codim(sig_params->rsd_n, sig_params->rsd_w); + const uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + uint64_t mux_inputs = 0; + for (uint64_t i = 0; i < mux_depth; ++i) { + mux_inputs += mux_arities[i] - 1; + } + const uint64_t skey_encoded_solution_bytes = (rsd_w * mux_inputs + 7) >> 3; + return lambda_bytes + skey_encoded_solution_bytes + rsd_codim_bytes; +} + +EXPORT uint64_t sdith_public_key_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + const uint64_t rsd_codim = compute_rsd_codim(sig_params->rsd_n, sig_params->rsd_w); + ; + const uint64_t rsd_codim_bytes = (rsd_codim + 7) >> 3; + return lambda_bytes + rsd_codim_bytes; +} +EXPORT uint64_t sdith_keygen_tmp_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint32_t*, skey_solution, 4, par.rsd_w * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, pkey_full_y, 32, par.rsd_codim_limbs* par.lambda_bytes); + COMP_SPACE_MAP_CALL(rsd_generate_random_instance_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + COMP_SPACE_RETURN(); +} + +EXPORT uint64_t sdith_keygen_entropy_bytes(const signature_parameters* sig_params) { + const uint64_t lambda = sig_params->lambda; + const uint64_t lambda_bytes = lambda >> 3; + return 2 * lambda_bytes; +} + +#define MAP_FIELD(POOL_NAME, FIELD_NAME, VAR_BYTES) \ + FIELD_NAME = (__typeof__(FIELD_NAME))POOL_NAME; \ + POOL_NAME += (VAR_BYTES) + +/** secret key mapping */ +typedef struct skey_mapping_t { + uint8_t* pkey_seed; + uint8_t* skey_encoded_solution; + uint8_t* pkey_y; +} skey_mapping_t; + +skey_mapping_t map_secret_key(const extended_parameters_t* par, const void* skey) { + const uint64_t skey_encoded_solution_bytes = (par->rsd_w * par->mux_inputs + 7) >> 3; + skey_mapping_t res; + uint8_t* secret_key = (uint8_t*)skey; + MAP_FIELD(secret_key, res.pkey_seed, par->lambda_bytes); + MAP_FIELD(secret_key, res.pkey_y, par->rsd_codim_bytes); + MAP_FIELD(secret_key, res.skey_encoded_solution, skey_encoded_solution_bytes); // unary encoded + return res; +} + +/** public key mapping */ +typedef struct pkey_mapping_t { + uint8_t* pkey_seed; + uint8_t* pkey_y; +} pkey_mapping_t; + +pkey_mapping_t map_public_key(const extended_parameters_t* par, const void* pkey) { + pkey_mapping_t res; + uint8_t* public_key = (uint8_t*)pkey; + MAP_FIELD(public_key, res.pkey_seed, par->lambda_bytes); + MAP_FIELD(public_key, res.pkey_y, par->rsd_codim_bytes); + return res; +} + +/** signature mapping */ +typedef struct signature_mapping_t { + uint8_t* global_salt; + uint8_t* ggm_sibling_path; + uint8_t* ggm_hidden_leaf_cmt; + uint8_t* corr_u; + uint8_t* cchk_u; + uint8_t* circuit_in_pub; + uint8_t* circuit_cz_pub; + uint8_t* hash_piop; + uint8_t* proofow_ctr_reveal; +} signature_mapping_t; + +signature_mapping_t map_signature(const extended_parameters_t* par, const void* sign) { + signature_mapping_t res; + uint8_t* sign_fields = (uint8_t*)sign; + MAP_FIELD(sign_fields, res.global_salt, par->lambda_bytes); + MAP_FIELD(sign_fields, res.ggm_sibling_path, par->target_topen * par->lambda_bytes); + MAP_FIELD(sign_fields, res.ggm_hidden_leaf_cmt, par->tau * 2 * par->lambda_bytes); + MAP_FIELD(sign_fields, res.corr_u, par->Lbyte * (par->tau - 1)); + MAP_FIELD(sign_fields, res.cchk_u, par->num_cchk_pairs >> 3); + MAP_FIELD(sign_fields, res.circuit_in_pub, (par->num_inputs_pairs + 7) >> 3); + MAP_FIELD(sign_fields, res.circuit_cz_pub, (par->degree - 1) * par->lambda_bytes); + MAP_FIELD(sign_fields, res.hash_piop, 2 * par->lambda_bytes); + MAP_FIELD(sign_fields, res.proofow_ctr_reveal, PROOFOW_CTR_REVEALED_BYTES); + return res; +} + +EXPORT void sdith_keygen(const signature_parameters* sig_params, // + void* skey, // out: secret key + void* pkey, // out: public key + const void* entropy, // in: entropy + uint8_t* tmp_space) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + const uint64_t skey_encoded_solution_bytes = (par.rsd_w * par.mux_inputs + 7) >> 3; + + // local variables + TMP_SPACE_MAP_ALIGNED(uint32_t*, skey_solution, 4, par.rsd_w * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, pkey_full_y, 32, par.rsd_codim_limbs* par.lambda_bytes); + + // secret key + skey_mapping_t sk = map_secret_key(&par, skey); + + // public key + pkey_mapping_t pk = map_public_key(&par, pkey); + + // copy the entropy + memcpy(pk.pkey_seed, entropy, par.lambda_bytes); + const uint8_t* skey_seed = (const uint8_t*)entropy + par.lambda_bytes; + memcpy(sk.pkey_seed, pk.pkey_seed, par.lambda_bytes); + + // H is not materialised: it is the public key, recoverable from pkey_seed. + rsd_generate_random_instance_ref(par.rsd_w, par.rsd_n, par.rsd_codim, // + &par.vole_params, // + pkey_full_y, par.rsd_codim_limbs * par.lambda_bytes, // + skey_solution, // + skey_seed, pk.pkey_seed, // + tmp_space); // + rsd_encode_solution_ref( // + par.rsd_w, par.rsd_n, par.rsd_codim, // + &par.vole_params, // + par.mux_depth, par.mux_arities, // + sk.skey_encoded_solution, skey_encoded_solution_bytes, // + skey_solution); + + memcpy(pk.pkey_y, pkey_full_y, par.rsd_codim_bytes); + memcpy(sk.pkey_y, pkey_full_y, par.rsd_codim_bytes); + // NOTE: on return, tmp_space still holds the raw solution (skey_solution) and + // one expanded H row. The caller must scrub it -- the constant-time work above + // is pointless if the secret is simply left behind in the scratch buffer. +} + +EXPORT void sdith_sign(const signature_parameters* sig_params, // + void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* skey, // secret key + const void* entropy, // in: entropy + uint8_t* tmp_space) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + // secret key + const skey_mapping_t sk = map_secret_key(&par, skey); + + // signature fields + const signature_mapping_t sign = map_signature(&par, signature); + + // local variables + TMP_SPACE_MAP_ALIGNED(hash_t*, hash_com, 32, 2 * par.lambda_bytes); // commitment of the ggm tree + TMP_SPACE_MAP_ALIGNED(hash_t*, hash_aux, 32, + 2 * par.lambda_bytes); // (round1) ggm_cmt_hash + corr_terms :=> cchk matrix + // (round3) hash_aux + cchk_u + cchk_v + inputs_mask :=> chall + TMP_SPACE_MAP_ALIGNED(hash_t*, hash_lines, 32, 2 * par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(seed_t*, root_seed, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, u, 32, par.Lslice * par.tau); + TMP_SPACE_MAP_ALIGNED(uint8_t*, v, 32, par.Lslice * par.lambda); + TMP_SPACE_MAP_ALIGNED(uint8_t*, v2, 32, par.Lslice * par.lambda); // copy needed during transposition + TMP_SPACE_MAP_ALIGNED(uint8_t*, rvp_f_cz, 32, par.lambda_bytes* par.degree * 2); + TMP_SPACE_MAP_ALIGNED(uint8_t*, res_f, 32, par.lambda_bytes*(par.degree + 1)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_f, 32, par.lambda_bytes*(par.degree + 1)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + TMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_f, 32, par.lambda_bytes * 2 * par.num_inputs_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_unitary, 32, par.lambda_bytes* par.rsd_w); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_H, 32, par.lambda_bytes* par.rsd_n); + TMP_SPACE_MAP_ALIGNED(uint8_t*, chall_a_y, 32, par.lambda_bytes); + TMP_SPACE_MAP(uint8_t*, cchk_matrix, par.cchk_matrix_nrows* par.cchk_matrix_ncols >> 3); + TMP_SPACE_MAP_ALIGNED(uint8_t*, cchk_res_v, 32, par.lambda_bytes* par.cchk_matrix_nrows); + TMP_SPACE_MAP(uint8_t*, delta0, par.delta0_capacity); + TMP_SPACE_MAP_ALIGNED(uint8_t*, delta1, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + TMP_SPACE_MAP_CALL( + prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes(&par.vole_params, par.L)) + TMP_SPACE_MAP_CALL( + prover_cst_mux_circuit_ct_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + TMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + TMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + TMP_SPACE_MAP_CALL( + full_ggm_tree_open_sibling_path_from_root_tmp_bytes(&par.vole_params, par.target_topen) + ); + + // draw a random root seed and global salt (entropy) + memcpy(sign.global_salt, entropy, par.lambda_bytes); + memcpy(root_seed, ((uint8_t*)entropy) + par.lambda_bytes, par.lambda_bytes); + + // -------------------------------------- + // Phase 0: generation of the Vole pairs + // -------------------------------------- + + // generate vole pairs + prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + &par.vole_params, par.L, hash_com, u, v, sign.global_salt, root_seed, tmp_space); + + // transpose vole + // set the last lambda - kappa.tau rows to zero + memset(v + par.kappa * par.tau * par.Lslice, 0, (par.lambda - par.kappa * par.tau) * par.Lslice); + prover_midsize_to_fullsize_std_vole_ct_ref(&par.vole_params, par.L, u, u + par.Lslice, v2, u, v); + // copy the corrective terms to the signature + for (uint64_t i=0; i cchk matrix. + xof_ctx hash_aux_ctx; + par.vole_params.xof.xof_init_and_seed(&hash_aux_ctx, &HASH_AUX_PREFIX, 1); + par.vole_params.xof.xof_seed(&hash_aux_ctx, hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_aux_ctx, sign.corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&hash_aux_ctx, hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&hash_aux_ctx); + + uint8_t* const rvp_u_cchk = u; + uint8_t* const rvp_v_cchk = v2; + const uint64_t num_inputs_padded = (par.num_inputs_pairs + 7) & UINT64_C(-8); + uint8_t* const rvp_u_in = rvp_u_cchk + (par.num_cchk_pairs >> 3); + uint8_t* const rvp_v_in = rvp_v_cchk + (par.num_cchk_pairs * par.lambda_bytes); + uint8_t* const rvp_u_cz = rvp_u_cchk + ((par.num_cchk_pairs + num_inputs_padded) >> 3); + uint8_t* const rvp_v_cz = rvp_v_cchk + ((par.num_cchk_pairs + num_inputs_padded) * par.lambda_bytes); + + // vole consistency check + both_vole_consistency_check_matrix(&par.vole_params, par.L, cchk_matrix, hash_aux, 2 * par.lambda_bytes); + prover_vole_consistency_check(&par.vole_params, par.L, sign.cchk_u, cchk_res_v, u, v2, cchk_matrix); + + // -------------------------------------- + // Phase 1: Build and Commit Witness/Masking polynomials + // -------------------------------------- + + // f2 to flambda + prover_f2_to_flambda_deg1_std_vole_ct_ref(&par.vole_params, par.degree - 1, rvp_f_cz, rvp_u_cz, rvp_v_cz); + // deg1 to degd [in place] + prover_flambda_deg1_to_degd_vole_ref(&par.vole_params, par.degree - 1, rvp_f_cz, rvp_f_cz); + // std to cst: deg d [in place] + prover_flambda_degd_std_to_cst_vole_ct_ref(&par.vole_params, par.degree - 1, rvp_f_cz, rvp_f_cz); + // std to cst: deg 1 [in place] + prover_f2_std_to_cst_vole_ct_ref(&par.vole_params, par.num_inputs_pairs, rvp_u_in, rvp_v_in, rvp_u_in, rvp_v_in); + + // ----- circuit evaluation ------ + // inputs + commit to it + prover_cst_vole_packed_secret_input_ct_ref( // + &par.vole_params, // + par.num_inputs_pairs, // + sign.circuit_in_pub, // publications -> signature + inputs_f, // output vole + sk.skey_encoded_solution, // input secret key bits + rvp_u_in, rvp_v_in); // rvp + + xof_ctx hash_lines_ctx; // round1 + cchk_u + cchk_v + inputs_mask :=> chall + par.vole_params.xof.xof_init_and_seed(&hash_lines_ctx, &HASH_LINES_PREFIX, 1); + par.vole_params.xof.xof_seed(&hash_lines_ctx, hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_lines_ctx, sign.cchk_u, (par.num_cchk_pairs + 7) >> 3); + par.vole_params.xof.xof_seed(&hash_lines_ctx, cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_lines_ctx, sign.circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&hash_lines_ctx, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&hash_lines_ctx); + + // -------------------------------------- + // Phase 3: PIOP protocol (prover side) + // -------------------------------------- + + // generate the batching challenge points + xof_ctx chall_rng; + par.vole_params.xof.xof_init_and_seed(&chall_rng, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_finalize_and_output(&chall_rng, chall_a, par.lambda_bytes * par.rsd_codim_limbs); + par.vole_params.xof.xof_output(&chall_rng, chall_unitary, par.lambda_bytes * par.rsd_w); + par.vole_params.xof.xof_ctx_release(&chall_rng); + + rsd_public_key_times_challenge_ref( // + &par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // + chall_a_H, chall_a_y, // + chall_a, sk.pkey_seed, // + sk.pkey_y, tmp_space); // + + // evaluate the mux trees + memset(res_f, 0, (par.degree + 1) * par.lambda_bytes); + par.vole_params.flambda_set(res_f, chall_a_y); + for (uint64_t i = 0; i < par.rsd_w; i++) { + prover_cst_mux_circuit_ct_ref( // + &par.vole_params, // + par.mux_depth, par.mux_arities, par.rsd_npw, // circuit parameters + mux_f, // mux output + inputs_f + 2 * par.lambda_bytes * par.mux_inputs * i, // secret input bits (bin, deg 1) + chall_a_H + par.lambda_bytes * par.rsd_npw * i, // challenge points (mul by H) + chall_unitary + par.lambda_bytes * i, // check_unitary challenge (depth coeffs) + tmp_space); + prover_cst_vole_xor_gate_ct_ref( // + &par.vole_params, // + res_f, // result + res_f, par.degree, // lhs + mux_f, par.degree); // rhs + } +#ifdef PARANOIA_CHECK + { + // manual verification that res_f is zero + for (uint64_t i = 0; i < par.lambda_bytes; i++) { + CREQUIRE(res_f[i] == 0, "bug! res_f cst term is not zero!"); + } + } +#endif // PARANOIA_CHECK + // checkzero + prover_cst_vole_check_zero_gate_ct_ref( // + &par.vole_params, // + par.degree, // + cz_pub_full, // + res_f, // + rvp_f_cz); // rvp + memcpy(sign.circuit_cz_pub, cz_pub_full + par.lambda_bytes, (par.degree - 1) * par.lambda_bytes); + + xof_ctx hash_piop_ctx; // round3 + check_zero + message :=> delta + par.vole_params.xof.xof_init_and_seed(&hash_piop_ctx, &HASH_PIOP_PREFIX, 1); + par.vole_params.xof.xof_seed(&hash_piop_ctx, sk.pkey_seed, par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, sk.pkey_y, par.rsd_codim_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&hash_piop_ctx, sign.hash_piop, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&hash_piop_ctx); + + // -------------------------------------- + // Phase 3: Open one random evaluation + // -------------------------------------- + + // ----- open delta ------ + // generate delta0 != 0 s.t. topen is good (POW) + uint64_t topen = 1e9; + memset(delta0, 0, par.delta0_capacity); + uint64_t pow_ctr = 0; + par.vole_params.proofow_init(pow_ctx, par.lambda, par.kappa, par.tau, par.proofow_w, sign.hash_piop); + while (1) { + int r = par.vole_params.proofow_grind_w(pow_ctx, delta0, &pow_ctr); + if (!r) abort(); // SIGNATURE FAILED: impossible to do the proofow // TODO return code? + if (bitvec_is_zero_nonct(delta0, par.tau * par.kappa)) continue; // retry + hidden_leaves_indexes2(par.kappa, par.tau, hidden_leaves_idx, delta0); + topen = estimate_topen(par.tau, par.kappa, par.target_topen, hidden_leaves_idx, tmp_space); + if (topen <= par.target_topen) break; // success! + ++pow_ctr; + } + par.vole_params.proofow_release(pow_ctx); + memcpy(sign.proofow_ctr_reveal, &pow_ctr, PROOFOW_CTR_REVEALED_BYTES); + + // generate delta1 + delta1_from_delta0_ref(&par.vole_params, delta1, delta0); + + // generate ggm_opening_data + full_ggm_tree_open_sibling_path_from_root( + &par.vole_params, // params + sign.ggm_sibling_path, // -> signature + sign.ggm_hidden_leaf_cmt, // -> signature + root_seed, sign.global_salt, // salt + hidden_leaves_idx, // indexes of the hidden leaves + topen, // exact size + tmp_space); + // zero-out the unused ggm path + uint8_t* ggm_sibling_path_zero_start = (uint8_t*)sign.ggm_sibling_path + topen * par.lambda_bytes; + memset(ggm_sibling_path_zero_start, 0, (par.target_topen - topen) * par.lambda_bytes); +} + +EXPORT uint64_t sdith_verify_tmp_bytes(const signature_parameters* sig_params) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_aux, 32, + 2 * par.lambda_bytes); // ggm_cmt_hash + corr_terms :=> cchk matrix + COMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_lines, 32, + 2 * par.lambda_bytes); // round1 + cchk_u + cchk_v + inputs_mask :=> chall + COMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_piop, 32, + 2 * par.lambda_bytes); // round3 + check_zero + message :=> delta + COMP_SPACE_MAP_ALIGNED(uint32_t*, verif_hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + COMP_SPACE_MAP(uint8_t*, verif_delta0, par.delta0_capacity); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta1, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2_dm1, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_corr, 32, par.Lslice* par.tau); + COMP_SPACE_MAP_ALIGNED(uint8_t*, q, 32, par.Lslice* par.lambda); + COMP_SPACE_MAP_ALIGNED(uint8_t*, q2, 32, par.Lslice* par.lambda); // copy needed during transposition + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_hash_com, 32, + 2 * par.lambda_bytes); // ggm commitment hash (verify against the signature) + COMP_SPACE_MAP(uint8_t*, verif_cchk_matrix, par.Lbyte* par.num_cchk_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_cchk_res_v, 32, par.lambda_bytes* par.num_cchk_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_q, 32, par.lambda_bytes* par.num_inputs_pairs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_unitary, 32, par.lambda_bytes* par.rsd_w); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_H, 32, par.lambda_bytes* par.rsd_n); + COMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_y, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, mux_q, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, res_q, 32, par.lambda_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + COMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + COMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + COMP_SPACE_MAP_CALL(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( + &par.vole_params, par.L, par.target_topen) // number of pairs to generate + ); + COMP_SPACE_MAP_CALL( + verifier_cst_mux_circuit_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + COMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)); + COMP_SPACE_RETURN(); +} + +#define VERIFY_OR_FAIL(condition, error_message) \ + if (!(condition)) { \ + return 0; \ + } +#define VERIFY_SUCCESS() return 1 + +EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + const void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* pkey, // secret key + uint8_t* tmp_space) { + extended_parameters_t par; + compute_extended_parameters(&par, sig_params); + + // public key + const pkey_mapping_t pk = map_public_key(&par, pkey); + + // signature fields + const signature_mapping_t sign = map_signature(&par, signature); + + // local variables + TMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_aux, 32, + 2 * par.lambda_bytes); // ggm_cmt_hash + corr_terms :=> cchk matrix + TMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_lines, 32, + 2 * par.lambda_bytes); // round1 + cchk_u + cchk_v + inputs_mask :=> chall + TMP_SPACE_MAP_ALIGNED(hash_t*, verif_hash_piop, 32, 2 * par.lambda_bytes); // round3 + check_zero + message :=> delta + TMP_SPACE_MAP_ALIGNED(uint32_t*, verif_hidden_leaves_idx, 4, par.tau * sizeof(uint32_t)); + TMP_SPACE_MAP(uint8_t*, verif_delta0, par.delta0_capacity); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta1, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_delta2_dm1, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_corr, 32, par.Lslice* par.tau); + TMP_SPACE_MAP_ALIGNED(uint8_t*, q, 32, par.Lslice* par.lambda); + TMP_SPACE_MAP_ALIGNED(uint8_t*, q2, 32, par.Lslice* par.lambda); // copy needed during transposition + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_hash_com, 32, + 2 * par.lambda_bytes); // ggm commitment hash (verify against the signature) + TMP_SPACE_MAP(uint8_t*, verif_cchk_matrix, par.Lbyte* par.num_cchk_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_cchk_res_v, 32, par.lambda_bytes* par.num_cchk_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, inputs_q, 32, par.lambda_bytes* par.num_inputs_pairs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_unitary, 32, par.lambda_bytes* par.rsd_w); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a, 32, par.lambda_bytes* par.rsd_codim_limbs); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_H, 32, par.lambda_bytes* par.rsd_n); + TMP_SPACE_MAP_ALIGNED(uint8_t*, verif_chall_a_y, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, mux_q, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, res_q, 32, par.lambda_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t*, cz_pub_full, 32, par.lambda_bytes* par.degree); + TMP_SPACE_MAP_ALIGNED(proofow_ctx_t*, pow_ctx, 32, par.vole_params.bytes_of_proofow_ctx()); + TMP_SPACE_MAP_CALL(estimate_topen_tmp_bytes(par.tau, par.kappa)); + TMP_SPACE_MAP_CALL(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( + &par.vole_params, par.L, par.target_topen) // number of pairs to generate + ); + TMP_SPACE_MAP_CALL( + verifier_cst_mux_circuit_ref_tmp_bytes(&par.vole_params, par.mux_depth, par.mux_arities, par.rsd_npw)); + TMP_SPACE_MAP_CALL(rsd_public_key_times_challenge_tmp_bytes(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim)) + + // verifier side + uint64_t leftover_bits = par.num_inputs_pairs & 7; + if (leftover_bits) { + uint64_t mask = ((1 << (8 - leftover_bits)) - 1) << leftover_bits; + uint64_t idx = ((par.num_inputs_pairs + 7) >> 3) - 1; + VERIFY_OR_FAIL((sign.circuit_in_pub[idx] & mask) == 0, "in_publications does not have trailing zeros"); + } + + // -------------------------------------- + // Phase 1: Recompute and check the evaluation + // -------------------------------------- + + // ----- open delta ------ + // generate delta0 != 0 s.t. topen is good (POW) + uint64_t topen = 1e9; + uint64_t proof_of_work_counter = 0; + memset(verif_delta0, 0, par.delta0_capacity); + memcpy(&proof_of_work_counter, sign.proofow_ctr_reveal, PROOFOW_CTR_REVEALED_BYTES); // load the golden counter + par.vole_params.proofow_init(pow_ctx, par.lambda, par.kappa, par.tau, par.proofow_w, sign.hash_piop); + int r = par.vole_params.proofow_verify_w(pow_ctx, verif_delta0, proof_of_work_counter); + par.vole_params.proofow_release(pow_ctx); + VERIFY_OR_FAIL(r, "invalid proof of work: vgrind"); + VERIFY_OR_FAIL(!bitvec_is_zero_nonct(verif_delta0, par.tau * par.kappa), "invalid proof of work: zero"); + hidden_leaves_indexes2(par.kappa, par.tau, verif_hidden_leaves_idx, verif_delta0); + topen = estimate_topen(par.tau, par.kappa, par.target_topen, verif_hidden_leaves_idx, tmp_space); + VERIFY_OR_FAIL(topen <= par.target_topen, "invalid proof of work: topen"); + + // check that the sibling path has trailing zeroes (if needed) + { + uint64_t zero_values = par.target_topen - topen; + uint8_t* ggm_sibling_path_zero_start = (uint8_t*)sign.ggm_sibling_path + topen * par.lambda_bytes; + // bitvec_is_zero_nonct counts BITS, so scale the byte length by 8. Without the + // *8 only 1/8 of the zeroed tail was checked, leaving the rest malleable. + VERIFY_OR_FAIL(bitvec_is_zero_nonct(ggm_sibling_path_zero_start, zero_values * par.lambda_bytes * 8), + "sibling path cleanliness"); + } + // generate delta1 and delta2 + delta1_from_delta0_ref(&par.vole_params, verif_delta1, verif_delta0); + delta2_from_delta1_ref(&par.vole_params, verif_delta2, verif_delta1); + + // From Vole perspective, the evaluation point is Delta1 (Delta0 is blockwise, the Grey code of Delta1) + // Vole protocol reconstructs pairs evaluated in Delta1. + + // generate vole pairs + memset(verif_corr, 0, par.Lslice * par.tau); + for (uint64_t i = 0; i < par.tau - 1; i++) { + memcpy(verif_corr + (i+1) * par.Lslice, sign.corr_u + i * par.Lbyte, par.Lbyte); + } + verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + &par.vole_params, par.L, // dimensions + verif_hash_com, // [out] hash of the leaves commits + q, // [out] TAU x KAPPA x L row major + verif_corr, // [in/out] TAU x L bits + verif_hidden_leaves_idx, // [in] TAU indices of the hidden (node) leaves + sign.ggm_hidden_leaf_cmt, // [in] TAU commits of the hidden (node) leaves + sign.ggm_sibling_path, // [in] Topen sibling seeds + topen, // [in] number of sibling seeds + sign.global_salt, // [in] global salt for the GGM tree + verif_delta1, // verifier's point delta1 + tmp_space); + + // then we reconvert these vole pairs into PIOP material. + // From PIOP perspective, the verifier gets the evaluation in Delta2 (qhich is the inverse of Delta1) + + // ----- vole preprocessing ------ + // transpose vole + memset(q + par.kappa * par.tau * par.Lslice, 0, (par.lambda - par.kappa * par.tau) * par.Lslice); + verifier_midsize_to_fullsize_std_vole_ref(&par.vole_params, par.L, q2, q); + + uint8_t* const rvp_q_cchk = q2; + const uint64_t num_inputs_padded_v = (par.num_inputs_pairs + 7) & UINT64_C(-8); + uint8_t* const rvp_q_in = rvp_q_cchk + (par.num_cchk_pairs * par.lambda_bytes); + uint8_t* const rvp_q_cz = rvp_q_cchk + ((par.num_cchk_pairs + num_inputs_padded_v) * par.lambda_bytes); + + // round 1 hash: prefix, hash_com(ggm), corr_terms :=> cchk matrix. + xof_ctx verif_hash_aux_ctx; + par.vole_params.xof.xof_init_and_seed(&verif_hash_aux_ctx, &HASH_AUX_PREFIX, 1); + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, verif_hash_com, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_aux_ctx, sign.corr_u, (par.tau - 1) * par.Lbyte); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_aux_ctx, verif_hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&verif_hash_aux_ctx); + + // vole consistency check + both_vole_consistency_check_matrix(&par.vole_params, par.L, verif_cchk_matrix, verif_hash_aux, 2 * par.lambda_bytes); + verifier_vole_consistency_check(&par.vole_params, par.L, verif_cchk_res_v, sign.cchk_u, q2, verif_cchk_matrix, + verif_delta1); + + xof_ctx verif_hash_lines_ctx; // round1 + cchk_u + cchk_v + inputs_mask :=> chall + par.vole_params.xof.xof_init_and_seed(&verif_hash_lines_ctx, &HASH_LINES_PREFIX, 1); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, verif_hash_aux, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, sign.cchk_u, (par.num_cchk_pairs + 7) >> 3); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, verif_cchk_res_v, par.cchk_matrix_nrows * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_lines_ctx, sign.circuit_in_pub, (par.num_inputs_pairs + 7) >> 3); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_lines_ctx, verif_hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&verif_hash_lines_ctx); + + // -------------------------------------- + // PIOP Protocol (verifier's side) + // -------------------------------------- + // At this point, delta2 is the only point that matters: the verifier will check + // the PIOP circuit evaluated on delta2. + + // f2 to flambda + verifier_f2_to_flambda_deg1_std_vole_ref(&par.vole_params, par.degree - 1, rvp_q_cz, rvp_q_cz); + // deg1 to degd [in place] + verifier_flambda_deg1_to_degd_vole_ref(&par.vole_params, par.degree - 1, rvp_q_cz, rvp_q_cz, verif_delta1); + // std to cst: deg d [in place] + flambda_power(&par.vole_params, verif_delta2_dm1, verif_delta2, par.degree - 1); + verifier_flambda_degd_std_to_cst_vole_ref(&par.vole_params, par.degree - 1, rvp_q_cz, rvp_q_cz, verif_delta2_dm1); + // std to cst: deg 1 [in place] + verifier_f2_std_to_cst_vole_ref(&par.vole_params, par.num_inputs_pairs, rvp_q_in, rvp_q_in, verif_delta2); + + // ----- circuit evaluation ------ + // inputs + commit to it + verifier_cst_vole_packed_secret_input_ref( // + &par.vole_params, // + par.num_inputs_pairs, // + inputs_q, + sign.circuit_in_pub, // publications -> signature + rvp_q_in, + verif_delta2); // rvp + + // reconstruct the batching challenge points + xof_ctx verif_chall_rng; + par.vole_params.xof.xof_init_and_seed(&verif_chall_rng, verif_hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_finalize_and_output(&verif_chall_rng, verif_chall_a, par.lambda_bytes * par.rsd_codim_limbs); + // note: the chall unitary are only needed if the mux tree contains one non-binary arity + par.vole_params.xof.xof_output(&verif_chall_rng, verif_chall_unitary, par.lambda_bytes * par.rsd_w); + par.vole_params.xof.xof_ctx_release(&verif_chall_rng); + + rsd_public_key_times_challenge_ref(&par.vole_params, par.rsd_w, par.rsd_n, par.rsd_codim, // + verif_chall_a_H, verif_chall_a_y, // + verif_chall_a, pk.pkey_seed, pk.pkey_y, tmp_space); + par.vole_params.flambda_set(res_q, verif_chall_a_y); + for (uint64_t i = 0; i < par.rsd_w; i++) { + verifier_cst_mux_circuit_ref( // + &par.vole_params, // + par.mux_depth, par.mux_arities, par.rsd_npw, // circuit parameters + mux_q, // mux output + inputs_q + par.lambda_bytes * par.mux_inputs * i, // secret input bits (bin, deg 1) + verif_chall_a_H + par.lambda_bytes * par.rsd_npw * i, // challenge points (mul by H) + verif_chall_unitary + par.lambda_bytes * i, // check_unitary challenge (depth coeffs) + verif_delta2, tmp_space); + verifier_cst_vole_xor_gate_ref( // + &par.vole_params, // + res_q, // result + res_q, par.degree, // lhs + mux_q, par.degree, // rhs + verif_delta2); + } + + // checkzero: reconstruct alpha_1 from alpha_2..alpha_d + VOLE evaluations + { + const uint64_t lb = par.lambda_bytes; + // partial is an operand of flambda_product/flambda_sum, so it needs the 32-byte + // alignment the gf256 backend loads it with (flambda_max_t provides it). + flambda_max_t partial; + memcpy(partial, sign.circuit_cz_pub + (par.degree - 2) * lb, lb); + for (int64_t i = par.degree - 3; i >= 0; i--) { + par.vole_params.flambda_product(partial, partial, verif_delta2); + flambda_max_t tmp; + memcpy(tmp, sign.circuit_cz_pub + i * lb, lb); + par.vole_params.flambda_sum(partial, partial, tmp); + } + par.vole_params.flambda_product(partial, partial, verif_delta2); + par.vole_params.flambda_sum(partial, partial, rvp_q_cz); + flambda_max_t rq_dinv; + par.vole_params.flambda_product(rq_dinv, res_q, verif_delta1); + par.vole_params.flambda_sum(partial, partial, rq_dinv); + memcpy(cz_pub_full, partial, lb); + memcpy(cz_pub_full + lb, sign.circuit_cz_pub, (par.degree - 1) * lb); + + // alpha_1 is not transmitted: hash the reconstructed alpha_1..alpha_d into + // h_piop and compare against the signature. This is the only acceptance test. + xof_ctx verif_hash_piop_ctx; + par.vole_params.xof.xof_init_and_seed(&verif_hash_piop_ctx, &HASH_PIOP_PREFIX, 1); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, pk.pkey_seed, par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, pk.pkey_y, par.rsd_codim_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, verif_hash_lines, 2 * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, cz_pub_full, par.degree * par.lambda_bytes); + par.vole_params.xof.xof_seed(&verif_hash_piop_ctx, message, message_bytes); + par.vole_params.xof.xof_finalize_and_output(&verif_hash_piop_ctx, verif_hash_piop, 2 * par.lambda_bytes); + par.vole_params.xof.xof_ctx_release(&verif_hash_piop_ctx); + VERIFY_OR_FAIL(memcmp(verif_hash_piop, sign.hash_piop, 2 * par.lambda_bytes) == 0, "invalid hash_piop"); + } + + VERIFY_SUCCESS(); +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature.h new file mode 100644 index 0000000000..59b6e51801 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature.h @@ -0,0 +1,132 @@ +#ifndef SDITH_SIGNATURE_H +#define SDITH_SIGNATURE_H + +// This header contains the main SDiTH signature + +#include "commons.h" + +/** signature main parameters */ +typedef struct signature_parameters_t { + uint64_t lambda; + uint64_t kappa; + uint64_t tau; + uint64_t target_topen; + uint64_t proofow_w; + uint64_t rsd_w; + uint64_t rsd_n; + uint64_t mux_depth; + uint64_t mux_arities[8]; + proofow_variant_t proofow_variant; +} signature_parameters; + +/** Default parameter sets */ +EXPORT_DECL const signature_parameters CAT1_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT1_FAST_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_FAST_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_FAST_PARAMETERS; +/** Default parameter sets for official variants */ +EXPORT_DECL const signature_parameters CAT1_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT1_FAST_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_FAST_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_FAST_CIPHERPOW_PARAMETERS; + +/** @brief Number of bytes of the secret key (in the sense keypair) */ +EXPORT uint64_t sdith_secret_key_bytes(const signature_parameters* sig_params); +/** @brief Number of bytes of the public key */ +EXPORT uint64_t sdith_public_key_bytes(const signature_parameters* sig_params); +/** @brief Number of bytes of a sdith signature */ +EXPORT uint64_t sdith_signature_bytes(const signature_parameters* sig_params); + +/** + * @brief Number of pure entropy bytes to provide to the keygen algorithm + * These bytes should be generated using a secure random generator, a random device, or something like /dev/urandom. + * During tests purposes, fixing the entropy makes the algorithm deterministic + */ +EXPORT uint64_t sdith_keygen_entropy_bytes(const signature_parameters* sig_params); + +/** + * @brief size of the scratch space to pass to the keygen function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_keygen_tmp_bytes(const signature_parameters* sig_params); + +/** + * @brief SDiTH Key generator + * @param sig_params parameter set + * @param skey [out] secret key (i.e. keypair) + * @param pkey [out] public key (i.e. keypair) + * @param entropy [in] entropy bytes + * @param tmp_space [tmp] scratch space -- holds secret key material on + * return (the raw solution): the caller must scrub it. + * + * Constant-time with respect to the generated secret key, save for the + * rejection loop of the position sampler (whose trip count is independent of + * the accepted positions). This holds only for the avx parameter table: the ref + * ct helpers are the readable definitions, not hardened ones. + */ +EXPORT void sdith_keygen(const signature_parameters* sig_params, // + void* skey, // out: secret key + void* pkey, // out: public key + const void* entropy, // in: entropy + uint8_t* tmp_space); + +/** + * @brief Number of pure entropy bytes to provide to the signature algorithm + * These bytes should be generated using a secure random generator, a random device, or something like /dev/urandom. + * During tests purposes, fixing the entropy makes the algorithm deterministic + */ +EXPORT uint64_t sdith_signature_entropy_bytes(const signature_parameters* sig_params); + +/** + * @brief size of the scratch space to pass to the signature function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_signature_tmp_bytes(const signature_parameters* sig_params); + +/** + * SDiTH signature + * @param sig_params parameter set + * @param signature [out] digital signature + * @param message [in] message to sign + * @param message_bytes [in] number of bytes of the message + * @param skey [in] secret key + * @param entropy [in] entropy bytes + * @param tmp_space [tmp] scratch space + */ +EXPORT void sdith_sign(const signature_parameters* sig_params, // + void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* skey, // secret key + const void* entropy, // in: entropy + uint8_t* tmp_space); + +/** + * @brief size of the scratch space to pass to the signature function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_verify_tmp_bytes(const signature_parameters* sig_params); + +/** + * Signature verification function + * @param sig_params SDiTH parameter set + * @param signature [in] signature to verify + * @param message [in] message that was signed + * @param message_bytes [in] size of the message + * @param pkey [in] public key + * @param tmp_space [tmp] scratch space + * @return + */ +EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + const void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* pkey, // secret key + uint8_t* tmp_space); + +#endif // SDITH_SIGNATURE_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature_parameters.c b/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature_parameters.c new file mode 100644 index 0000000000..e0b59ce299 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_signature_parameters.c @@ -0,0 +1,176 @@ +#include "sdith_signature.h" + +const signature_parameters CAT1_SHORT_PARAMETERS = { + // + .lambda = 128, // + .kappa = 11, // + .tau = 11, // + .target_topen = 109, // + .proofow_w = 9, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT3_SHORT_PARAMETERS = { + // + .lambda = 192, // + .kappa = 11, // + .tau = 17, // + .target_topen = 169, // + .proofow_w = 7, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // + }; + +const signature_parameters CAT5_SHORT_PARAMETERS = { + // + .lambda = 256, // + .kappa = 11, // + .tau = 23, // + .target_topen = 228, // + .proofow_w = 5, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT1_FAST_PARAMETERS = { + // + .lambda = 128, // + .kappa = 7, // + .tau = 18, // + .target_topen = 107, // + .proofow_w = 4, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT3_FAST_PARAMETERS = { + // + .lambda = 192, // + .kappa = 7, // + .tau = 27, // + .target_topen = 161, // + .proofow_w = 5, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +const signature_parameters CAT5_FAST_PARAMETERS = { + // + .lambda = 256, // + .kappa = 7, // + .tau = 36, // + .target_topen = 216, // + .proofow_w = 6, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_SHAKE // +}; + +// The cipher-grinding variants. kappa and the RSD parameters are shared with +// the base set (so pk and sk are identical), but do NOT just copy the base set +// and flip the variant: in round 3, cat1-fast and cat3-fast use their own tau, +// target_topen and proofow_w (see the specs, tab:params-voleith-aespow). The +// short sets and cat5-fast keep the base values, so only the variant differs +// for those. + +const signature_parameters CAT1_SHORT_CIPHERPOW_PARAMETERS = { + // + .lambda = 128, // + .kappa = 11, // + .tau = 11, // + .target_topen = 109, // + .proofow_w = 9, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT3_SHORT_CIPHERPOW_PARAMETERS = { + // + .lambda = 192, // + .kappa = 11, // + .tau = 17, // + .target_topen = 169, // + .proofow_w = 7, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // + }; + +const signature_parameters CAT5_SHORT_CIPHERPOW_PARAMETERS = { + // + .lambda = 256, // + .kappa = 11, // + .tau = 23, // + .target_topen = 228, // + .proofow_w = 5, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT1_FAST_CIPHERPOW_PARAMETERS = { + // + .lambda = 128, // + .kappa = 7, // + .tau = 17, // + .target_topen = 101, // + .proofow_w = 11, // + .rsd_w = 56, // + .rsd_n = 10360, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT3_FAST_CIPHERPOW_PARAMETERS = { + // + .lambda = 192, // + .kappa = 7, // + .tau = 26, // + .target_topen = 155, // + .proofow_w = 12, // + .rsd_w = 73, // + .rsd_n = 18396, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 4}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; + +const signature_parameters CAT5_FAST_CIPHERPOW_PARAMETERS = { + // + .lambda = 256, // + .kappa = 7, // + .tau = 36, // + .target_topen = 216, // + .proofow_w = 6, // + .rsd_w = 104, // + .rsd_n = 19864, // + .mux_depth = 4, // + .mux_arities = {4, 4, 4, 3}, // + .proofow_variant = PROOFOW_VARIANT_CIPHER // +}; diff --git a/src/sig/sdith/sdith_sdith_common_avx2/sdith_vole_to_piop.h b/src/sig/sdith/sdith_sdith_common_avx2/sdith_vole_to_piop.h new file mode 100644 index 0000000000..7f5d6b60bd --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/sdith_vole_to_piop.h @@ -0,0 +1,88 @@ +#ifndef SDITH_VOLE_TO_PIOP_H +#define SDITH_VOLE_TO_PIOP_H + +// This header contains the functions used to convert vole pairs into piop pairs +// For each step of the conversion, there is a prover side and a verifier's side function. + +#include "vole_parameters.h" + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void prover_f2_to_flambda_deg1_std_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + fpoly_t* out_f, // [out] deg-1 fpoly[num_pairs] + const bitvec_t* in_u, // [in] in_L bits where in_L = num_pairs * LAMBDA + const flambda_t* in_v); // [in] flambda[in_L] + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void verifier_f2_to_flambda_deg1_std_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + flambda_t* out_q, // [out] gflambda[num_pairs] + const flambda_t* in_q); // [in] gflambda in_q[in_L] where in_L = num_pairs * LAMBDA + +/** + * @brief convert packed degree 1 std-vole to packed cst-vole + * (Prover side is just the identity function) + */ +EXPORT void prover_f2_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + bitvec_t* out_u, flambda_t* out_v, // [out] bit[num_pairs], flambda[num_pairs] + const bitvec_t* in_u, const flambda_t* in_v); // [in] bit[num_pairs], flambda[num_pairs] + +/** + * @brief convert packed degree 1 std-vole to packed cst-vole + */ +EXPORT void verifier_f2_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + flambda_t* out_q, // [in] gflambda[num_pairs] + const flambda_t* in_q, // [in] gflambda[num_pairs] + const flambda_t* delta2); // [in] verifier's point + +/** + * convert d degree 1 std-vole over flambda to one degree-d vole + */ +EXPORT void prover_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + fpoly_t* out_f, // single poly_t of degree out_degree + const fpoly_t* in_f); // out_degree poly[out_degree] + +/** + * convert d degree 1 std-vole to one degree-d vole + */ +EXPORT void verifier_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + flambda_t* out_q, // [out] single gflambda + const flambda_t* in_q, // [in] gflambda[out_deg] + const flambda_t* delta_powers); // verifier's point powers + +/** + * convert a degree-d vole from std to cst + */ +EXPORT void prover_flambda_degd_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // degree d of of the pair to process + fpoly_t* out_f, // [out] single poly of degree d + const fpoly_t* in_f); // [in] single poly of degree d + +/** + * convert a degree-d vole from std to cst + */ +EXPORT void verifier_flambda_degd_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // output degree + flambda_t* out_q, // [out] single evaluation + const flambda_t* in_q, // [in] single evaluation + const flambda_t* delta_pow_d); // [in] verifier's point to the power d + +#endif // SDITH_VOLE_TO_PIOP_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_expansion.c b/src/sig/sdith/sdith_sdith_common_avx2/vole_expansion.c new file mode 100644 index 0000000000..eb49506cef --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_expansion.c @@ -0,0 +1,873 @@ +#include +#include + +#include "ggm.h" +#include "sdith_prng.h" +#include "vole_private.h" + +#ifndef SDITH3_FOR_LIBOQS +#include "KeccakSpongetimes4.h" +#endif + +#ifndef NDEBUG +#define MSTACK_DEF(bytelen) \ + uint8_t stack_var[bytelen] __attribute((aligned(32))); \ + uint8_t* stack_cur = stack_var; \ + uint8_t* const stack_end = stack_var + bytelen + +#define MSTACK_ALLOC(bytelen) \ + (void*)stack_cur; \ + stack_cur += bytelen; \ + CREQUIRE(stack_cur <= stack_end, "manual stack overflow!!") +#else +#define MSTACK_DEF(bytelen) \ + uint8_t stack_var[bytelen] __attribute((aligned(32))); \ + uint8_t* stack_cur = stack_var + +#define MSTACK_ALLOC(bytelen) \ + (void*)stack_cur; \ + stack_cur += bytelen +#endif + +#ifndef SDITH3_FOR_LIBOQS +// these don't appear to be used here at all, so no corresponding liboqs implimentaion is added +#define BATCH_XOF_STRIDE (((sizeof(KeccakWidth1600times4_SpongeInstance) + 31) / 32) * 32) +#define BATCH_XOF(base, idx) ((KeccakWidth1600times4_SpongeInstance*)((uint8_t*)(base) + (idx) * BATCH_XOF_STRIDE)) +#endif + +/** @brief converts delta0 to delta1 + * delta0 has kappa*tau bits, encoding tau grey code encodings + * delta1 has lambda bits, only the lowest kappa*tau are used, the rest is zero. + */ +EXPORT void delta1_from_delta0_ref(const vole_parameters* vole_params, flambda_t* delta1, const bitvec_t* delta0) { + // bit_vector delta1_from_delta0(uint64_t kappa, uint64_t tau, uint64_t lambda, const bit_vector& delta0) { + const uint64_t kappa = vole_params->KAPPA; + const uint64_t tau = vole_params->TAU; + CASSERT(vole_params->LAMBDA >= tau * kappa, "invalid lambda"); + CASSERT(tau * kappa > 0, "invalid kappa, tau"); + CASSERT(delta0 != delta1, "in_place not supported"); + memset(delta1, 0, vole_params->lambda_bytes); + for (uint64_t i = 0; i < tau; i++) { + uint64_t pos = extract_kappabit_uint(kappa, i * kappa, delta0); + xorto_kappabit_uint(kappa, i * kappa, delta1, pos ^ (pos >> 1)); + } +} + +/** + * number of tmp bytes needed by the function + */ +EXPORT uint64_t prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L // number of pairs to generate [Lslice next mult of 32] +) { + const uint64_t Lbytesx = L >> 3; + const uint64_t Lslice = (Lbytesx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + //const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + //const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + //const uint64_t nleaves = UINT64_C(1) << KAPPA; + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + // tree representation + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + COMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + COMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + COMP_SPACE_MAP_ALIGNED(bitvec_t**, uu, 8, TAU * sizeof(bitvec_t*)); + COMP_SPACE_MAP_ALIGNED(bitmat_t**, vv, 8, TAU * sizeof(bitmat_t*)); + COMP_SPACE_RETURN(); +} + + +/** + * Generate L vole pairs over (F2,F2^KAPPA) (grey code + BFS version) + * @param u (output): L bits: Xor of all ri's, + * @param v (output): matrix KAPPA x L bits: Xor of ri.grey(i) + */ +EXPORT void prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate [Lslice next mult of 32] + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* u, // [out] TAU x (L bits on Lslice bytes) + bitmat_t* v, // [out] TAU x KAPPA x (L bits on Lslice bytes) row major + const salt_t* global_salt, // [in] global salt for the GGM tree + const seed_t* ggm_root_seed, // [in] root seed for the GGM tree + uint8_t* tmp_space) // [tmp] scratch space +{ + const uint64_t Lbytesx = L >> 3; + const uint64_t Lslice = (Lbytesx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t nleaves = UINT64_C(1) << KAPPA; + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + // tree representation + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + TMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + TMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + TMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + TMP_SPACE_MAP_ALIGNED(bitvec_t**, uu, 8, TAU * sizeof(bitvec_t*)); + TMP_SPACE_MAP_ALIGNED(bitmat_t**, vv, 8, TAU * sizeof(bitmat_t*)); + // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) + vole_params->prepare_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + // the two domain-separated salts: one for the GGM tree, one for the vole rng + uint64_t* const ggm_masked_salt = masked_salts; + uint64_t* const vole_masked_salt = masked_salts + (SEED_BYTES >> 3); + compute_tweaked_salts(vole_params, ggm_masked_salt, vole_masked_salt, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); + for (uint64_t i = 0; i < TAU; ++i) { // some handy double pointers for vole + uu[i] = u + i * Lslice; + vv[i] = v + i * KAPPA * Lslice; + } + for (uint64_t i = 0; i < TAU; ++i) { // some handy double pointers for xofs + commit_ptrs[i] = commit_buffer + i * COMMIT_BYTES; + } + uint8_t* const subhashes = commit_buffer; // we will share that space since the subhash size is 2lambda + uint8_t** const subhashes_ptrs = commit_ptrs; + + // memcpy the root of the tree + memcpy(seeds + SEED_BYTES, ggm_root_seed, SEED_BYTES); + + // expand all the seeds using the seed_rng + uint64_t next_node_idx = 2; // also equal to the num leaves to write at that depth + const uint8_t* rd_ptr = seeds + SEED_BYTES; // root position (node_id = 1) + uint8_t* wr_ptr = seeds + 2 * SEED_BYTES; // left child (node_id=2) + // expand the first two depths of the tree one by one + while (next_node_idx < 8) { + vole_params->extend_leaf_seed(ext_seeds, rd_ptr); + vole_params->ggm_extseed_rng_lr(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 2 * SEED_BYTES; + rd_ptr += SEED_BYTES; + next_node_idx += 2; + } + // expand the rest of the depths 4x by 4x + while (next_node_idx <= TOTAL_NODES) { + vole_params->extend_leaf_seed_4x(ext_seeds, rd_ptr); + // I8: expand the 4 sibling parents (node_idx, +2, +4, +6) in one call. The cat1 avx2 + // build batches them into one 8-block encrypt; the other builds do four single calls. + vole_params->ggm_extseed_rng_lr_x4(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 8 * SEED_BYTES; + rd_ptr += 4 * SEED_BYTES; + next_node_idx += 8; + } + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have filled the tree"); + + // expand all the leaf seeds into commit and vole randomness + memset(u, 0, TAU * Lslice); + memset(v, 0, TAU * KAPPA * Lslice); + vole_params->xof_vector.init_and_seed(commit_xofs, TAU, &HASH_BAVC_PREFIX, 1); + + uint64_t l = 0; + next_node_idx = TOTAL_LEAVES; + const uint8_t* next_leaf_seed = seeds + TOTAL_LEAVES * SEED_BYTES; // ptr of the first leaf seed + const uint8_t* const end_leaf_seed = seeds + (TOTAL_NODES + 1) * SEED_BYTES; + while (next_leaf_seed < end_leaf_seed) { + // expand 4 * TAU leaf seeds and advance the read pointer + uint8_t* out_ext_seed = ext_seeds; + for (uint64_t i = 0; i < TAU; ++i) { + // expand the leaf seed -> expanded buffer + vole_params->extend_leaf_seed_4x(out_ext_seed, // output + next_leaf_seed // leaf seed + ); + next_leaf_seed += 4 * LAMBDA_BYTES; + out_ext_seed += 4 * EXT_BYTES; + } + CASSERT(out_ext_seed == ext_seeds + 4 * TAU * EXT_BYTES, "out_ext_seed should be at the end of the buffer"); + + // process the 4 * TAU expanded leaves (it corresponds to 4 positions) + const uint8_t* in_expanded_seed = ext_seeds; + for (uint64_t nb = 0; nb < 4; ++nb) { + const uint64_t loc = (l + 1 < nleaves) ? binval_of(l + 1) : KAPPA - 1; + const uint64_t loc_offset = loc * Lslice; + uint8_t* out_commit = commit_buffer; + for (uint64_t i = 0; i < TAU; ++i) { + // compute the commit and add it to the commit buffer + vole_params->ggm_extseed_rng_commit(out_commit, // out + ggm_masked_salt, // salt + in_expanded_seed, // expanded_seed + next_node_idx // node_idx + ); + // compute the vole_rng and process it + vole_params->vole_extseed_rng(tmp_r, Lslice, // out (only Lbytes would suffice here) + vole_masked_salt, // salt + in_expanded_seed, // expanded_seed + i); // repetition index + vole_params->bitvec_cascade_xor_to(Lslice, vv[i] + loc_offset, uu[i], tmp_r); + // advance pointers + in_expanded_seed += EXT_BYTES; + out_commit += COMMIT_BYTES; + next_node_idx += 1; + } + // hash the commits + vole_params->xof_vector.seed(commit_xofs, TAU, commit_ptrs, COMMIT_BYTES); + // advance the pointers + ++l; + } + CASSERT(in_expanded_seed == ext_seeds + 4 * TAU * EXT_BYTES, "we should have consumed all the expanded seeds"); + } + CASSERT(l == nleaves, "we should have processed all the leaves"); + CASSERT(next_leaf_seed == end_leaf_seed, "we should have processed all the leaves"); + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have processed all the leaves"); + + // now, hash the per-rep subhashes into the final commits hash: + // commits_hash = H(HASH_BAVC_PREFIX, global_salt, subhashes). the full salt is + // bound first (it commits all lambda bits, whereas the tweaked salts drop the + // low GGM_TWEAK_BITS and the top prefix bits), then the per-rep subhashes. + vole_params->xof_vector.finalize_and_output(commit_xofs, TAU, subhashes_ptrs, 2 * LAMBDA_BYTES); + vole_params->xof_vector.ctx_release(commit_xofs, TAU); + xof_ctx commits_xof; + vole_params->xof.xof_init_and_seed(&commits_xof, &HASH_BAVC_PREFIX, 1); + vole_params->xof.xof_seed(&commits_xof, global_salt, LAMBDA_BYTES); + vole_params->xof.xof_seed(&commits_xof, subhashes, 2 * TAU * LAMBDA_BYTES); + vole_params->xof.xof_finalize_and_output(&commits_xof, commits_hash, 2 * LAMBDA_BYTES); + vole_params->xof.xof_ctx_release(&commits_xof); + + // release any per-slot state the ext_seed backend cached (no-op unless the + // liboqs aes128 backend is in use) + vole_params->release_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); +} + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) -- tmp bytes needed + */ +EXPORT uint64_t verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + uint64_t topen // (max) size of the sibling path + ) { + const uint64_t Lbytesxx = L >> 3; + const uint64_t Lslice = (Lbytesxx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + COMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + COMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + COMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + COMP_SPACE_MAP_ALIGNED(bitvec_t**, ss, 8, TAU * sizeof(bitvec_t*)); + COMP_SPACE_MAP_ALIGNED(bitmat_t**, qq, 8, TAU * sizeof(bitmat_t*)); + COMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_nodes_idx, 8, (2 * TAU + topen + 1) * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(uint32_t*, sibling_nodes_idx, 8, (topen + 1) * sizeof(uint32_t)); + COMP_SPACE_RETURN(); +} + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) + */ +EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* q, // [out] TAU x KAPPA x L row major + bitmat_t* coor_terms, // [in/out] TAU x L bits + const uint32_t* hidden_leaves_idx, // [in] TAU indices of the hidden (node) leaves + const commit_t* hidden_leaves_commit, // [in] TAU commits of the hidden (node) leaves + const seed_t* sibling_seeds, // [in] Topen sibling seeds + const uint64_t topen, // [in] number of sibling seeds + const salt_t* global_salt, // [in] global salt for the GGM tree + const flambda_t* delta1, // verifier's point delta1 + uint8_t* tmp_space) { + const uint64_t Lbytesxx = L >> 3; + const uint64_t Lslice = (Lbytesxx + 31) & UINT64_C(-32); + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t LAMBDA_BYTES = vole_params->lambda_bytes; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + const uint64_t nleaves = UINT64_C(1) << KAPPA; + + const uint64_t SEED_BYTES = LAMBDA_BYTES; + const uint64_t COMMIT_BYTES = 2 * LAMBDA_BYTES; + + const uint64_t TOTAL_LEAVES = TAU << KAPPA; // total number of leaves in the tree + const uint64_t TOTAL_NODES = (TOTAL_LEAVES << 1) - 1; + const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t xof_vector_ctx_bytes = vole_params->xof_vector.ctx_bytes(TAU); + + CASSERT(L % 8 == 0, "currently, we support only L multiple of 8"); + + TMP_SPACE_MAP_ALIGNED(uint64_t*, masked_salts, 32, 2 * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, (TOTAL_NODES + 1) * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seeds, 32, 4 * TAU * EXT_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, commit_buffer, 32, TAU* COMMIT_BYTES); + TMP_SPACE_MAP_ALIGNED(bitvec_t*, tmp_r, 32, Lslice); + TMP_SPACE_MAP_ALIGNED(xof_vector_ctx*, commit_xofs, 32, xof_vector_ctx_bytes); + TMP_SPACE_MAP_ALIGNED(uint8_t**, commit_ptrs, 8, TAU * sizeof(uint8_t*)); + TMP_SPACE_MAP_ALIGNED(bitvec_t**, ss, 8, TAU * sizeof(bitvec_t*)); + TMP_SPACE_MAP_ALIGNED(bitmat_t**, qq, 8, TAU * sizeof(bitmat_t*)); + TMP_SPACE_MAP_ALIGNED(uint32_t*, hidden_nodes_idx, 8, (2 * TAU + topen + 1) * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint32_t*, sibling_nodes_idx, 8, (topen + 1) * sizeof(uint32_t)); + // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) + vole_params->prepare_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); + // the two domain-separated salts: one for the GGM tree, one for the vole rng + uint64_t* const ggm_masked_salt = masked_salts; + uint64_t* const vole_masked_salt = masked_salts + (SEED_BYTES >> 3); + compute_tweaked_salts(vole_params, ggm_masked_salt, vole_masked_salt, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); + for (uint64_t i = 0; i < TAU; ++i) { + qq[i] = ((uint8_t*)q) + i * KAPPA * Lslice; + ss[i] = ((uint8_t*)coor_terms) + i * Lslice; + } + for (uint64_t i = 0; i < TAU; ++i) { // some handy double pointers for xofs + commit_ptrs[i] = commit_buffer + i * COMMIT_BYTES; + } + uint8_t* const subhashes = commit_buffer; // we will share that space since the subhash size is 2lambda + uint8_t** const subhashes_ptrs = commit_ptrs; + + // step 1: compute the sibling node indexes +#ifndef NDEBUG + uint32_t num_leaves = TAU << KAPPA; + for (uint32_t i = 0; i < TAU - 1; ++i) { + CREQUIRE(hidden_leaves_idx[i] < hidden_leaves_idx[i + 1], "leave nodes not ordered"); + } + CREQUIRE(hidden_leaves_idx[0] >= num_leaves, "incorrect leave node index"); + CREQUIRE(hidden_leaves_idx[TAU - 1] < 2 * num_leaves, "incorrect leave node index"); +#endif + // copy the leaf indexes in reversed order + hidden_nodes_idx[0] = -1; // arbitrary large delimiter + for (uint32_t i = 0; i < TAU; ++i) { + hidden_nodes_idx[TAU - i] = hidden_leaves_idx[i]; + } + uint64_t istart = 1; + uint64_t iend = TAU + 1; + uint64_t isibling = 0; + sibling_nodes_idx[isibling++] = -1; // arbitrary large delimiter + while (iend - istart >= 2) { + const uint32_t first_idx = hidden_nodes_idx[istart]; + const uint32_t second_idx = hidden_nodes_idx[istart + 1]; + const uint32_t next_idx = first_idx >> 1; + CASSERT(first_idx > 1, "bug1"); + CASSERT(hidden_nodes_idx[iend - 1] > next_idx, "bug2"); + if ((first_idx ^ second_idx) == 1) { + // two hidden nodes with the same parent: no sibling + istart += 2; + } else { + // single child out of at least 2: one sibling + sibling_nodes_idx[isibling++] = first_idx ^ UINT32_C(1); + istart += 1; + } + hidden_nodes_idx[iend++] = next_idx; + } + for (uint32_t hidden_idx = hidden_nodes_idx[istart]; hidden_idx != 1; hidden_idx >>= 1) { + sibling_nodes_idx[isibling++] = hidden_idx ^ UINT32_C(1); + } + CREQUIRE(isibling == topen + 1, "we should have found all the siblings (+ delim )"); +#ifndef NDEBUG + for (uint32_t i = 0; i < topen; ++i) { + CREQUIRE(sibling_nodes_idx[i] > sibling_nodes_idx[i + 1], "sibling nodes not ordered"); + } +#endif + + // step 2: expand all the seeds (replacing siblings) + CASSERT(topen >= 1, "BUG! invalid parameter"); + uint64_t next_node_idx = 2; // also equal to the num leaves to write at that depth + const uint8_t* rd_ptr = seeds + SEED_BYTES; // root position (node_id = 1) + uint8_t* wr_ptr = seeds + 2 * SEED_BYTES; // left child (node_id=2) + const uint32_t* next_sibling = sibling_nodes_idx + topen; + const uint8_t* next_sibling_seed = ((uint8_t*)sibling_seeds) + (topen - 1) * SEED_BYTES; + + // pretend that the root is zero (we know it is hidden!) + CASSERT(*next_sibling > 1, "the root is necessarily hidden"); + memset(seeds + SEED_BYTES, 0, SEED_BYTES); + + // expand the first two depths of the tree one by one + while (next_node_idx < 8) { + vole_params->extend_leaf_seed(ext_seeds, rd_ptr); + vole_params->ggm_extseed_rng_lr(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 2 * SEED_BYTES; + rd_ptr += SEED_BYTES; + next_node_idx += 2; + // replace the sibling seeds + while (*next_sibling < next_node_idx) { + memcpy(seeds + (*next_sibling) * SEED_BYTES, next_sibling_seed, SEED_BYTES); + next_sibling_seed -= SEED_BYTES; + --next_sibling; + } + } + // expand the rest of the depths 4x by 4x + while (next_node_idx <= TOTAL_NODES) { + vole_params->extend_leaf_seed_4x(ext_seeds, rd_ptr); + // I8: expand the 4 sibling parents (node_idx, +2, +4, +6) in one call. The cat1 avx2 + // build batches them into one 8-block encrypt; the other builds do four single calls. + vole_params->ggm_extseed_rng_lr_x4(wr_ptr, ggm_masked_salt, ext_seeds, next_node_idx, THETA); + wr_ptr += 8 * SEED_BYTES; + rd_ptr += 4 * SEED_BYTES; + next_node_idx += 8; + // replace the sibling seeds + while (*next_sibling < next_node_idx) { + memcpy(seeds + (*next_sibling) * SEED_BYTES, next_sibling_seed, SEED_BYTES); + next_sibling_seed -= SEED_BYTES; + --next_sibling; + } + } + CASSERT(next_sibling == sibling_nodes_idx, "we should have exhausted the siblings"); + CASSERT(next_sibling_seed == sibling_seeds - SEED_BYTES, "we should have exhausted the siblings"); + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have expanded the tree"); + + // step 3: expand all the leaf seeds into commit and vole randomness + memset(q, 0, TAU * KAPPA * Lslice); + vole_params->xof_vector.init_and_seed(commit_xofs, TAU, &HASH_BAVC_PREFIX, 1); + + uint64_t l = 0; + next_node_idx = TOTAL_LEAVES; + const uint8_t* next_leaf_seed = seeds + TOTAL_LEAVES * SEED_BYTES; // ptr of the first leaf seed + const uint8_t* const end_leaf_seed = seeds + (TOTAL_NODES + 1) * SEED_BYTES; + const uint32_t* next_hidden_leaf_idx = hidden_nodes_idx + TAU; + const uint8_t* next_hidden_leaf_commit = hidden_leaves_commit; + CASSERT(*next_hidden_leaf_idx >= TOTAL_LEAVES, "BUG! the first hidden leaf is necessarily a leaf"); + CASSERT(*(next_hidden_leaf_idx + 1) < TOTAL_NODES, "BUG! the 'first' hidden leaf is not the first"); + while (next_leaf_seed < end_leaf_seed) { + // expand 4 * TAU leaf seeds and advance the read pointer + uint8_t* out_ext_seed = ext_seeds; + for (uint64_t i = 0; i < TAU; ++i) { + // expand the leaf seed -> expanded buffer + vole_params->extend_leaf_seed_4x(out_ext_seed, // output + next_leaf_seed // leaf seed + ); + next_leaf_seed += 4 * LAMBDA_BYTES; + out_ext_seed += 4 * EXT_BYTES; + } + CASSERT(out_ext_seed == ext_seeds + 4 * TAU * EXT_BYTES, "out_ext_seed should be at the end of the buffer"); + + // process the 4 * TAU expanded leaves (it corresponds to 4 positions) + const uint8_t* in_expanded_seed = ext_seeds; + for (uint64_t nb = 0; nb < 4; ++nb) { + const uint64_t loc = (l + 1 < nleaves) ? binval_of(l + 1) : KAPPA - 1; + const uint64_t loc_offset = loc * Lslice; + uint8_t* out_commit = commit_buffer; + for (uint64_t i = 0; i < TAU; ++i) { + // compute the commit and add it to the commit buffer + if (next_node_idx == *next_hidden_leaf_idx) { + // copy the commit + memcpy(out_commit, next_hidden_leaf_commit, COMMIT_BYTES); + // and process hidden vole + vole_params->bitvec_xor_to(Lslice, qq[i] + loc_offset, ss[i]); + // advance hidden leaf ptr + --next_hidden_leaf_idx; + next_hidden_leaf_commit += COMMIT_BYTES; + } else { + // otherwise derive it from the seed + vole_params->ggm_extseed_rng_commit(out_commit, // out + ggm_masked_salt, // salt + in_expanded_seed, // expanded_seed + next_node_idx // node_idx + ); + // and process vole with seed + vole_params->vole_extseed_rng(tmp_r, Lslice, // out (only Lbytes would suffice here) + vole_masked_salt, // salt + in_expanded_seed, // expanded_seed + i); // repetition index + vole_params->bitvec_cascade_xor_to(Lslice, qq[i] + loc_offset, ss[i], tmp_r); + } + // advance pointers + in_expanded_seed += EXT_BYTES; + out_commit += COMMIT_BYTES; + next_node_idx += 1; + } + // hash the commits + vole_params->xof_vector.seed(commit_xofs, TAU, commit_ptrs, COMMIT_BYTES); + // advance the pointers + ++l; + } + CASSERT(in_expanded_seed == ext_seeds + 4 * TAU * EXT_BYTES, "we should have consumed all the expanded seeds"); + } + CASSERT(l == nleaves, "we should have processed all the leaves"); + CASSERT(next_leaf_seed == end_leaf_seed, "we should have processed all the leaves"); + CASSERT(next_node_idx == TOTAL_NODES + 1, "we should have processed all the leaves"); + CASSERT(next_hidden_leaf_idx == hidden_nodes_idx, "BUG! we should have consumed all the hidden leaves"); + CASSERT(next_hidden_leaf_commit == hidden_leaves_commit + TAU * COMMIT_BYTES, + "BUG! we should have consumed all the hidden leaves"); + + // now, hash the per-rep subhashes into the final commits hash (same layout as + // the prover's): commits_hash = H(HASH_BAVC_PREFIX, global_salt, subhashes). + vole_params->xof_vector.finalize_and_output(commit_xofs, TAU, subhashes_ptrs, 2 * LAMBDA_BYTES); + vole_params->xof_vector.ctx_release(commit_xofs, TAU); + xof_ctx commits_xof; + vole_params->xof.xof_init_and_seed(&commits_xof, &HASH_BAVC_PREFIX, 1); + vole_params->xof.xof_seed(&commits_xof, global_salt, LAMBDA_BYTES); + vole_params->xof.xof_seed(&commits_xof, subhashes, 2 * TAU * LAMBDA_BYTES); + vole_params->xof.xof_finalize_and_output(&commits_xof, commits_hash, 2 * LAMBDA_BYTES); + vole_params->xof.xof_ctx_release(&commits_xof); + + // postprocess q using delta + const uint64_t* deltap64 = delta1; + for (uint64_t i = 0; i < TAU; ++i) { + uint32_t delta_i = extract_kappabit_uint(KAPPA, i * KAPPA, deltap64); + for (uint64_t j = 0; j < KAPPA; ++j) { + if ((delta_i >> j) & 1) { + vole_params->bitvec_xor_to(Lslice, qq[i] + j * Lslice, ss[i]); + } + } + } + + // release any per-slot state the ext_seed backend cached (no-op unless the + // liboqs aes128 backend is in use) + vole_params->release_extseed_buf(ext_seeds, 4 * TAU, EXT_BYTES); +} + + +enum node_action_t { + NODE_ACTION_NONE = 0, + NODE_ACTION_HIDDEN_RIGHT = 1, + NODE_ACTION_HIDDEN_LEFT = 2, + NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT = 3, + NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT = 4 +}; + +EXPORT void compute_tweaked_salts( // + const vole_parameters* vole_params, // params + uint64_t* ggm_masked_salt, // [out] masked salt for the GGM tree + uint64_t* vole_masked_salt, // [out] masked salt for the vole RNG (if not nullptr) + const salt_t* global_salt // [in] +) { + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t msb_idx = (lambda_bytes >> 3) - 1; + memcpy(ggm_masked_salt, global_salt, lambda_bytes); + // clear the GGM_TWEAK_BITS least significant bits (used for the actual tweak/ctr) + ggm_masked_salt[0] &= (UINT64_C(-1) << GGM_TWEAK_BITS); + if (vole_params->proofow_variant == PROOFOW_VARIANT_CIPHER) { + // cipher PoW uses the 2-bits domain separation prefix "01" + ggm_masked_salt[msb_idx] &= UINT64_C(-1) >> 2; + ggm_masked_salt[msb_idx] |= UINT64_C(1) << 62; + } else { + // shake PoW uses the 1-bit domain separation prefix "1" + ggm_masked_salt[msb_idx] |= UINT64_C(1) << 63; + } + if (vole_masked_salt) { + // same algorithm but different prefixes + memcpy(vole_masked_salt, global_salt, lambda_bytes); + // clear the GGM_TWEAK_BITS least significant bits (used for the actual tweak/ctr) + vole_masked_salt[0] &= (UINT64_C(-1) << GGM_TWEAK_BITS); + if (vole_params->proofow_variant == PROOFOW_VARIANT_CIPHER) { + // cipher PoW uses the 2-bits domain separation prefix "00" + vole_masked_salt[msb_idx] &= UINT64_C(-1) >> 2; + } else { + // shake PoW uses the 1-bit domain separation prefix "0" + vole_masked_salt[msb_idx] &= UINT64_C(-1) >> 1; + } + } +} + +EXPORT uint64_t full_ggm_tree_open_sibling_path_from_root_tmp_bytes( // + const vole_parameters* vole_params, // + const uint64_t sibling_path_size // number of sibling seeds +) { + const uint64_t TAU = vole_params->TAU; + // const uint64_t KAPPA = vole_params->KAPPA; + // const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + // const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t BUF_SIZE_MAX = (2 * TAU - 1) + sibling_path_size; + const uint64_t SEED_BYTES = vole_params->lambda_bytes; + // const uint64_t COMMIT_BYTES = 2 * SEED_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + COMP_SPACE_INIT(); + COMP_SPACE_MAP_ALIGNED(uint64_t*, ggm_masked_salt, 32, SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seed, 32, EXT_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, lr_seeds, 32, 2 * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, 2 * BUF_SIZE_MAX * SEED_BYTES); + COMP_SPACE_MAP_ALIGNED(uint32_t*, node_indexes, 8, BUF_SIZE_MAX * sizeof(uint32_t)); + COMP_SPACE_MAP_ALIGNED(uint8_t*, node_actions, 8, BUF_SIZE_MAX * sizeof(uint8_t)); + COMP_SPACE_RETURN(); +} + +EXPORT void full_ggm_tree_open_sibling_path_from_root( // + const vole_parameters* vole_params, // + seed_t* sibling_seeds, // sibling seeds (in decreasing node index order) + commit_t* hidden_leaves_commits, // hidden leaves commits (in increasing leaf order) + const seed_t* root_seed, // the ggm root seed + const salt_t* global_salt, // the global salt + const uint32_t* hidden_leaves_idx, // index of hidden leaves (node index) + const uint64_t sibling_path_size, // number of sibling seeds + uint8_t* tmp_space) { + const uint64_t TAU = vole_params->TAU; + const uint64_t KAPPA = vole_params->KAPPA; + const uint64_t TREE_DEPTH = ceil_log2i(TAU) + KAPPA; + const uint64_t THETA = TREE_DEPTH + 2; // theta = ceil(log2(tau*2^kappa)) + 2 + const uint64_t BUF_SIZE_MAX = (2 * TAU - 1) + sibling_path_size; + const uint64_t SEED_BYTES = vole_params->lambda_bytes; + const uint64_t COMMIT_BYTES = 2 * SEED_BYTES; + const uint64_t EXT_BYTES = vole_params->extended_node_seed_bytes(); + + TMP_SPACE_MAP_ALIGNED(uint64_t*, ggm_masked_salt, 32, SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, ext_seed, 32, EXT_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, lr_seeds, 32, 2 * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint8_t*, seeds, 32, 2 * BUF_SIZE_MAX * SEED_BYTES); + TMP_SPACE_MAP_ALIGNED(uint32_t*, node_indexes, 8, BUF_SIZE_MAX * sizeof(uint32_t)); + TMP_SPACE_MAP_ALIGNED(uint8_t*, node_actions, 8, BUF_SIZE_MAX * sizeof(uint8_t)); + // prepeare the buffer to be used for extended seeds (no-op unless the liboqs aes128 backend is in use) + vole_params->prepare_extseed_buf(ext_seed, 1, EXT_BYTES); + // only the GGM salt is needed here: this path does not draw any vole randomness + compute_tweaked_salts(vole_params, ggm_masked_salt, NULL, global_salt); + CASSERT(THETA <= GGM_TWEAK_BITS, "bug! the tree is too deep for the salt tweak field"); +#ifndef NDEBUG + const uint64_t TOTAL_LEAVES = (TAU << KAPPA); + for (uint64_t i = 0; i < TAU - 1; ++i) { + CREQUIRE(hidden_leaves_idx[i] < hidden_leaves_idx[i + 1], "incorrect leave order"); + } + CREQUIRE(hidden_leaves_idx[0] >= TOTAL_LEAVES, "incorrect leave node index"); + CREQUIRE(hidden_leaves_idx[TAU - 1] < 2 * TOTAL_LEAVES, "incorrect leave node index"); +#endif + // copy the leaf indexes in reversed order + uint32_t istart = 0; + uint32_t iend = TAU; + for (uint32_t i = 0; i < TAU; ++i) { + node_indexes[TAU - i - 1] = hidden_leaves_idx[i]; + } + uint32_t first_idx; + while (iend - istart >= 2) { + first_idx = node_indexes[istart]; // *(bstart++); + const uint32_t second_idx = node_indexes[istart + 1]; + const uint32_t next_idx = first_idx >> 1; + CASSERT(first_idx > 1, "bug1"); + CASSERT(node_indexes[iend - 1] > next_idx, "bug2"); + if ((first_idx ^ second_idx) == 1) { + // two hidden nodes with the same parent + node_actions[istart] = NODE_ACTION_HIDDEN_RIGHT; + node_actions[istart + 1] = NODE_ACTION_HIDDEN_LEFT; + istart += 2; + } else { + // single child out of at least 2 + if (first_idx & 1) { + node_actions[istart] = NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT; + } else { + node_actions[istart] = NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT; + } + istart += 1; + } + node_indexes[iend++] = next_idx; + } + while ((first_idx = node_indexes[istart]) != 1) { + if (first_idx & 1) { + node_actions[istart] = NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT; + } else { + node_actions[istart] = NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT; + } + istart += 1; + node_indexes[iend++] = first_idx >> 1; + } +#ifndef NDEBUG + CREQUIRE(iend == BUF_SIZE_MAX, "we should have processed all the nodes"); + for (uint64_t i = 0; i < BUF_SIZE_MAX - 1; i++) { + CREQUIRE(node_indexes[i] > node_indexes[i + 1], "incorrect node index"); + } + CREQUIRE(node_indexes[BUF_SIZE_MAX - 1] == 1, "the last node should be the root"); +#endif + // second pass in decreasing order: fill-in the seeds + int64_t dend = BUF_SIZE_MAX - 1; + int64_t spath_idx = sibling_path_size - 1; + memcpy(seeds + dend * SEED_BYTES, root_seed, SEED_BYTES); + for (int64_t dstart = BUF_SIZE_MAX - 2; dstart >= 0; --dstart) { + switch (node_actions[dstart]) { + case NODE_ACTION_HIDDEN_LEFT: { + CASSERT(dstart > 0 && node_actions[dstart - 1] == NODE_ACTION_HIDDEN_RIGHT, "incorrect node action"); + // and continue + } + case NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT: + case NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT: { + // expand the seed and store left + CASSERT(dend >= TAU, "incorrect node action"); + vole_params->extend_leaf_seed(ext_seed, seeds + dend * SEED_BYTES); + vole_params->ggm_extseed_rng_lr(lr_seeds, ggm_masked_salt, ext_seed, node_indexes[dstart] & UINT32_C(-2), THETA); + --dend; + break; + } + case NODE_ACTION_HIDDEN_RIGHT: + break; + default: + abort(); // unknown case + } + switch (node_actions[dstart]) { + case NODE_ACTION_HIDDEN_LEFT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds, SEED_BYTES); + break; + } + case NODE_ACTION_HIDDEN_RIGHT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds + SEED_BYTES, SEED_BYTES); + break; + } + case NODE_ACTION_HIDDEN_LEFT_SIBLING_RIGHT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds, SEED_BYTES); + memcpy(sibling_seeds + spath_idx * SEED_BYTES, lr_seeds + SEED_BYTES, SEED_BYTES); + --spath_idx; + break; + } + case NODE_ACTION_HIDDEN_RIGHT_SIBLING_LEFT: { + memcpy(seeds + dstart * SEED_BYTES, lr_seeds + SEED_BYTES, SEED_BYTES); + memcpy(sibling_seeds + spath_idx * SEED_BYTES, lr_seeds, SEED_BYTES); + --spath_idx; + break; + } + default: + abort(); // unknown case + } + } + CASSERT(spath_idx == -1, "we should have processed all the sibling seeds"); + CASSERT(dend == TAU - 1, "we should have processed all the nodes"); + // final pass: compute the hidden leaves commits + for (uint64_t i = 0; i < TAU; ++i) { + vole_params->extend_leaf_seed(ext_seed, seeds + (TAU - i - 1) * SEED_BYTES); + vole_params->ggm_extseed_rng_commit(hidden_leaves_commits + i * COMMIT_BYTES, ggm_masked_salt, ext_seed, + node_indexes[TAU - i - 1]); + } + + // release any per-slot state the ext_seed backend cached (no-op unless the + // liboqs aes128 backend is in use) + vole_params->release_extseed_buf(ext_seed, 1, EXT_BYTES); +} + +EXPORT void prover_midsize_to_fullsize_std_vole_ct_ref(const vole_parameters* vole_params, uint64_t L, bitvec_t* out_u, + bitmat_t* out_corr, flambda_t* out_v, const bitmat_t* in_u, + const bitmat_t* in_v) { + // in_v points to a lambda x L_byte region, and the last lambda - tau.kappa rows are set to zero + + const uint64_t Lbytesx = (L + 7) / 8; + const uint64_t Lslice = (Lbytesx + 31) & UINT64_C(-32); + + // out_v = transpose(in_v) + (*vole_params->matrix_lambda_transpose)(out_v, in_v, L, Lslice); + + // out_u = first L bits of in_u + memcpy(out_u, in_u, Lbytesx); + + // out_corr = in_u[i+1] ^ in_u[0] + // attention: out_corr has an LByte slice, whereas in_u has a Lslice slice + for (uint64_t i = 0; i < vole_params->TAU - 1; i++) { + vole_params->bitvec_xor(Lslice, out_corr + i * Lslice, in_u + (i + 1) * Lslice, in_u); + } +} + +EXPORT void verifier_midsize_to_fullsize_std_vole_ref(const vole_parameters* vole_params, uint64_t L, flambda_t* out_q, + const bitmat_t* in_q) { + const uint64_t Lbytes = (L + 7) / 8; + const uint64_t Lslice = (Lbytes + 31) & UINT64_C(-32); + // out_q = transpose(in_q) + (*vole_params->matrix_lambda_transpose)(out_q, in_q, L, Lslice); +} + +EXPORT uint64_t vole_consistency_check_matrix_nrows( // + const vole_parameters* vole_params) // dimensions // number of pairs to treat +{ + // num_cchk_pairs = LAMBDA + B, B = 16 (Thibauld Feneuil / FAEST spec): the consistency-check matrix + // size for the claimed soundness level (LAMBDA+16 is already a multiple of 8). Value-identical to the + // old ceil8(KAPPA*TAU+16) for every shipped set, but the authoritative form -- KAPPA*TAU only + // coincided with LAMBDA and would UNDER-size the check for faster params where KAPPA*TAU < LAMBDA. + return vole_params->LAMBDA + 16; +} + +EXPORT uint64_t vole_consistency_check_matrix_ncols( // + const vole_parameters* vole_params, // dimensions + uint64_t L) { + return L - vole_consistency_check_matrix_nrows(vole_params); +} + +EXPORT void both_vole_consistency_check_matrix( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitmat_t* chk_matrix, // [out] cst_check_dim x (L - cst_check_dim) + const hash_t* chk_seed1, uint64_t chk_seed1_bytes) // [in] rng seed and tweak +{ + const uint64_t cchk_nrows = vole_consistency_check_matrix_nrows(vole_params); + const uint64_t cchk_ncols = vole_consistency_check_matrix_ncols(vole_params, L); + const uint64_t cchk_col_bytes = (cchk_ncols + 7) >> 3; + xof_ctx cchk_matrix_rng; + vole_params->xof.xof_init_and_seed(&cchk_matrix_rng, chk_seed1, chk_seed1_bytes); + vole_params->xof.xof_finalize_and_output(&cchk_matrix_rng, chk_matrix, cchk_nrows * cchk_col_bytes); + vole_params->xof.xof_ctx_release(&cchk_matrix_rng); + // mask last columns with zeroes if needed + uint8_t cchk_last_mask = 0xFF >> ((-cchk_ncols) & 7); + uint8_t* const cm = (uint8_t*)chk_matrix; + for (uint64_t i = 0; i < cchk_nrows; i++) { + cm[i * cchk_col_bytes + cchk_col_bytes - 1] &= cchk_last_mask; + } +} + +EXPORT void prover_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitvec_t* chk_u, // [out] cst check of size KAPPA.TAU+B + flambda_t* chk_v, // [out] chk_v + const bitvec_t* u, // [in] vector of length L + const flambda_t* v, // [in] vector of length L + const bitvec_t* chk_matrix) // [in] cst check matrix +{ + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t cchk_nrows = vole_consistency_check_matrix_nrows(vole_params); + const uint64_t cchk_ncols = vole_consistency_check_matrix_ncols(vole_params, L); + const uint64_t cchk_nrows_bytes = cchk_nrows >> 3; + const uint8_t* const uu = (const uint8_t*)u; + const uint8_t* const vv = (const uint8_t*)v; + vole_params->matrix_vector_product_f2(cchk_nrows, cchk_ncols, chk_u, chk_matrix, uu + cchk_nrows_bytes); + vole_params->bitvec_xor_to(cchk_nrows_bytes, chk_u, uu); + vole_params->matrix_f2_times_vector_flambda(lambda, cchk_nrows, cchk_ncols, chk_v, chk_matrix, + vv + cchk_nrows * lambda_bytes); + vole_params->bitvec_xor_to(cchk_nrows * lambda_bytes, chk_v, vv); +} + +EXPORT void verifier_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + flambda_t* chk_v, // [out] chk_v + const bitvec_t* chk_u, // [in] cst check of size KAPPA.TAU+B + const flambda_t* q, // [in] vector of length L + const bitvec_t* chk_matrix, // [in] cst check matrix (L-cst_check_dim) x L + const bitvec_t* delta1) // [in] delta1 (kappa.tau bits) +{ + const uint64_t lambda = vole_params->LAMBDA; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t cchk_nrows = vole_consistency_check_matrix_nrows(vole_params); + const uint64_t cchk_ncols = vole_consistency_check_matrix_ncols(vole_params, L); + const uint8_t* const qq = (const uint8_t*)q; + vole_params->matrix_f2_times_vector_flambda(lambda, cchk_nrows, cchk_ncols, chk_v, chk_matrix, + qq + cchk_nrows * lambda_bytes); + vole_params->bitvec_xor_to(cchk_nrows * lambda_bytes, chk_v, qq); + const uint8_t* const cu = (uint8_t*)chk_u; + uint8_t* const cv = (uint8_t*)chk_v; + for (uint64_t i = 0; i < cchk_nrows; ++i) { + if ((cu[i >> 3] >> (i & 7)) & 1) { + vole_params->flambda_sum(cv + i * lambda_bytes, cv + i * lambda_bytes, delta1); + } + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_generation.h b/src/sig/sdith/sdith_sdith_common_avx2/vole_generation.h new file mode 100644 index 0000000000..951ee7256d --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_generation.h @@ -0,0 +1,168 @@ +#ifndef VOLE_GENERATION_H +#define VOLE_GENERATION_H + +/// This header declares the functions needed to generate vole pairs securely + +#include "vole_parameters.h" + +/** @brief converts delta0 to delta1 + * delta0 has kappa*tau bits, encoding tau grey code encodings + * delta1 has lambda bits, only the lowest kappa*tau are used, the rest is zero. + */ +EXPORT void delta1_from_delta0_ref(const vole_parameters* vole_params, flambda_t* delta1, const bitvec_t* delta0); + +/** @brief converts delta1 to delta2 + * delta2 is the field inverse of delta1 + */ +EXPORT void delta2_from_delta1_ref(const vole_parameters* vole_params, flambda_t* delta2, const flambda_t* delta1); + +EXPORT uint64_t prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L // number of pairs to generate [Lslice next mult of 32] +); + +/** + * Compute the tweaked base salts that are used in GGM seed-expand, seed-commit, and vole-rng + */ +EXPORT void compute_tweaked_salts( // + const vole_parameters* vole_params, // params + uint64_t* ggm_masked_salt, // [out] masked salt for the GGM tree + uint64_t* vole_masked_salt, // [out] masked salt for the vole RNG (if not nullptr) + const salt_t* global_salt // [in] +); + +/** + * tmp space needed to open the sibling path that corresponds to the provided hidden leaves indexes + */ +EXPORT uint64_t full_ggm_tree_open_sibling_path_from_root_tmp_bytes( // + const vole_parameters* vole_params, // + const uint64_t sibling_path_size // number of sibling seeds + ); + +/** + * Opens the sibling path that corresponds to the provided hidden leaves indexes + */ +EXPORT void full_ggm_tree_open_sibling_path_from_root( // + const vole_parameters* vole_params, // + seed_t* sibling_seeds, // sibling seeds (in decreasing node index order) + commit_t* hidden_leaves_commits, // hidden leaves commits (in increasing leaf order) + const seed_t* root_seed, // the ggm root seed + const salt_t* global_salt, // the global salt + const uint32_t* hidden_leaves_idx, // index of hidden leaves (node index) + const uint64_t sibling_path_size, // number of sibling seeds + uint8_t* tmp_space); + +/** + * Generate L vole pairs over (F2,F2^KAPPA) (grey code + BFS version) + * @param commits_hash (output): 2.lambda bytes: + * H(HASH_BAVC_PREFIX, global_salt, per-rep subhashes) + * @param u (output): L bits: Xor of all ri's, + * @param v (output): matrix KAPPA x L bits: Xor of ri.grey(i) + */ +EXPORT void prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate [Lslice next mult of 32] + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* u, // [out] TAU x (L bits on Lslice bytes) + bitmat_t* v, // [out] TAU x KAPPA x (L bits on Lslice bytes) row major + const salt_t* ggm_salt, // [in] global salt for the GGM tree + const seed_t* ggm_root_seed, // [in] root seed for the GGM tree + uint8_t* tmp_space); // [tmp] scratch space + + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) -- tmp bytes needed + */ +EXPORT uint64_t verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + uint64_t topen // (max) size of the sibling path +); + + +/** + * Open L vole pairs over (F2,F2^KAPPA) (grey code version) + * @param commits_hash (output): 2.lambda bytes, same layout as the prover's: + * H(HASH_BAVC_PREFIX, global_salt, per-rep subhashes) + */ +EXPORT void verifier_open_midsize_grey_vole_from_seeds_bfs_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to generate + hash_t* commits_hash, // [out] hash of the leaves commits (2.lambda bytes) + bitmat_t* q, // [out] TAU x KAPPA x L row major + bitmat_t* coor_terms, // [in/out] TAU x L bits + const uint32_t* hidden_leaves_idx, // [in] TAU indices of the hidden (node) leaves + const commit_t* hidden_leaves_commit, // [in] TAU commits of the hidden (node) leaves + const seed_t* sibling_seeds, // [in] Topen sibling seeds + const uint64_t topen, // [in] number of sibling seeds + const salt_t* ggm_salt, // [in] global salt for the GGM tree + const flambda_t* delta1, // verifier's point delta1 + uint8_t* tmp_space); + + +/** + * Concatenate and transpose L mid-size std vole pairs over (F2,F2^KAPPA) + * To form L full-size std vole pairs over (F2,F2^LAMBDA) + * // acceptable in_place mode: + * // either + * // out_u == in_u and out_corr == in_u[1] + * // otherwise, out_u, out_corr, in_u shall be completely disjoint + * // also: either + * // out_v == in_v + * // or otherwise, out_v, in_v must be completely disjoint + */ +EXPORT void prover_midsize_to_fullsize_std_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitvec_t* out_u, // [out] L bits + bitmat_t* out_corr, // [out] (TAU-1 x L) row major + flambda_t* out_v, // [out] gflambda[L] contiguous + const bitmat_t* in_u, // [in] TAU x L row major + const bitmat_t* in_v); // [in] (TAU*KAPPA) x L row major + +/** + * Concatenate and transpose L mid-size std vole pairs over (F2,F2^KAPPA) + * To form L full-size std vole pairs over (F2,F2^LAMBDA) + * // acceptable in_place mode: + * // also: either + * // out_q == in_a + * // or otherwise, out_q, in_q must be completely disjoint + */ +EXPORT void verifier_midsize_to_fullsize_std_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + flambda_t* out_q, // [out] gflambda[L] + const bitmat_t* in_q); // [in] TAU*KAPPA x L row major + +EXPORT uint64_t vole_consistency_check_matrix_nrows( // + const vole_parameters* vole_params); // dimensions + +EXPORT uint64_t vole_consistency_check_matrix_ncols( // + const vole_parameters* vole_params, // dimensions + uint64_t L); // number of pairs to treat + +EXPORT void both_vole_consistency_check_matrix( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitmat_t* chk_matrix, // [out] cst_check_dim x (L - cst_check_dim) + const hash_t* chk_seed1, uint64_t chk_seed1_bytes); // [in] rng seed and tweak + +EXPORT void prover_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + bitvec_t* chk_u, // [out] cst check of size KAPPA.TAU+B + flambda_t* chk_v, // [out] chk_v + const bitvec_t* u, // [in] vector of length L + const flambda_t* v, // [in] vector of length L + const bitvec_t* chk_matrix); // [in] cst check matrix + +EXPORT void verifier_vole_consistency_check( // + const vole_parameters* vole_params, // dimensions + uint64_t L, // number of pairs to treat + flambda_t* chk_v, // [out] chk_v + const bitvec_t* chk_u, // [in] cst check of size KAPPA.TAU+B + const flambda_t* q, // [in] vector of length L + const bitvec_t* chk_matrix, // [in] cst check matrix (L-cst_check_dim) x L + const bitvec_t* delta1); // [in] delta1 (kappa.tau bits) + +#endif // VOLE_GENERATION_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters.c b/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters.c new file mode 100644 index 0000000000..f1c6fb5795 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters.c @@ -0,0 +1,182 @@ +#include "vole_private.h" + +void vole_parameters_init_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa) { + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, PROOFOW_VARIANT_SHAKE); +} + +EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant) { + CASSERT(lambda > 0 && lambda >= tau * kappa, "bug? lambda is not larger than tau*kappa (check parameter order)"); + vole_params->proofow_variant = proofow_variant; + vole_params->KAPPA = kappa; + vole_params->TAU = tau; + vole_params->LAMBDA = lambda; + vole_params->lambda_bytes = (lambda + 7) >> 3; + vole_params->bitvec_xor = bitvec_xor_ref; + vole_params->bitvec_xor_to = bitvec_xor_to_ref; + vole_params->bitvec_cascade_xor_to = bitvec_cascade_xor_to_ref; + vole_params->matrix_f2_times_vector_flambda = matrix_f2_times_vector_flambda_ref; + vole_params->matrix_vector_product_f2 = matrix_vector_product_f2_ref; + vole_params->ct = ct_utils_ref; + switch (lambda) { + case 128: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat1; + vole_params->proofow_init = proofow_init_shake_cat1; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat1; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat1; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat1; + vole_params->proofow_init = proofow_init_cipher_cat1_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat1_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat1_ref; + vole_params->proofow_release = proofow_release_cipher_cat1_ref; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat1_aes128_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat1_aes128_4x_ref; + vole_params->prepare_extseed_buf = prepare_extseed_buf_cat1_aes128_ref; + vole_params->release_extseed_buf = release_extseed_buf_cat1_aes128_ref; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat1_aes128; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat1_aes128_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat1_aes128_x4_ref; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat1_aes128_ref; + vole_params->vole_extseed_rng = vole_rng_ext_cat1_aes128_ctrle_ref; + vole_params->xof = xof_shake128; + vole_params->xof_vector = xof_vector_shake128; + vole_params->matrix_prg = matrix_rng_cat1_aes128_ref; + vole_params->keygen_rng = keygen_rng_cat1_aes128_ref; + // arithmetic + vole_params->flambda_set = gf128_flambda_set_ref; + vole_params->flambda_inverse = gf128_flambda_inverse_ref; + vole_params->flambda_sum_pow2 = gf128_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf128_flambda_sum_ref; + vole_params->flambda_product = gf128_flambda_product_ref; + vole_params->flambda_product_f2 = gf128_flambda_product_f2_ref; + vole_params->flambda_dot_product = gf128_flambda_dot_product_ref; + vole_params->flambda_dot_product_acc = gf128_flambda_dot_product_acc_ref; + vole_params->flambda_dot_product_f2_acc = gf128_flambda_dot_product_f2_acc_ref; + vole_params->flambda_echelon_pow2 = gf128_flambda_echelon_pow2_ref; + vole_params->matrix_lambda_transpose = transpose_128_L_ref; + break; + case 192: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat3; + vole_params->proofow_init = proofow_init_shake_cat3; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat3; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat3; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat3; + vole_params->proofow_init = proofow_init_cipher_cat3_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat3_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat3_ref; + vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat3_rijndael256_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat3_rijndael256_4x_ref; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat3_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat3_rijndael256_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat3_rijndael256_ref; + vole_params->vole_extseed_rng = vole_rng_ext_cat3_rijndael256_ctrle_ref; + vole_params->xof = xof_shake256; + vole_params->xof_vector = xof_vector_shake256; + vole_params->matrix_prg = matrix_rng_cat3_rijndael256_ref; + vole_params->keygen_rng = keygen_rng_cat3_rijndael256_ref; + // arithmetic + vole_params->flambda_set = gf192_flambda_set_ref; + vole_params->flambda_inverse = gf192_flambda_inverse_ref; + vole_params->flambda_sum_pow2 = gf192_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf192_flambda_sum_ref; + vole_params->flambda_product = gf192_flambda_product_ref; + vole_params->flambda_product_f2 = gf192_flambda_product_f2_ref; + vole_params->flambda_dot_product = gf192_flambda_dot_product_ref; + vole_params->flambda_dot_product_acc = gf192_flambda_dot_product_acc_ref; + vole_params->flambda_dot_product_f2_acc = gf192_flambda_dot_product_f2_acc_ref; + vole_params->flambda_echelon_pow2 = gf192_flambda_echelon_pow2_ref; + vole_params->matrix_lambda_transpose = transpose_192_L_ref; + break; + case 256: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat5; + vole_params->proofow_init = proofow_init_shake_cat5; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat5; + vole_params->proofow_verify_w = proofow_verify_w_shake_cat5; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat5; + vole_params->proofow_init = proofow_init_cipher_cat5_ref; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat5_ref; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat5_ref; + vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat5_rijndael256_ref; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat5_rijndael256_4x_ref; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat5_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat5_rijndael256_ref; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat5_rijndael256_ref; + vole_params->vole_extseed_rng = vole_rng_ext_cat5_rijndael256_ctrle_ref; + vole_params->xof = xof_shake256; + vole_params->xof_vector = xof_vector_shake256; + vole_params->matrix_prg = matrix_rng_cat5_rijndael256_ref; + vole_params->keygen_rng = keygen_rng_cat5_rijndael256_ref; + // arithmetic + vole_params->flambda_set = gf256_flambda_set_ref; + vole_params->flambda_inverse = gf256_flambda_inverse_ref; + vole_params->flambda_sum_pow2 = gf256_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf256_flambda_sum_ref; + vole_params->flambda_product = gf256_flambda_product_ref; + vole_params->flambda_product_f2 = gf256_flambda_product_f2_ref; + vole_params->flambda_dot_product = gf256_flambda_dot_product_ref; + vole_params->flambda_dot_product_acc = gf256_flambda_dot_product_acc_ref; + vole_params->flambda_dot_product_f2_acc = gf256_flambda_dot_product_f2_acc_ref; + vole_params->flambda_echelon_pow2 = gf256_flambda_echelon_pow2_ref; + vole_params->matrix_lambda_transpose = transpose_256_L_ref; + break; + default: + CREQUIRE(0, "lambda not supported"); + } +} + +void vole_parameters_init(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa) { + vole_parameters_init_with_variant(vole_params, lambda, tau, kappa, PROOFOW_VARIANT_SHAKE); +} + +EXPORT void vole_parameters_init_with_variant(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant) { +#ifndef ONLY_REF_IMPLEMENTATION +#ifdef __x86_64__ + if (CPU_SUPPORTS("avx2") && CPU_SUPPORTS("aes") && CPU_SUPPORTS("pclmul") && CPU_SUPPORTS("sse")) { + vole_parameters_init_with_variant_avx(vole_params, lambda, tau, kappa, proofow_variant); + } else { + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, proofow_variant); + } +#else + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, proofow_variant); +#endif +#else + vole_parameters_init_with_variant_ref(vole_params, lambda, tau, kappa, proofow_variant); +#endif +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters.h b/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters.h new file mode 100644 index 0000000000..6fa831b4ba --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters.h @@ -0,0 +1,97 @@ +#ifndef VOLE_PARAMETERS_H +#define VOLE_PARAMETERS_H + +#include "sdith_ct_utils.h" +#include "sdith_prng.h" + +typedef void BITVEC_XOR_TO_F(uint64_t bytelen, bitvec_t* res, const bitvec_t* b); +typedef void BITVEC_XOR_F(uint64_t bytelen, bitvec_t* res, const bitvec_t* a, const bitvec_t* b); +typedef void BITVEC_CASCADE_XOR_TO_F(uint64_t bytelen, bitvec_t* c, bitvec_t* b, const bitvec_t* a); +typedef void FLAMBDA_PRODUCT_F(flambda_t* res, const flambda_t* a, const flambda_t* b); +typedef void FLAMBDA_PRODUCT_F2_F(flambda_t* res, const flambda_t* a, const flambda_t* b_f2); +typedef void FLAMBDA_DOT_PRODUCT_F(flambda_t* res, const flambda_t* x, const flambda_t* y, uint64_t size); +// res += sum_i x[i . x_byte_slice] . y[i]: x is strided (byte stride, multiple of lambda_bytes), y is contiguous +typedef void FLAMBDA_DOT_PRODUCT_ACC_F(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, const flambda_t* y, + uint64_t size); +// same, with every y_f2[i] restricted to 0 or 1 (the products are plain bit-masks) +typedef void FLAMBDA_DOT_PRODUCT_F2_ACC_F(flambda_t* res, const flambda_t* x, uint64_t x_byte_slice, + const flambda_t* y_f2, uint64_t size); +typedef void FLAMBDA_SUM_F(flambda_t* res, const flambda_t* a, const flambda_t* b); +typedef void FLAMBDA_SUM_POW2_F(flambda_t* res, const flambda_t* a); +typedef void FLAMBDA_ECHELON_POW2_F(uint64_t k, flambda_t* res, const flambda_t* a, uint64_t a_size, + uint64_t a_byte_slice); +typedef void FLAMBDA_SET_F(flambda_t* res, const flambda_t* a); +typedef void FLAMBDA_INVERSE_F(flambda_t* res, const flambda_t* a); +typedef void MATRIX_LAMBDA_TRANSPOSE_F(bitmat_t* out, const bitmat_t* in, uint64_t L, uint64_t Lslice); +typedef void MATRIX_VECTOR_PRODUCT_F2( // + uint64_t nrows, uint64_t ncols, // dimensions + bitvec_t* res, // bit vector of size nrows. res=a*b + const bitmat_t* a, // nrows x ncols matrix + const bitvec_t* b); // bit vector of size ncols +typedef void MATRIX_F2_TIMES_VECTOR_FLAMBDA( // + uint64_t lambda, uint64_t nrows, uint64_t ncols, // + flambda_t* res, // vector of size nrows. res = a*b + const bitmat_t* a, // nrows x ncols matrix + const flambda_t* b); + +typedef struct vole_parameters_t vole_parameters; +struct vole_parameters_t { + uint64_t TAU; + uint64_t KAPPA; + uint64_t LAMBDA; + uint64_t lambda_bytes; + // ptr to the prng function? + BITVEC_XOR_TO_F* bitvec_xor_to; + BITVEC_XOR_F* bitvec_xor; + BITVEC_CASCADE_XOR_TO_F* bitvec_cascade_xor_to; + FLAMBDA_SET_F* flambda_set; + FLAMBDA_INVERSE_F* flambda_inverse; + FLAMBDA_PRODUCT_F* flambda_product; + FLAMBDA_PRODUCT_F* flambda_product_f2; + FLAMBDA_DOT_PRODUCT_F* flambda_dot_product; + FLAMBDA_DOT_PRODUCT_ACC_F* flambda_dot_product_acc; + FLAMBDA_DOT_PRODUCT_F2_ACC_F* flambda_dot_product_f2_acc; + FLAMBDA_SUM_F* flambda_sum; + FLAMBDA_SUM_POW2_F* flambda_sum_pow2; + FLAMBDA_ECHELON_POW2_F* flambda_echelon_pow2; + MATRIX_LAMBDA_TRANSPOSE_F* matrix_lambda_transpose; + MATRIX_VECTOR_PRODUCT_F2* matrix_vector_product_f2; + MATRIX_F2_TIMES_VECTOR_FLAMBDA* matrix_f2_times_vector_flambda; + // rng functions + BYTES_OF_PROOFOW_CTX_F* bytes_of_proofow_ctx; + PROOFOW_INIT_F* proofow_init; + PROOFOW_GRIND_W_F* proofow_grind_w; + PROOFOW_VERIFY_W_F* proofow_verify_w; + PROOFOW_RELEASE_F* proofow_release; + EXTEND_LEAF_SEED_F* extend_leaf_seed; + EXTEND_LEAF_SEED_4X_F* extend_leaf_seed_4x; + EXTSEED_BUF_F* prepare_extseed_buf; + EXTSEED_BUF_F* release_extseed_buf; + EXTENDED_NODE_SEED_BYTES_F* extended_node_seed_bytes; + GGM_EXTSEED_RNG_LR_F* ggm_extseed_rng_lr; + GGM_EXTSEED_RNG_LR_X4_F* ggm_extseed_rng_lr_x4; // I8: batched 4-node variant; NULL => four ggm_extseed_rng_lr calls + GGM_EXTSEED_RNG_COMMIT_F* ggm_extseed_rng_commit; + VOLE_EXTSEED_RNG_F* vole_extseed_rng; + xof_functions xof; + xof_vector_functions xof_vector; + matrix_rng_functions matrix_prg; // row-wise prng for public-key (H) expansion + keygen_rng_functions keygen_rng; // secret-key seed prng (solution sampling) + ct_utils ct; // constant-time helpers (prover/keygen side only) + // variants + proofow_variant_t proofow_variant; +}; + +EXPORT void vole_parameters_init_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa); + +EXPORT void vole_parameters_init_avx(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa); + +EXPORT void vole_parameters_init(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa); + +EXPORT void vole_parameters_init_with_variant(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant); + +EXPORT void vole_parameters_init_with_variant_ref(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant); + +EXPORT void vole_parameters_init_with_variant_avx(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant); + + +#endif // VOLE_PARAMETERS_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters_avx2.c b/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters_avx2.c new file mode 100644 index 0000000000..dcdbeeebeb --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_parameters_avx2.c @@ -0,0 +1,162 @@ +#include "vole_private.h" + +void vole_parameters_init_avx(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa) { + vole_parameters_init_with_variant_avx(vole_params, lambda, tau, kappa, PROOFOW_VARIANT_SHAKE); +} + +EXPORT void vole_parameters_init_with_variant_avx(vole_parameters* vole_params, uint64_t lambda, uint64_t tau, uint64_t kappa, proofow_variant_t proofow_variant) { + CASSERT(lambda > 0 && lambda >= tau * kappa, "bug? lambda is not larger than tau*kappa (check parameter order)"); + vole_params->proofow_variant = proofow_variant; + vole_params->KAPPA = kappa; + vole_params->TAU = tau; + vole_params->LAMBDA = lambda; + vole_params->lambda_bytes = (lambda + 7) >> 3; + vole_params->bitvec_xor = bitvec_xor_avx2; + vole_params->bitvec_xor_to = bitvec_xor_to_avx2; + vole_params->bitvec_cascade_xor_to = bitvec_cascade_xor_to_avx2; + vole_params->matrix_f2_times_vector_flambda = matrix_f2_times_vector_flambda_avx2; + vole_params->matrix_vector_product_f2 = matrix_vector_product_f2_avx2; + vole_params->ct = ct_utils_avx; + switch (lambda) { + case 128: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat1; + vole_params->proofow_init = proofow_init_shake_cat1; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat1_4way; // AVX2 4-way KeccakP-1600-times4 + vole_params->proofow_verify_w = proofow_verify_w_shake_cat1; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat1; + vole_params->proofow_init = proofow_init_cipher_cat1_avx; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat1_avx; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat1_avx; + vole_params->proofow_release = proofow_release_noop; + break; + default: + abort(); // unknown variant + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat1_aes128_avx2; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat1_aes128_4x_avx2; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat1_aes128; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat1_aes128_avx2; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2; // I8 + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat1_aes128_avx2; + vole_params->vole_extseed_rng = vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2; + vole_params->xof = xof_shake128; + vole_params->xof_vector = xof_vector_shake128; + vole_params->matrix_prg = matrix_rng_cat1_aes128_avx; + vole_params->keygen_rng = keygen_rng_cat1_aes128_avx; + // arithmetic + vole_params->flambda_set = gf128_flambda_set_ref; + vole_params->flambda_inverse = gf128_flambda_inverse_pclmul; + vole_params->flambda_sum_pow2 = gf128_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf128_flambda_sum_avx2; + vole_params->flambda_product = gf128_flambda_product_pclmul; + vole_params->flambda_product_f2 = gf128_flambda_product_pclmul_f2; + vole_params->flambda_dot_product = gf128_flambda_dot_product_pclmul; + vole_params->flambda_dot_product_acc = gf128_flambda_dot_product_acc_pclmul; + vole_params->flambda_dot_product_f2_acc = gf128_flambda_dot_product_f2_acc_avx2; + vole_params->flambda_echelon_pow2 = gf128_flambda_echelon_pow2_avx; + vole_params->matrix_lambda_transpose = transpose_128_L_ref; + break; + case 192: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat3; + vole_params->proofow_init = proofow_init_shake_cat3; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat3_4way; // AVX2 4-way KeccakP-1600-times4 + vole_params->proofow_verify_w = proofow_verify_w_shake_cat3; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat3; + vole_params->proofow_init = proofow_init_cipher_cat3_avx; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat3_avx; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat3_avx; + vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat3_rijndael256_avx2; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat3_rijndael256_4x_avx2; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat3_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat3_rijndael256_avx2; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat3_rijndael256_avx2; + vole_params->vole_extseed_rng = vole_rng_ext_cat3_rijndael256_ctrle_avx2; + vole_params->xof = xof_shake256; + vole_params->xof_vector = xof_vector_shake256; + vole_params->matrix_prg = matrix_rng_cat3_rijndael256_avx; + vole_params->keygen_rng = keygen_rng_cat3_rijndael256_avx; + // arithmetic + vole_params->flambda_set = gf192_flambda_set_ref; + vole_params->flambda_inverse = gf192_flambda_inverse_pclmul; + vole_params->flambda_sum_pow2 = gf192_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf192_flambda_sum_ref; + vole_params->flambda_product = gf192_flambda_product_pclmul; + vole_params->flambda_product_f2 = gf192_flambda_product_f2_ref; // no avx version + vole_params->flambda_dot_product = gf192_flambda_dot_product_pclmul; + vole_params->flambda_dot_product_acc = gf192_flambda_dot_product_acc_pclmul; + vole_params->flambda_dot_product_f2_acc = gf192_flambda_dot_product_f2_acc_avx2; + vole_params->flambda_echelon_pow2 = gf192_flambda_echelon_pow2_avx; + vole_params->matrix_lambda_transpose = transpose_192_L_ref; + break; + case 256: + // crypto + switch (proofow_variant) { + case PROOFOW_VARIANT_SHAKE: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_shake_cat5; + vole_params->proofow_init = proofow_init_shake_cat5; + vole_params->proofow_grind_w = proofow_grind_w_shake_cat5_4way; // AVX2 4-way KeccakP-1600-times4 + vole_params->proofow_verify_w = proofow_verify_w_shake_cat5; + vole_params->proofow_release = proofow_release_noop; + break; + case PROOFOW_VARIANT_CIPHER: + vole_params->bytes_of_proofow_ctx = bytes_of_proofow_ctx_cipher_cat5; + vole_params->proofow_init = proofow_init_cipher_cat5_avx; + vole_params->proofow_grind_w = proofow_grind_w_cipher_cat5_avx; + vole_params->proofow_verify_w = proofow_verify_w_cipher_cat5_avx; + vole_params->proofow_release = proofow_release_noop; + break; + default: + CREQUIRE(0, "Unknown proof-of-work variant"); + } + vole_params->extend_leaf_seed = extend_leaf_seed_cat5_rijndael256_avx2; + vole_params->extend_leaf_seed_4x = extend_leaf_seed_cat5_rijndael256_4x_avx2; + vole_params->prepare_extseed_buf = extseed_buf_noop; + vole_params->release_extseed_buf = extseed_buf_noop; + vole_params->extended_node_seed_bytes = extended_node_seed_bytes_cat5_rijndael256; + vole_params->ggm_extseed_rng_lr = ggm_seed_rng_lr_ext_cat5_rijndael256_avx2; + vole_params->ggm_extseed_rng_lr_x4 = ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2; // I8: naive four calls + vole_params->ggm_extseed_rng_commit = ggm_commit_rng_ext_cat5_rijndael256_avx2; + vole_params->vole_extseed_rng = vole_rng_ext_cat5_rijndael256_ctrle_avx2; + vole_params->xof = xof_shake256; + vole_params->xof_vector = xof_vector_shake256; + vole_params->matrix_prg = matrix_rng_cat5_rijndael256_avx; + vole_params->keygen_rng = keygen_rng_cat5_rijndael256_avx; + // arithmetic + vole_params->flambda_set = gf256_flambda_set_ref; + vole_params->flambda_inverse = gf256_flambda_inverse_pclmul; + vole_params->flambda_sum_pow2 = gf256_flambda_sum_pow2_ref; + vole_params->flambda_sum = gf256_flambda_sum_avx2; + vole_params->flambda_product = gf256_flambda_product_pclmul; + vole_params->flambda_product_f2 = gf256_flambda_product_pclmul_f2; + vole_params->flambda_dot_product = gf256_flambda_dot_product_pclmul; + vole_params->flambda_dot_product_acc = gf256_flambda_dot_product_acc_pclmul; + vole_params->flambda_dot_product_f2_acc = gf256_flambda_dot_product_f2_acc_avx2; + vole_params->flambda_echelon_pow2 = gf256_flambda_echelon_pow2_avx; + vole_params->matrix_lambda_transpose = transpose_256_L_ref; + break; + default: + CREQUIRE(0, "lambda not supported"); + } +} diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_private.h b/src/sig/sdith/sdith_sdith_common_avx2/vole_private.h new file mode 100644 index 0000000000..e0957854c4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_private.h @@ -0,0 +1,255 @@ +#ifndef AQ_VOLE_IMPL_VOLE_PRIVATE_H +#define AQ_VOLE_IMPL_VOLE_PRIVATE_H + +#include +#include + +#include "commons.h" +#include "sdith_inline.h" +#include "ggm.h" +#include "sdith_algebra.h" +#include "sdith_arithmetic.h" +#include "sdith_vole_to_piop.h" +#include "sdith_piop_circuits.h" +#include "sdith_prng.h" +#include "sdith_rsd.h" +#include "sdith_signature.h" +#include "vole_parameters.h" +#include "vole_generation.h" + +#define CREQUIRE(condition, error_printf...) \ + do { \ + if (!(condition)) { \ + fprintf(stderr, "ERROR!! :" error_printf); \ + abort(); \ + } \ + } while (0) + +#define CREQUIRE_ALIGNMENT(variable, alignment) \ + CREQUIRE(((uint64_t)(variable) & ((alignment) - 1)) == 0, "alignment problem:" __FILE__ " : %d", __LINE__); + +#ifdef NDEBUG +#define CASSERT(condition, error_printf...) +#define CASSERT_ALIGNMENT(variable, alignment) +#else +#define CASSERT CREQUIRE +#define CASSERT_ALIGNMENT CREQUIRE_ALIGNMENT +#endif + +SDITH_ALWAYS_INLINE uint64_t alignment_of(uint64_t x) { return (x ^ (x - 1)) >> 1; } + +// irreducible polynomial constant for GF128 +#define GF128_PV 0b10000111 +#define GF192_PV 0b10000111 +#define GF256_PV 0b10000100101 +static const __uint128_t GF128_P = GF128_PV; +static const uint64_t GF256_P = GF256_PV; +static const uint64_t GF192_P = GF192_PV; +static const uint64_t GF121_P = 0b100100011; + +// in the public API, the layout of the fields is OPAQUE +// here, we only provide possible instantiations. +// it is also possible to cast these types to __m128i for instance + +union gf128_t { + uint8_t v[16]; + __uint128_t v128; +}; +union gf121_t { + uint8_t v[16]; + __uint128_t v128; +}; +union gf192_t { + uint8_t v[24]; + uint64_t v64[3]; +}; +union gf256_t { + uint8_t v[32]; + uint64_t v64[4]; +}; + +// Constant-time carryless (GF(2)[x]) multiply helpers used by the reference +// field multiplies. gf_bmul32 is BearSSL's branchless 32x32->64 carryless +// product: only integer multiply, mask and xor, so it has no data-dependent +// branch or memory access and runs in time independent of its operands (the +// integer multiplier is constant-time on the targets we care about, incl. +// Cortex-M4 UMULL). gf_clmul64 combines three gf_bmul32 (Karatsuba) into a +// full 64x64->128 carryless product. +SDITH_ALWAYS_INLINE uint64_t gf_bmul32(uint32_t x, uint32_t y) { + uint32_t x0 = x & 0x11111111u, x1 = x & 0x22222222u, x2 = x & 0x44444444u, x3 = x & 0x88888888u; + uint32_t y0 = y & 0x11111111u, y1 = y & 0x22222222u, y2 = y & 0x44444444u, y3 = y & 0x88888888u; + uint64_t z0 = (uint64_t)x0 * y0 ^ (uint64_t)x1 * y3 ^ (uint64_t)x2 * y2 ^ (uint64_t)x3 * y1; + uint64_t z1 = (uint64_t)x0 * y1 ^ (uint64_t)x1 * y0 ^ (uint64_t)x2 * y3 ^ (uint64_t)x3 * y2; + uint64_t z2 = (uint64_t)x0 * y2 ^ (uint64_t)x1 * y1 ^ (uint64_t)x2 * y0 ^ (uint64_t)x3 * y3; + uint64_t z3 = (uint64_t)x0 * y3 ^ (uint64_t)x1 * y2 ^ (uint64_t)x2 * y1 ^ (uint64_t)x3 * y0; + z0 &= 0x1111111111111111ull; z1 &= 0x2222222222222222ull; + z2 &= 0x4444444444444444ull; z3 &= 0x8888888888888888ull; + return z0 | z1 | z2 | z3; +} +SDITH_ALWAYS_INLINE void gf_clmul64(uint64_t a, uint64_t b, uint64_t* hi, uint64_t* lo) { + uint32_t a0 = (uint32_t)a, a1 = (uint32_t)(a >> 32), b0 = (uint32_t)b, b1 = (uint32_t)(b >> 32); + uint64_t z0 = gf_bmul32(a0, b0); + uint64_t z2 = gf_bmul32(a1, b1); + uint64_t z1 = gf_bmul32(a0 ^ a1, b0 ^ b1) ^ z0 ^ z2; + *lo = z0 ^ (z1 << 32); + *hi = z2 ^ (z1 >> 32); +} + +extern const gf256 GF256_ONE; +extern const gf256 GF256_ZERO; +// functions by value should are for test and assertions purposes only +EXPORT uint8_t gf256v_equals(const gf256 a, const gf256 b); +EXPORT uint8_t gf256v_bitof(const gf256 a, const uint64_t position); +EXPORT gf256 gf256v_sum(const gf256 a, const gf256 b); +EXPORT gf256 gf256v_lsh(const gf256 a, const uint64_t amount); +EXPORT gf256 gf256v_rsh(const gf256 a, const uint64_t amount); +EXPORT gf256 gf256v_mul(const gf256 a, const gf256 b); +// left and right shift by pointer are not part of the private API +EXPORT void gf256p_lsh(gf256* const res, const gf256* const a, const uint64_t amount); +EXPORT void gf256p_rsh(gf256* const res, const gf256* const a, const uint64_t amount); + +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b); + +extern const gf192 GF192_ONE; +extern const gf192 GF192_ZERO; +// functions by value should are for test and assertions purposes only +EXPORT uint8_t gf192v_equals(const gf192 a, const gf192 b); +EXPORT uint8_t gf192v_bitof(const gf192 a, const uint64_t position); +EXPORT gf192 gf192v_sum(const gf192 a, const gf192 b); +EXPORT gf192 gf192v_lsh(const gf192 a, const uint64_t amount); +EXPORT gf192 gf192v_rsh(const gf192 a, const uint64_t amount); +EXPORT gf192 gf192v_mul(const gf192 a, const gf192 b); +// left and right shift by pointer are not part of the private API +EXPORT void gf192p_lsh(gf192* const res, const gf192* const a, const uint64_t amount); +EXPORT void gf192p_rsh(gf192* const res, const gf192* const a, const uint64_t amount); + +EXPORT void gf192_sum_ref(gf192* res, const gf192* a, const gf192* b); + +extern const gf128 GF128_ONE; +extern const gf128 GF128_ZERO; +// functions by value should are for test and assertions purposes only +EXPORT uint8_t gf128v_equals(const gf128 a, const gf128 b); +EXPORT uint8_t gf128v_bitof(const gf128 a, const uint64_t position); +EXPORT gf128 gf128v_sum(const gf128 a, const gf128 b); +EXPORT gf128 gf128v_lsh(const gf128 a, const uint64_t amount); +EXPORT gf128 gf128v_rsh(const gf128 a, const uint64_t amount); +EXPORT gf128 gf128v_mul(const gf128 a, const gf128 b); +// left and right shift by pointer are not part of the private API +EXPORT void gf128p_lsh(gf128* const res, const gf128* const a, const uint64_t amount); +EXPORT void gf128p_rsh(gf128* const res, const gf128* const a, const uint64_t amount); +EXPORT void gf128p_sum(gf128* const res, const gf128* const a, const gf128* const b); +EXPORT void gf128p_mul(gf128* const res, const gf128* const a, const gf128* const b); + +EXPORT void gf128_sum_ref(gf128* res, const gf128* a, const gf128* b); + +// binary valuation +uint16_t binval_of(uint16_t i); +uint16_t grey_of(uint16_t x); +uint16_t inv_grey_of(uint16_t x); + +/** @brief extract/xorto a kappa-bit uint from a bit array. + * data must be 8-byte aligned and its size must be a multiple of 8. */ +EXPORT uint32_t extract_kappabit_uint(uint64_t kappa, uint64_t bitpos, const void* data); +EXPORT void xorto_kappabit_uint(uint64_t kappa, uint64_t bitpos, void* data, uint64_t value); + +/** raise to the power p */ +EXPORT void flambda_power(const vole_parameters* vole_params, flambda_t* res, const flambda_t* x, uint64_t p); + +/** test if a field element is zero (non-ct version) */ +EXPORT uint8_t flambda_is_zero_nonct(const vole_parameters* vole_params, const flambda_t* x); +/** test if a bit vector is zero (non-ct version) */ +EXPORT uint8_t bitvec_is_zero_nonct(const uint8_t* x, uint64_t num_bits); + +#define TMP_SPACE_MAP_ALIGNED(VARTYPE, VARNAME, VARALIGN, BYTE_SIZE) \ + tmp_space = (uint8_t*)(((uint64_t)tmp_space + (VARALIGN - 1)) & (uint64_t)(-(VARALIGN))); \ + VARTYPE VARNAME = (VARTYPE)tmp_space; \ + tmp_space += (BYTE_SIZE) + +#define TMP_SPACE_MAP(VARTYPE, VARNAME, BYTE_SIZE) \ + VARTYPE VARNAME = (VARTYPE)tmp_space; \ + tmp_space += (BYTE_SIZE) + +// this one is empty +#define TMP_SPACE_MAP_CALL(BYTE_SIZE) + +#define COMP_SPACE_INIT() \ + struct tmp_bytes_comp_t ts; \ + tmp_bytes_init(&ts) + +#define COMP_SPACE_MAP_ALIGNED(VARTYPE, VARNAME, VARALIGN, BYTE_SIZE) \ + tmp_bytes_reserve_local_var_aligned(&ts, (VARALIGN), (BYTE_SIZE)) + +#define COMP_SPACE_MAP(VARTYPE, VARNAME, BYTE_SIZE) tmp_bytes_reserve_local_var(&ts, (BYTE_SIZE)) + +#define COMP_SPACE_MAP_CALL(BYTE_SIZE) tmp_bytes_reserve_call(&ts, (BYTE_SIZE)) + +#define COMP_SPACE_RETURN() return ts.max_size + +/** helper structure to compute the tmp space required for functions */ +typedef struct tmp_bytes_comp_t { + uint64_t local_size; // size of local variables + uint64_t max_size; // local variables + calls + uint64_t last_alignment; // last requested local alignment +} tmp_bytes_comp_t; + +EXPORT void tmp_bytes_init(tmp_bytes_comp_t* tmp_bytes_comp); +EXPORT void tmp_bytes_reserve_local_var(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_bytes); +EXPORT void tmp_bytes_reserve_local_var_aligned(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t var_align, + uint64_t var_bytes); +EXPORT void tmp_bytes_reserve_call(tmp_bytes_comp_t* tmp_bytes_comp, uint64_t call_tmp_bytes); + +EXPORT_DECL const uint8_t HASH_BAVC_PREFIX; +EXPORT_DECL const uint8_t HASH_AUX_PREFIX; +EXPORT_DECL const uint8_t HASH_LINES_PREFIX; +EXPORT_DECL const uint8_t HASH_PIOP_PREFIX; +EXPORT_DECL const uint8_t PROOFOW_H0_PREFIX; +EXPORT_DECL const uint8_t PROOFOW_H1_PREFIX; +EXPORT_DECL const uint64_t PROOFOW_CTR_REVEALED_BYTES; + +// sdith parameters: deduced parameter set +typedef struct extended_parameters_t { + uint64_t lambda; + uint64_t kappa; + uint64_t tau; + uint64_t target_topen; + uint64_t rsd_n; + uint64_t rsd_w; + uint64_t mux_arities[8]; + uint64_t mux_depth; + uint64_t rsd_npw; + uint64_t rsd_codim; + uint64_t proofow_w; + uint64_t delta0_bits; + uint64_t delta0_dwords; + uint64_t delta0_bytess; + uint64_t delta0_capacity; + vole_parameters vole_params; + uint64_t mux_inputs; + uint64_t chall_unitary_powers; + uint64_t degree; + uint64_t num_inputs_pairs; + uint64_t num_cchk_pairs; + uint64_t num_cz_pairs; + uint64_t real_L; + uint64_t L; + uint64_t Lbyte; + uint64_t Lslice; + uint64_t lambda_bytes; + uint64_t cchk_matrix_nrows; + uint64_t cchk_matrix_ncols; + uint64_t rsd_codim_bytes; + uint64_t rsd_codim_limbs; + uint64_t rsd_codim_slice; // byte slice if we store the full matrix H (multiple of the rng block) +} extended_parameters_t; + +/** compute the rsd codim slice (bytes), accounting for the prng block size and the actual bitsize */ +EXPORT void compute_rsd_codim_slice( + uint64_t* rsd_codim_limbs, // [out] number of limbs + uint64_t* rsd_codim_slice, // [out] number of slice bytes to hold the prng blocks + const uint64_t lambda, const uint64_t rsd_codim); + +EXPORT void compute_extended_parameters(extended_parameters_t* res, const signature_parameters* sig_params); + +EXPORT uint32_t ceil_log2i(uint32_t x); + +#endif // AQ_VOLE_IMPL_VOLE_PRIVATE_H diff --git a/src/sig/sdith/sdith_sdith_common_avx2/vole_to_piop.c b/src/sig/sdith/sdith_sdith_common_avx2/vole_to_piop.c new file mode 100644 index 0000000000..ac936b613e --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_avx2/vole_to_piop.c @@ -0,0 +1,208 @@ +#include + +#include "vole_private.h" + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void prover_f2_to_flambda_deg1_std_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + fpoly_t* out_f, // [out] deg-1 fpoly[num_pairs] + const bitvec_t* in_u, // [in] in_L bits where in_L = num_pairs * LAMBDA + const flambda_t* in_v) // [in] flambda[in_L] +{ + uint8_t* out = (uint8_t*)out_f; + const uint8_t* u = (uint8_t*)in_u; + const uint8_t* v = (uint8_t*)in_v; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t lambda = vole_params->LAMBDA; + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_v, alignment_of(lambda_bytes)); + + for (size_t i = 0; i < num_pairs; i++) { + (*vole_params->flambda_sum_pow2)(out + lambda_bytes * 2 * i, v + lambda_bytes * lambda * i); + memcpy(out + lambda_bytes * (2 * i + 1), u + lambda_bytes * i, lambda_bytes); + } +} + +/** + * Recombine in_L = lambda. out_L full-size std vole pairs over F2 + * To form out_L full-size std vole F2^LAMBDA + */ +EXPORT void verifier_f2_to_flambda_deg1_std_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // number of output pairs to produce + flambda_t* out_q, // [out] gflambda[num_pairs] + const flambda_t* in_q) // [in] gflambda in_q[in_L] where in_L = num_pairs * LAMBDA +{ + uint8_t* out = (uint8_t*)out_q; + const uint8_t* in = (uint8_t*)in_q; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + const uint64_t lambda = vole_params->LAMBDA; + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + + for (size_t i = 0; i < num_pairs; i++) { + (*vole_params->flambda_sum_pow2)(out + lambda_bytes * i, in + lambda_bytes * lambda * i); + } +} + +/** + * convert d degree 1 std-vole over flambda to one degree-d vole + */ +EXPORT void prover_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + fpoly_t* out_f, // single poly_t of degree out_degree + const fpoly_t* in_f) // out_degree poly[out_degree] +{ + CASSERT(out_degree > 0, "degree 0 is not supported"); + // this function can work in place + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_f, alignment_of(lambda_bytes)); + const uint8_t* const in = (uint8_t*)in_f; + uint8_t* const out = (uint8_t*)out_f; + + // copy first coefficient of first polynomial to out_f + vole_params->flambda_set(out, in); + + for (size_t i = 1; i < out_degree; i++) { + (*vole_params->flambda_sum)(out + lambda_bytes * i, // result + in + lambda_bytes * (2 * i), // low coefficient of i-th in_f poly + in + lambda_bytes * (2 * i - 1) // high coefficient of (i-1)-th in_f poly + ); + } + + // copy second coefficient of last polynomial to out_f + vole_params->flambda_set(out + out_degree * lambda_bytes, in + (2 * out_degree - 1) * lambda_bytes); +} + +/** + * convert d degree 1 std-vole to one degree-d vole + */ +EXPORT void verifier_flambda_deg1_to_degd_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t out_degree, // degree of the output pair + flambda_t* out_q, // [out] single gflambda + const flambda_t* in_q, // [in] gflambda[out_deg] + const flambda_t* delta) // verifier's point powers +{ + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(delta, alignment_of(lambda_bytes)); + const uint8_t* const in = (uint8_t*)in_q; + uint8_t* const out = (uint8_t*)out_q; + // we use a temporary so that the function works in place + flambda_max_t tmp; + + (*vole_params->flambda_set)(tmp, in + (out_degree - 1) * lambda_bytes); + for (int64_t i = out_degree - 2; i >= 0; i--) { + (*vole_params->flambda_product)(tmp, tmp, delta); + (*vole_params->flambda_sum)(tmp, tmp, in + i * lambda_bytes); + } + (*vole_params->flambda_set)(out, tmp); +} + +/** + * convert a degree-d vole from std to cst + */ +EXPORT void prover_flambda_degd_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // degree d of of the pair to process + fpoly_t* out_f, // [out] single poly of degree d + const fpoly_t* in_f) // [in] single poly of degree d +{ + // mirror f + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(out_f, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(in_f, alignment_of(lambda_bytes)); + uint8_t* res = (uint8_t*)out_f; + const uint8_t* in = (const uint8_t*)in_f; + if (in_f == out_f) { + // in place variant + uint64_t half_d = (degree + 1) >> 1; + for (uint64_t i = 0; i < half_d; i++) { + uint8_t* r1 = res + i * lambda_bytes; + uint8_t* r2 = res + (degree - i) * lambda_bytes; + // swap r1 <-> r2 + vole_params->flambda_sum(r1, r1, r2); + vole_params->flambda_sum(r2, r2, r1); + vole_params->flambda_sum(r1, r1, r2); + } + } else { + // out of place variant + for (uint64_t i = 0; i <= degree; i++) { + memcpy(res + i * lambda_bytes, in + (degree - i) * lambda_bytes, lambda_bytes); + } + } +} + +/** + * convert d degree 1 std-vole to one degree-d cst-vole + */ +EXPORT void verifier_flambda_degd_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t degree, // output degree + flambda_t* out_q, // [out] single evaluation + const flambda_t* in_q, // [in] single evaluation + const flambda_t* delta_pow_d) // [in] verifier's point to the power d +{ +#ifndef NDEBUG + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CREQUIRE_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + CREQUIRE_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + CREQUIRE_ALIGNMENT(delta_pow_d, alignment_of(lambda_bytes)); +#endif + vole_params->flambda_product(out_q, in_q, delta_pow_d); +} + +/** + * convert packed degree 1 std-vole to packed cst-vole + */ +EXPORT void prover_f2_std_to_cst_vole_ct_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + bitvec_t* out_u, flambda_t* out_v, // [out] bit[num_pairs], flambda[num_pairs] + const bitvec_t* in_u, const flambda_t* in_v) // [in] bit[num_pairs], flambda[num_pairs] +{ +#ifndef NDEBUG + uint64_t lambda_bytes = vole_params->lambda_bytes; + CREQUIRE_ALIGNMENT(in_v, alignment_of(lambda_bytes)); + CREQUIRE_ALIGNMENT(out_v, alignment_of(lambda_bytes)); +#endif + if (in_u == out_u && in_v == out_v) return; + memcpy(out_u, in_u, (num_pairs + 7) >> 3); + memcpy(out_v, in_v, vole_params->lambda_bytes * num_pairs); +} + +/** + * convert packed degree 1 std-vole to packed cst-vole + */ +EXPORT void verifier_f2_std_to_cst_vole_ref( // + const vole_parameters* vole_params, // dimensions + uint64_t num_pairs, // num_pairs to process + flambda_t* out_q, // [out] gflambda[num_pairs] + const flambda_t* in_q, // [in] gflambda[num_pairs] + const flambda_t* delta2) // [in] verifier's point +{ + const uint8_t* in = (uint8_t*)in_q; + uint8_t* out = (uint8_t*)out_q; + const uint64_t lambda_bytes = vole_params->lambda_bytes; + CASSERT_ALIGNMENT(in_q, alignment_of(lambda_bytes)); + CASSERT_ALIGNMENT(out_q, alignment_of(lambda_bytes)); + + for (size_t i = 0; i < num_pairs; i++) { + (*vole_params->flambda_product)(out + lambda_bytes * i, in + lambda_bytes * i, delta2); + } +} + +/** @brief converts delta1 to delta2 + * delta2 is the field inverse of delta1 + */ +EXPORT void delta2_from_delta1_ref(const vole_parameters* vole_params, flambda_t* delta2, const flambda_t* delta1) { + vole_params->flambda_inverse(delta2, delta1); +} diff --git a/src/sig/sdith/sdith_sdith_common_headers/LICENSE.txt b/src/sig/sdith/sdith_sdith_common_headers/LICENSE.txt new file mode 100644 index 0000000000..599479c32a --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_headers/LICENSE.txt @@ -0,0 +1,235 @@ +======================================================================== +Apache 2.0 License +======================================================================== + 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. + +======================================================================== +Third-Party Components & Subcomponent Licenses +======================================================================== +This software includes the following third-party components under distinct licenses: + +lib/sha3: + copied from The eXtended Keccak Code Package (XKCP) (multiple licenses) + https://github.com/XKCP/XKCP + only build files have been edited (CMakeLists.txt) + +lib/aes/aes_ansi_ref.c/.h: + ANSI C Rijndael code by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto -- public domain + A little-endian version of the algorithm is provided in aes_ansi_littleendian_ref.c + the avx implementation via the aes-ni instructions are new, and covered by the main repository license. + +lib/aes/rijndael256_avx.c/.h: + The following part is adapted from a work by Nir Drucker and Shay Gueron: + Software optimization of Rijndael for Modern x86_64 platforms, + in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) + Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. + (SPDX-License-Identifier: Apache-2.0) + +kat/*/PQCgenKAT_sign.c, rng.c, rng.h: + NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the + software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative + works of the software or any portion of the software, and you may copy and distribute such modifications or works. + Modified works should carry a notice stating that you changed the software and should note the date and nature of any + such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the + software. + diff --git a/src/sig/sdith/sdith_sdith_common_headers/NOTICE b/src/sig/sdith/sdith_sdith_common_headers/NOTICE new file mode 100644 index 0000000000..f372dc9e28 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_headers/NOTICE @@ -0,0 +1,28 @@ +Copyright 2026 The SDitH Consortium + +This product includes software developed by: + +lib/sha3: + copied from The eXtended Keccak Code Package (XKCP) (multiple licenses) + https://github.com/XKCP/XKCP + only build files have been edited (CMakeLists.txt) + +lib/aes/aes_ansi_ref.c/.h: + ANSI C Rijndael code by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto -- public domain + A little-endian version of the algorithm is provided in aes_ansi_littleendian_ref.c + the avx implementation via the aes-ni instructions are new, and covered by the main repository license. + +lib/aes/rijndael256_avx.c/.h: + The following part is adapted from a work by Nir Drucker and Shay Gueron: + Software optimization of Rijndael for Modern x86_64 platforms, + in ITNG 2022 - 19th International Conference on Information Technology - New Generations (pp 147-153) + Original code: Copyright Nir Drucker and Shay Gueron All Rights Reserved. + (SPDX-License-Identifier: Apache-2.0) + +kat/*/PQCgenKAT_sign.c, rng.c, rng.h: + NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the + software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative + works of the software or any portion of the software, and you may copy and distribute such modifications or works. + Modified works should carry a notice stating that you changed the software and should note the date and nature of any + such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the + software. diff --git a/src/sig/sdith/sdith_sdith_common_headers/commons.h b/src/sig/sdith/sdith_sdith_common_headers/commons.h new file mode 100644 index 0000000000..d30521b080 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_headers/commons.h @@ -0,0 +1,55 @@ +#ifndef COMMONS_H +#define COMMONS_H + +/* liboqs links one shared copy of this code into every scheme variant, so the + * internal symbols need a namespace of their own. See gen_namespace.sh. */ +#ifdef SDITH3_FOR_LIBOQS +#include "sdith_namespace.h" +#endif + +#ifdef __cplusplus +#define EXPORT extern "C" +#define EXPORT_DECL extern "C" +#include +#else +#define EXPORT +#define EXPORT_DECL extern +#include "stdint.h" +#endif + +#ifdef __x86_64__ +#define CPU_SUPPORTS(feature) __builtin_cpu_supports(feature) +#endif + +/* Namespacing with the appropriate prefix */ +#ifndef SDITH_PUBLIC_API_NAMESPACE +#ifdef APPLY_PUBLIC_API_NAMESPACE +#ifndef concat2 +#define _concat2(a, b) a ## b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_PUBLIC_API_NAMESPACE(s) concat2(APPLY_PUBLIC_API_NAMESPACE, s) +#else +#define SDITH_PUBLIC_API_NAMESPACE(s) s +#endif +#endif + +typedef void bitvec_t; // vector of bits row major (dimensions provided at runtime) +typedef void bitmat_t; // matrix of bits row major (dimensions provided at runtime) +typedef void flambda_t; // at runtime, the size of a big fielf elem is lam (i.e. lambda/8) +typedef void fpoly_t; // at runtime, the size of a degree d is (d+1).lam +typedef void seed_t; // at runtime, the size of a commit is 1.lam +typedef void salt_t; // at runtime, the size of a commit is 1.lam +typedef void hash_t; // at runtime, the size of a hash is 2.lam +typedef void commit_t; // at runtime, the size of a commit is 2.lam +typedef void hash_ctx_t; + +// type large enough to hold one field element +typedef uint64_t flambda_max_t[4] __attribute((aligned(32))); // usable as data type for temporary variables + +typedef enum proofow_variant_t { + PROOFOW_VARIANT_SHAKE = 0, + PROOFOW_VARIANT_CIPHER = 1 +} proofow_variant_t; + +#endif // COMMONS_H diff --git a/src/sig/sdith/sdith_sdith_common_headers/sdith_namespace.h b/src/sig/sdith/sdith_sdith_common_headers/sdith_namespace.h new file mode 100644 index 0000000000..8691c1c0e4 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_headers/sdith_namespace.h @@ -0,0 +1,528 @@ +#ifndef SDITH_NAMESPACE_H +#define SDITH_NAMESPACE_H + +/** + * Generated by integration/liboqs/gen_namespace.sh. Do not edit by hand. + * + * liboqs compiles the shared SDitH sources once and links every scheme variant + * against that single copy, so these symbols are global in liboqs' own library. + */ + +#ifdef APPLY_NAMESPACE + +#ifndef concat2 +#define _concat2(a, b) a##b +#define concat2(a, b) _concat2(a, b) +#endif +#define SDITH_NAMESPACE_FOR_LIBOQS(s) concat2(APPLY_NAMESPACE, s) + +#define CAT1_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_CIPHERPOW_PARAMETERS) +#define CAT1_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_FAST_PARAMETERS) +#define CAT1_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_CIPHERPOW_PARAMETERS) +#define CAT1_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT1_SHORT_PARAMETERS) +#define CAT3_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_CIPHERPOW_PARAMETERS) +#define CAT3_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_FAST_PARAMETERS) +#define CAT3_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_CIPHERPOW_PARAMETERS) +#define CAT3_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT3_SHORT_PARAMETERS) +#define CAT5_FAST_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_CIPHERPOW_PARAMETERS) +#define CAT5_FAST_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_FAST_PARAMETERS) +#define CAT5_SHORT_CIPHERPOW_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_CIPHERPOW_PARAMETERS) +#define CAT5_SHORT_PARAMETERS SDITH_NAMESPACE_FOR_LIBOQS(CAT5_SHORT_PARAMETERS) +#define FLAMBDA_2P32 SDITH_NAMESPACE_FOR_LIBOQS(FLAMBDA_2P32) +#define GF128_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF128_ONE) +#define GF128_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF128_ZERO) +#define GF192_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF192_ONE) +#define GF192_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF192_ZERO) +#define GF256_ONE SDITH_NAMESPACE_FOR_LIBOQS(GF256_ONE) +#define GF256_ZERO SDITH_NAMESPACE_FOR_LIBOQS(GF256_ZERO) +#define HASH_AUX_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_AUX_PREFIX) +#define HASH_BAVC_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_BAVC_PREFIX) +#define HASH_LINES_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_LINES_PREFIX) +#define HASH_PIOP_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(HASH_PIOP_PREFIX) +#define PROOFOW_CTR_REVEALED_BYTES SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_CTR_REVEALED_BYTES) +#define PROOFOW_H0_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H0_PREFIX) +#define PROOFOW_H1_PREFIX SDITH_NAMESPACE_FOR_LIBOQS(PROOFOW_H1_PREFIX) +#define aes128_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_avx2) +#define aes128_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_1block_ref) +#define aes128_ctrle_nocarry_2blk_x4keys_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2blk_x4keys_avx2) +#define aes128_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_avx2) +#define aes128_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_2block_ref) +#define aes128_ctrle_nocarry_3blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_avx2) +#define aes128_ctrle_nocarry_3blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_3blocks_ref) +#define aes128_ctrle_nocarry_4blocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_avx2) +#define aes128_ctrle_nocarry_4blocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_4blocks_ref) +#define aes128_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_avx2) +#define aes128_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_nocarry_nblocks_ref) +#define aes128_ctrle_set_key_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_ctrle_set_key_avx2) +#define aes128_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_encrypt_1block_ref) +#define aes128_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_avx2) +#define aes128_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x1_ref) +#define aes128_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_avx2) +#define aes128_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x2_ref) +#define aes128_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_avx2) +#define aes128_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x3_ref) +#define aes128_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_avx2) +#define aes128_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_key_schedule_x4_ref) +#define aes128_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(aes128_keyexp_x4_enclast) +#define aes128_prepare_rk_buffer SDITH_NAMESPACE_FOR_LIBOQS(aes128_prepare_rk_buffer) +#define aes128_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(aes128_proofow_grind_avx2) +#define aes128_release_key SDITH_NAMESPACE_FOR_LIBOQS(aes128_release_key) +#define aes128_set_key_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_ref) +#define aes128_set_key_reuse_ref SDITH_NAMESPACE_FOR_LIBOQS(aes128_set_key_reuse_ref) +#define binval_of SDITH_NAMESPACE_FOR_LIBOQS(binval_of) +#define binval_of_compat SDITH_NAMESPACE_FOR_LIBOQS(binval_of_compat) +#define bit_of SDITH_NAMESPACE_FOR_LIBOQS(bit_of) +#define bitmat_get_value SDITH_NAMESPACE_FOR_LIBOQS(bitmat_get_value) +#define bitvec_cascade_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_avx2) +#define bitvec_cascade_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_cascade_xor_to_ref) +#define bitvec_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(bitvec_is_zero_nonct) +#define bitvec_xor_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_avx2) +#define bitvec_xor_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_ref) +#define bitvec_xor_to_avx2 SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_avx2) +#define bitvec_xor_to_masked_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_avx) +#define bitvec_xor_to_masked_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_masked_ct_ref) +#define bitvec_xor_to_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xor_to_ref) +#define bitvec_xorbit_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_avx) +#define bitvec_xorbit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xorbit_ct_ref) +#define bitvec_xoru32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_avx) +#define bitvec_xoru32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(bitvec_xoru32_ct_ref) +#define both_vole_consistency_check_matrix SDITH_NAMESPACE_FOR_LIBOQS(both_vole_consistency_check_matrix) +#define bytes_of_proofow_ctx_cipher_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat1) +#define bytes_of_proofow_ctx_cipher_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat3) +#define bytes_of_proofow_ctx_cipher_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_cipher_cat5) +#define bytes_of_proofow_ctx_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat1) +#define bytes_of_proofow_ctx_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat3) +#define bytes_of_proofow_ctx_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(bytes_of_proofow_ctx_shake_cat5) +#define ceil_log2i SDITH_NAMESPACE_FOR_LIBOQS(ceil_log2i) +#define compute_extended_parameters SDITH_NAMESPACE_FOR_LIBOQS(compute_extended_parameters) +#define compute_rsd_codim SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim) +#define compute_rsd_codim_slice SDITH_NAMESPACE_FOR_LIBOQS(compute_rsd_codim_slice) +#define compute_tweaked_salts SDITH_NAMESPACE_FOR_LIBOQS(compute_tweaked_salts) +#define delta1_from_delta0_ref SDITH_NAMESPACE_FOR_LIBOQS(delta1_from_delta0_ref) +#define delta2_from_delta1_ref SDITH_NAMESPACE_FOR_LIBOQS(delta2_from_delta1_ref) +#define div_rem_u32_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_avx) +#define div_rem_u32_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(div_rem_u32_ct_ref) +#define estimate_topen SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen) +#define estimate_topen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(estimate_topen_tmp_bytes) +#define extend_leaf_seed_cat1_aes128_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_avx2) +#define extend_leaf_seed_cat1_aes128_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_4x_ref) +#define extend_leaf_seed_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_avx2) +#define extend_leaf_seed_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat1_aes128_ref) +#define extend_leaf_seed_cat3_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_avx2) +#define extend_leaf_seed_cat3_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_4x_ref) +#define extend_leaf_seed_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_avx2) +#define extend_leaf_seed_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat3_rijndael256_ref) +#define extend_leaf_seed_cat5_rijndael256_4x_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_avx2) +#define extend_leaf_seed_cat5_rijndael256_4x_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_4x_ref) +#define extend_leaf_seed_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_avx2) +#define extend_leaf_seed_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(extend_leaf_seed_cat5_rijndael256_ref) +#define extended_node_seed_bytes_cat1_aes128 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat1_aes128) +#define extended_node_seed_bytes_cat3_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat3_rijndael256) +#define extended_node_seed_bytes_cat5_rijndael256 SDITH_NAMESPACE_FOR_LIBOQS(extended_node_seed_bytes_cat5_rijndael256) +#define extract_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(extract_kappabit_uint) +#define extseed_buf_noop SDITH_NAMESPACE_FOR_LIBOQS(extseed_buf_noop) +#define flambda_is_zero_nonct SDITH_NAMESPACE_FOR_LIBOQS(flambda_is_zero_nonct) +#define flambda_power SDITH_NAMESPACE_FOR_LIBOQS(flambda_power) +#define floor_log2i SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i) +#define floor_log2i_compat SDITH_NAMESPACE_FOR_LIBOQS(floor_log2i_compat) +#define full_ggm_tree_open_sibling_path_from_root SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root) +#define full_ggm_tree_open_sibling_path_from_root_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(full_ggm_tree_open_sibling_path_from_root_tmp_bytes) +#define gf128_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_pclmul) +#define gf128_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_acc_ref) +#define gf128_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_avx2) +#define gf128_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_f2_acc_ref) +#define gf128_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_pclmul) +#define gf128_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_dot_product_ref) +#define gf128_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_avx) +#define gf128_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_naive) +#define gf128_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_echelon_pow2_ref) +#define gf128_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_pclmul) +#define gf128_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_acc_ref) +#define gf128_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_avx2) +#define gf128_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_f2_acc_ref) +#define gf128_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_pclmul) +#define gf128_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_dot_product_ref) +#define gf128_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_avx) +#define gf128_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_echelon_pow2_ref) +#define gf128_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_pclmul) +#define gf128_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_inverse_ref) +#define gf128_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_f2_ref) +#define gf128_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul) +#define gf128_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_pclmul_f2) +#define gf128_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_product_ref) +#define gf128_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_set_ref) +#define gf128_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_avx2) +#define gf128_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_pow2_ref) +#define gf128_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_flambda_sum_ref) +#define gf128_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_pclmul) +#define gf128_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_inverse_ref) +#define gf128_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_f2_ref) +#define gf128_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul) +#define gf128_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_pclmul_f2) +#define gf128_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_product_ref) +#define gf128_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_set_ref) +#define gf128_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_avx2) +#define gf128_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_naive) +#define gf128_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_pow2_ref) +#define gf128_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf128_sum_ref) +#define gf128p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_lsh) +#define gf128p_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128p_mul) +#define gf128p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128p_rsh) +#define gf128p_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128p_sum) +#define gf128v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf128v_bitof) +#define gf128v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf128v_equals) +#define gf128v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_lsh) +#define gf128v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf128v_mul) +#define gf128v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf128v_rsh) +#define gf128v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf128v_sum) +#define gf192_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_pclmul) +#define gf192_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_acc_ref) +#define gf192_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_avx2) +#define gf192_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_f2_acc_ref) +#define gf192_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_pclmul) +#define gf192_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_dot_product_ref) +#define gf192_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_avx) +#define gf192_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_naive) +#define gf192_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_echelon_pow2_ref) +#define gf192_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_pclmul) +#define gf192_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_acc_ref) +#define gf192_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_avx2) +#define gf192_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_f2_acc_ref) +#define gf192_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_pclmul) +#define gf192_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_dot_product_ref) +#define gf192_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_avx) +#define gf192_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_echelon_pow2_ref) +#define gf192_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_pclmul) +#define gf192_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_inverse_ref) +#define gf192_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_f2_ref) +#define gf192_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_pclmul) +#define gf192_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_product_ref) +#define gf192_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_set_ref) +#define gf192_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_pow2_ref) +#define gf192_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_flambda_sum_ref) +#define gf192_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_pclmul) +#define gf192_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_inverse_ref) +#define gf192_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_f2_ref) +#define gf192_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_pclmul) +#define gf192_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_product_ref) +#define gf192_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_set_ref) +#define gf192_sum_pow2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_avx2) +#define gf192_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_naive) +#define gf192_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_pow2_ref) +#define gf192_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf192_sum_ref) +#define gf192p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_lsh) +#define gf192p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192p_rsh) +#define gf192v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf192v_bitof) +#define gf192v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf192v_equals) +#define gf192v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_lsh) +#define gf192v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf192v_mul) +#define gf192v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf192v_rsh) +#define gf192v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf192v_sum) +#define gf256_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_pclmul) +#define gf256_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_acc_ref) +#define gf256_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_avx2) +#define gf256_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_f2_acc_ref) +#define gf256_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_pclmul) +#define gf256_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_dot_product_ref) +#define gf256_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_avx) +#define gf256_echelon_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_naive) +#define gf256_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_echelon_pow2_ref) +#define gf256_flambda_dot_product_acc_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_pclmul) +#define gf256_flambda_dot_product_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_acc_ref) +#define gf256_flambda_dot_product_f2_acc_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_avx2) +#define gf256_flambda_dot_product_f2_acc_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_f2_acc_ref) +#define gf256_flambda_dot_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_pclmul) +#define gf256_flambda_dot_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_dot_product_ref) +#define gf256_flambda_echelon_pow2_avx SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_avx) +#define gf256_flambda_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_echelon_pow2_ref) +#define gf256_flambda_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_pclmul) +#define gf256_flambda_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_inverse_ref) +#define gf256_flambda_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_f2_ref) +#define gf256_flambda_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul) +#define gf256_flambda_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_pclmul_f2) +#define gf256_flambda_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_product_ref) +#define gf256_flambda_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_set_ref) +#define gf256_flambda_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_avx2) +#define gf256_flambda_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_pow2_ref) +#define gf256_flambda_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_flambda_sum_ref) +#define gf256_inverse_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_pclmul) +#define gf256_inverse_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_inverse_ref) +#define gf256_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_f2_ref) +#define gf256_product_pclmul SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul) +#define gf256_product_pclmul_f2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_pclmul_f2) +#define gf256_product_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_product_ref) +#define gf256_set_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_set_ref) +#define gf256_sum_avx2 SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_avx2) +#define gf256_sum_pow2_naive SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_naive) +#define gf256_sum_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_pow2_ref) +#define gf256_sum_ref SDITH_NAMESPACE_FOR_LIBOQS(gf256_sum_ref) +#define gf256p_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_lsh) +#define gf256p_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256p_rsh) +#define gf256v_bitof SDITH_NAMESPACE_FOR_LIBOQS(gf256v_bitof) +#define gf256v_equals SDITH_NAMESPACE_FOR_LIBOQS(gf256v_equals) +#define gf256v_lsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_lsh) +#define gf256v_mul SDITH_NAMESPACE_FOR_LIBOQS(gf256v_mul) +#define gf256v_rsh SDITH_NAMESPACE_FOR_LIBOQS(gf256v_rsh) +#define gf256v_sum SDITH_NAMESPACE_FOR_LIBOQS(gf256v_sum) +#define gfprod128 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128) +#define gfprod128_f2 SDITH_NAMESPACE_FOR_LIBOQS(gfprod128_f2) +#define ggm_commit_rng_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_avx2) +#define ggm_commit_rng_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat1_aes128_ref) +#define ggm_commit_rng_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_avx2) +#define ggm_commit_rng_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat3_rijndael256_ref) +#define ggm_commit_rng_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_avx2) +#define ggm_commit_rng_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_commit_rng_ext_cat5_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat1_aes128_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_avx2) +#define ggm_seed_rng_lr_ext_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_ref) +#define ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_avx2) +#define ggm_seed_rng_lr_ext_cat1_aes128_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat1_aes128_x4_ref) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_avx2) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_avx2) +#define ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat3_rijndael256_x4_ref) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_avx2) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_ref) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_avx2) +#define ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(ggm_seed_rng_lr_ext_cat5_rijndael256_x4_ref) +#define grey_of SDITH_NAMESPACE_FOR_LIBOQS(grey_of) +#define hidden_leaves_indexes SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes) +#define hidden_leaves_indexes2 SDITH_NAMESPACE_FOR_LIBOQS(hidden_leaves_indexes2) +#define inv_grey_of SDITH_NAMESPACE_FOR_LIBOQS(inv_grey_of) +#define keygen_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_avx) +#define keygen_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_aes128_cat1_ref) +#define keygen_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_avx) +#define keygen_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat3_ref) +#define keygen_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_avx) +#define keygen_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_init_rijndael256_cat5_ref) +#define keygen_rng_next_u32_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_avx) +#define keygen_rng_next_u32_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_aes128_cat1_ref) +#define keygen_rng_next_u32_rijndael256_avx SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_avx) +#define keygen_rng_next_u32_rijndael256_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_next_u32_rijndael256_ref) +#define keygen_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_aes128_cat1_ref) +#define keygen_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(keygen_rng_release_noop) +#define map_public_key SDITH_NAMESPACE_FOR_LIBOQS(map_public_key) +#define map_secret_key SDITH_NAMESPACE_FOR_LIBOQS(map_secret_key) +#define map_signature SDITH_NAMESPACE_FOR_LIBOQS(map_signature) +#define mask_eq_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_avx) +#define mask_eq_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_eq_ct_ref) +#define mask_lt_ct_avx SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_avx) +#define mask_lt_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(mask_lt_ct_ref) +#define matrix_f2_times_vector_flambda_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_avx2) +#define matrix_f2_times_vector_flambda_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_f2_times_vector_flambda_ref) +#define matrix_rng_get_row_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_avx) +#define matrix_rng_get_row_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_aes128_cat1_ref) +#define matrix_rng_get_row_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_avx) +#define matrix_rng_get_row_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat3_ref) +#define matrix_rng_get_row_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_avx) +#define matrix_rng_get_row_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_row_rijndael256_cat5_ref) +#define matrix_rng_get_rows_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_avx) +#define matrix_rng_get_rows_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_aes128_cat1_ref) +#define matrix_rng_get_rows_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_avx) +#define matrix_rng_get_rows_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat3_ref) +#define matrix_rng_get_rows_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_avx) +#define matrix_rng_get_rows_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_get_rows_rijndael256_cat5_ref) +#define matrix_rng_init_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_avx) +#define matrix_rng_init_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_aes128_cat1_ref) +#define matrix_rng_init_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_avx) +#define matrix_rng_init_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat3_ref) +#define matrix_rng_init_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_avx) +#define matrix_rng_init_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_init_rijndael256_cat5_ref) +#define matrix_rng_preprocess_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_avx) +#define matrix_rng_preprocess_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_aes128_cat1_ref) +#define matrix_rng_preprocess_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_avx) +#define matrix_rng_preprocess_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat3_ref) +#define matrix_rng_preprocess_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_avx) +#define matrix_rng_preprocess_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_preprocess_chall_rijndael256_cat5_ref) +#define matrix_rng_release_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_aes128_cat1_ref) +#define matrix_rng_release_noop SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_release_noop) +#define matrix_rng_rows_times_chall_aes128_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_avx) +#define matrix_rng_rows_times_chall_aes128_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_aes128_cat1_ref) +#define matrix_rng_rows_times_chall_rijndael256_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_avx) +#define matrix_rng_rows_times_chall_rijndael256_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat3_ref) +#define matrix_rng_rows_times_chall_rijndael256_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_avx) +#define matrix_rng_rows_times_chall_rijndael256_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_rng_rows_times_chall_rijndael256_cat5_ref) +#define matrix_vector_product_f2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_avx2) +#define matrix_vector_product_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(matrix_vector_product_f2_ref) +#define partition SDITH_NAMESPACE_FOR_LIBOQS(partition) +#define prepare_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(prepare_extseed_buf_cat1_aes128_ref) +#define proofow_grind_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_avx) +#define proofow_grind_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat1_ref) +#define proofow_grind_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_avx) +#define proofow_grind_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat3_ref) +#define proofow_grind_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_avx) +#define proofow_grind_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_cipher_cat5_ref) +#define proofow_grind_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1) +#define proofow_grind_w_shake_cat1_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat1_4way) +#define proofow_grind_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3) +#define proofow_grind_w_shake_cat3_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat3_4way) +#define proofow_grind_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5) +#define proofow_grind_w_shake_cat5_4way SDITH_NAMESPACE_FOR_LIBOQS(proofow_grind_w_shake_cat5_4way) +#define proofow_init_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_avx) +#define proofow_init_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat1_ref) +#define proofow_init_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_avx) +#define proofow_init_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat3_ref) +#define proofow_init_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_avx) +#define proofow_init_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_cipher_cat5_ref) +#define proofow_init_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat1) +#define proofow_init_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat3) +#define proofow_init_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_init_shake_cat5) +#define proofow_release_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_cipher_cat1_ref) +#define proofow_release_noop SDITH_NAMESPACE_FOR_LIBOQS(proofow_release_noop) +#define proofow_verify_w_cipher_cat1_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_avx) +#define proofow_verify_w_cipher_cat1_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat1_ref) +#define proofow_verify_w_cipher_cat3_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_avx) +#define proofow_verify_w_cipher_cat3_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat3_ref) +#define proofow_verify_w_cipher_cat5_avx SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_avx) +#define proofow_verify_w_cipher_cat5_ref SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_cipher_cat5_ref) +#define proofow_verify_w_shake_cat1 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat1) +#define proofow_verify_w_shake_cat3 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat3) +#define proofow_verify_w_shake_cat5 SDITH_NAMESPACE_FOR_LIBOQS(proofow_verify_w_shake_cat5) +#define prover_cst_check_unitary_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref) +#define prover_cst_check_unitary_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_check_unitary_gate_ct_ref_tmp_bytes) +#define prover_cst_mux_circuit_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref) +#define prover_cst_mux_circuit_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_mux_circuit_ct_ref_tmp_bytes) +#define prover_cst_vole_check_zero_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_check_zero_gate_ct_ref) +#define prover_cst_vole_echelon_pow2_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_echelon_pow2_ct_ref) +#define prover_cst_vole_mul_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_mul_gate_ct_ref) +#define prover_cst_vole_packed_secret_input_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_packed_secret_input_ct_ref) +#define prover_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_ctrl_bytes) +#define prover_cst_vole_qary_mux_gate_ct_f2_prep SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_prep) +#define prover_cst_vole_qary_mux_gate_ct_f2_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref) +#define prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_f2_ref_tmp_bytes) +#define prover_cst_vole_qary_mux_gate_ct_naive SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_naive) +#define prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_gate_ct_ref_tmp_bytes) +#define prover_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_qary_mux_prepare_ctrl) +#define prover_cst_vole_xor_gate_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_cst_vole_xor_gate_ct_ref) +#define prover_f2_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_std_to_cst_vole_ct_ref) +#define prover_f2_to_flambda_deg1_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_f2_to_flambda_deg1_std_vole_ct_ref) +#define prover_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_deg1_to_degd_vole_ref) +#define prover_flambda_degd_std_to_cst_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_flambda_degd_std_to_cst_vole_ct_ref) +#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_ref) +#define prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(prover_generate_midsize_grey_vole_from_seeds_bfs_ct_tmp_bytes) +#define prover_midsize_to_fullsize_std_vole_ct_ref SDITH_NAMESPACE_FOR_LIBOQS(prover_midsize_to_fullsize_std_vole_ct_ref) +#define prover_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(prover_vole_consistency_check) +#define quickSort SDITH_NAMESPACE_FOR_LIBOQS(quickSort) +#define release_extseed_buf_cat1_aes128_ref SDITH_NAMESPACE_FOR_LIBOQS(release_extseed_buf_cat1_aes128_ref) +#define rijndael256_ctrle_nocarry_1block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_avx2) +#define rijndael256_ctrle_nocarry_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_1block_ref) +#define rijndael256_ctrle_nocarry_2block_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_avx2) +#define rijndael256_ctrle_nocarry_2block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_2block_ref) +#define rijndael256_ctrle_nocarry_nblocks_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_avx2) +#define rijndael256_ctrle_nocarry_nblocks_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_ctrle_nocarry_nblocks_ref) +#define rijndael256_encrypt_1block_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_encrypt_1block_ref) +#define rijndael256_key_schedule_avx SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_avx) +#define rijndael256_key_schedule_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_ref) +#define rijndael256_key_schedule_x1_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_avx2) +#define rijndael256_key_schedule_x1_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x1_ref) +#define rijndael256_key_schedule_x2_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_avx2) +#define rijndael256_key_schedule_x2_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x2_ref) +#define rijndael256_key_schedule_x3_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_avx2) +#define rijndael256_key_schedule_x3_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x3_ref) +#define rijndael256_key_schedule_x4_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_avx2) +#define rijndael256_key_schedule_x4_ref SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_key_schedule_x4_ref) +#define rijndael256_keyexp_x1_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x1_enclast) +#define rijndael256_keyexp_x2_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x2_enclast) +#define rijndael256_keyexp_x3_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x3_enclast) +#define rijndael256_keyexp_x4_enclast SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_keyexp_x4_enclast) +#define rijndael256_proofow_grind_avx2 SDITH_NAMESPACE_FOR_LIBOQS(rijndael256_proofow_grind_avx2) +#define rijndaelEncrypt SDITH_NAMESPACE_FOR_LIBOQS(rijndaelEncrypt) +#define rijndaelKeySetupEnc SDITH_NAMESPACE_FOR_LIBOQS(rijndaelKeySetupEnc) +#define rsd_encode_solution_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_encode_solution_ref) +#define rsd_expand_public_key_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_expand_public_key_ref) +#define rsd_generate_random_instance_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_ref) +#define rsd_generate_random_instance_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_generate_random_instance_tmp_bytes) +#define rsd_public_key_times_challenge_ref SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_ref) +#define rsd_public_key_times_challenge_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(rsd_public_key_times_challenge_tmp_bytes) +#define sdith_keygen SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen) +#define sdith_keygen_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_entropy_bytes) +#define sdith_keygen_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_keygen_tmp_bytes) +#define sdith_public_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_public_key_bytes) +#define sdith_secret_key_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_secret_key_bytes) +#define sdith_sign SDITH_NAMESPACE_FOR_LIBOQS(sdith_sign) +#define sdith_signature_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_bytes) +#define sdith_signature_entropy_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_entropy_bytes) +#define sdith_signature_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_signature_tmp_bytes) +#define sdith_verify SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify) +#define sdith_verify_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(sdith_verify_tmp_bytes) +#define swap SDITH_NAMESPACE_FOR_LIBOQS(swap) +#define tmp_bytes_init SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_init) +#define tmp_bytes_reserve_call SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_call) +#define tmp_bytes_reserve_local_var SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var) +#define tmp_bytes_reserve_local_var_aligned SDITH_NAMESPACE_FOR_LIBOQS(tmp_bytes_reserve_local_var_aligned) +#define transpose_128_128_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_naive) +#define transpose_128_128_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_128_ref) +#define transpose_128_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_naive) +#define transpose_128_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_128_L_ref) +#define transpose_192_192_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_naive) +#define transpose_192_192_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_192_ref) +#define transpose_192_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_naive) +#define transpose_192_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_192_L_ref) +#define transpose_256_256_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_naive) +#define transpose_256_256_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_256_ref) +#define transpose_256_L_naive SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_naive) +#define transpose_256_L_ref SDITH_NAMESPACE_FOR_LIBOQS(transpose_256_L_ref) +#define verifier_cst_check_unitary_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref) +#define verifier_cst_check_unitary_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_check_unitary_gate_ref_tmp_bytes) +#define verifier_cst_mux_circuit_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref) +#define verifier_cst_mux_circuit_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_mux_circuit_ref_tmp_bytes) +#define verifier_cst_vole_check_zero_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_check_zero_gate_ref) +#define verifier_cst_vole_echelon_pow2_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_echelon_pow2_ref) +#define verifier_cst_vole_mul_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_mul_gate_ref) +#define verifier_cst_vole_packed_secret_input_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_packed_secret_input_ref) +#define verifier_cst_vole_qary_mux_ctrl_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_ctrl_bytes) +#define verifier_cst_vole_qary_mux_gate_prep SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_prep) +#define verifier_cst_vole_qary_mux_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref) +#define verifier_cst_vole_qary_mux_gate_ref_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_gate_ref_tmp_bytes) +#define verifier_cst_vole_qary_mux_prepare_ctrl SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_qary_mux_prepare_ctrl) +#define verifier_cst_vole_xor_gate_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_cst_vole_xor_gate_ref) +#define verifier_f2_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_std_to_cst_vole_ref) +#define verifier_f2_to_flambda_deg1_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_f2_to_flambda_deg1_std_vole_ref) +#define verifier_flambda_deg1_to_degd_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_deg1_to_degd_vole_ref) +#define verifier_flambda_degd_std_to_cst_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_flambda_degd_std_to_cst_vole_ref) +#define verifier_midsize_to_fullsize_std_vole_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_midsize_to_fullsize_std_vole_ref) +#define verifier_open_midsize_grey_vole_from_seeds_bfs_ref SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_ref) +#define verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes SDITH_NAMESPACE_FOR_LIBOQS(verifier_open_midsize_grey_vole_from_seeds_bfs_tmp_bytes) +#define verifier_vole_consistency_check SDITH_NAMESPACE_FOR_LIBOQS(verifier_vole_consistency_check) +#define vole_consistency_check_matrix_ncols SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_ncols) +#define vole_consistency_check_matrix_nrows SDITH_NAMESPACE_FOR_LIBOQS(vole_consistency_check_matrix_nrows) +#define vole_parameters_init SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init) +#define vole_parameters_init_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_avx) +#define vole_parameters_init_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_ref) +#define vole_parameters_init_with_variant SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant) +#define vole_parameters_init_with_variant_avx SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_avx) +#define vole_parameters_init_with_variant_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_parameters_init_with_variant_ref) +#define vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_nocarry_avx2) +#define vole_rng_ext_cat1_aes128_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat1_aes128_ctrle_ref) +#define vole_rng_ext_cat3_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_avx2) +#define vole_rng_ext_cat3_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat3_rijndael256_ctrle_ref) +#define vole_rng_ext_cat5_rijndael256_ctrle_avx2 SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_avx2) +#define vole_rng_ext_cat5_rijndael256_ctrle_ref SDITH_NAMESPACE_FOR_LIBOQS(vole_rng_ext_cat5_rijndael256_ctrle_ref) +#define xof_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake128) +#define xof_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_ctx_release_shake256) +#define xof_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake128) +#define xof_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_and_output_shake256) +#define xof_finalize_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake128) +#define xof_finalize_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_finalize_shake256) +#define xof_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake128) +#define xof_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_and_seed_shake256) +#define xof_init_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake128) +#define xof_init_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_init_shake256) +#define xof_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake128) +#define xof_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_output_shake256) +#define xof_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake128) +#define xof_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_seed_shake256) +#define xof_vector_ctx_bytes_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake128) +#define xof_vector_ctx_bytes_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_bytes_shake256) +#define xof_vector_ctx_release_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake128) +#define xof_vector_ctx_release_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_ctx_release_shake256) +#define xof_vector_finalize_and_output_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake128) +#define xof_vector_finalize_and_output_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_finalize_and_output_shake256) +#define xof_vector_init_and_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake128) +#define xof_vector_init_and_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_init_and_seed_shake256) +#define xof_vector_seed_shake128 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake128) +#define xof_vector_seed_shake256 SDITH_NAMESPACE_FOR_LIBOQS(xof_vector_seed_shake256) +#define xorto_kappabit_uint SDITH_NAMESPACE_FOR_LIBOQS(xorto_kappabit_uint) + +#endif // APPLY_NAMESPACE + +#endif // SDITH_NAMESPACE_H diff --git a/src/sig/sdith/sdith_sdith_common_headers/sdith_signature.h b/src/sig/sdith/sdith_sdith_common_headers/sdith_signature.h new file mode 100644 index 0000000000..59b6e51801 --- /dev/null +++ b/src/sig/sdith/sdith_sdith_common_headers/sdith_signature.h @@ -0,0 +1,132 @@ +#ifndef SDITH_SIGNATURE_H +#define SDITH_SIGNATURE_H + +// This header contains the main SDiTH signature + +#include "commons.h" + +/** signature main parameters */ +typedef struct signature_parameters_t { + uint64_t lambda; + uint64_t kappa; + uint64_t tau; + uint64_t target_topen; + uint64_t proofow_w; + uint64_t rsd_w; + uint64_t rsd_n; + uint64_t mux_depth; + uint64_t mux_arities[8]; + proofow_variant_t proofow_variant; +} signature_parameters; + +/** Default parameter sets */ +EXPORT_DECL const signature_parameters CAT1_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_SHORT_PARAMETERS; +EXPORT_DECL const signature_parameters CAT1_FAST_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_FAST_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_FAST_PARAMETERS; +/** Default parameter sets for official variants */ +EXPORT_DECL const signature_parameters CAT1_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_SHORT_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT1_FAST_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT3_FAST_CIPHERPOW_PARAMETERS; +EXPORT_DECL const signature_parameters CAT5_FAST_CIPHERPOW_PARAMETERS; + +/** @brief Number of bytes of the secret key (in the sense keypair) */ +EXPORT uint64_t sdith_secret_key_bytes(const signature_parameters* sig_params); +/** @brief Number of bytes of the public key */ +EXPORT uint64_t sdith_public_key_bytes(const signature_parameters* sig_params); +/** @brief Number of bytes of a sdith signature */ +EXPORT uint64_t sdith_signature_bytes(const signature_parameters* sig_params); + +/** + * @brief Number of pure entropy bytes to provide to the keygen algorithm + * These bytes should be generated using a secure random generator, a random device, or something like /dev/urandom. + * During tests purposes, fixing the entropy makes the algorithm deterministic + */ +EXPORT uint64_t sdith_keygen_entropy_bytes(const signature_parameters* sig_params); + +/** + * @brief size of the scratch space to pass to the keygen function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_keygen_tmp_bytes(const signature_parameters* sig_params); + +/** + * @brief SDiTH Key generator + * @param sig_params parameter set + * @param skey [out] secret key (i.e. keypair) + * @param pkey [out] public key (i.e. keypair) + * @param entropy [in] entropy bytes + * @param tmp_space [tmp] scratch space -- holds secret key material on + * return (the raw solution): the caller must scrub it. + * + * Constant-time with respect to the generated secret key, save for the + * rejection loop of the position sampler (whose trip count is independent of + * the accepted positions). This holds only for the avx parameter table: the ref + * ct helpers are the readable definitions, not hardened ones. + */ +EXPORT void sdith_keygen(const signature_parameters* sig_params, // + void* skey, // out: secret key + void* pkey, // out: public key + const void* entropy, // in: entropy + uint8_t* tmp_space); + +/** + * @brief Number of pure entropy bytes to provide to the signature algorithm + * These bytes should be generated using a secure random generator, a random device, or something like /dev/urandom. + * During tests purposes, fixing the entropy makes the algorithm deterministic + */ +EXPORT uint64_t sdith_signature_entropy_bytes(const signature_parameters* sig_params); + +/** + * @brief size of the scratch space to pass to the signature function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_signature_tmp_bytes(const signature_parameters* sig_params); + +/** + * SDiTH signature + * @param sig_params parameter set + * @param signature [out] digital signature + * @param message [in] message to sign + * @param message_bytes [in] number of bytes of the message + * @param skey [in] secret key + * @param entropy [in] entropy bytes + * @param tmp_space [tmp] scratch space + */ +EXPORT void sdith_sign(const signature_parameters* sig_params, // + void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* skey, // secret key + const void* entropy, // in: entropy + uint8_t* tmp_space); + +/** + * @brief size of the scratch space to pass to the signature function + * The signature function does not use any heap allocation: temporaries that are too large to fit + * on the stack are going to be allocated in this scratch space. + */ +EXPORT uint64_t sdith_verify_tmp_bytes(const signature_parameters* sig_params); + +/** + * Signature verification function + * @param sig_params SDiTH parameter set + * @param signature [in] signature to verify + * @param message [in] message that was signed + * @param message_bytes [in] size of the message + * @param pkey [in] public key + * @param tmp_space [tmp] scratch space + * @return + */ +EXPORT uint8_t sdith_verify(const signature_parameters* sig_params, // + const void* signature, // out: signature + const void* message, uint64_t message_bytes, // in: message + const void* pkey, // secret key + uint8_t* tmp_space); + +#endif // SDITH_SIGNATURE_H diff --git a/src/sig/sdith/sig_sdith.h b/src/sig/sdith/sig_sdith.h new file mode 100644 index 0000000000..6c92ce2c47 --- /dev/null +++ b/src/sig/sdith/sig_sdith.h @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT + +#ifndef OQS_SIG_SDITH_H +#define OQS_SIG_SDITH_H + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short) +#define OQS_SIG_sdith_l1_gf2_short_length_public_key 70 +#define OQS_SIG_sdith_l1_gf2_short_length_secret_key 147 +#define OQS_SIG_sdith_l1_gf2_short_length_signature 3721 + +OQS_SIG *OQS_SIG_sdith_l1_gf2_short_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow) +#define OQS_SIG_sdith_l1_gf2_short_cipherpow_length_public_key 70 +#define OQS_SIG_sdith_l1_gf2_short_cipherpow_length_secret_key 147 +#define OQS_SIG_sdith_l1_gf2_short_cipherpow_length_signature 3721 + +OQS_SIG *OQS_SIG_sdith_l1_gf2_short_cipherpow_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast) +#define OQS_SIG_sdith_l1_gf2_fast_length_public_key 70 +#define OQS_SIG_sdith_l1_gf2_fast_length_secret_key 147 +#define OQS_SIG_sdith_l1_gf2_fast_length_signature 4914 + +OQS_SIG *OQS_SIG_sdith_l1_gf2_fast_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow) +#define OQS_SIG_sdith_l1_gf2_fast_cipherpow_length_public_key 70 +#define OQS_SIG_sdith_l1_gf2_fast_cipherpow_length_secret_key 147 +#define OQS_SIG_sdith_l1_gf2_fast_cipherpow_length_signature 4643 + +OQS_SIG *OQS_SIG_sdith_l1_gf2_fast_cipherpow_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short) +#define OQS_SIG_sdith_l3_gf2_short_length_public_key 98 +#define OQS_SIG_sdith_l3_gf2_short_length_secret_key 208 +#define OQS_SIG_sdith_l3_gf2_short_length_signature 8484 + +OQS_SIG *OQS_SIG_sdith_l3_gf2_short_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow) +#define OQS_SIG_sdith_l3_gf2_short_cipherpow_length_public_key 98 +#define OQS_SIG_sdith_l3_gf2_short_cipherpow_length_secret_key 208 +#define OQS_SIG_sdith_l3_gf2_short_cipherpow_length_signature 8484 + +OQS_SIG *OQS_SIG_sdith_l3_gf2_short_cipherpow_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast) +#define OQS_SIG_sdith_l3_gf2_fast_length_public_key 98 +#define OQS_SIG_sdith_l3_gf2_fast_length_secret_key 208 +#define OQS_SIG_sdith_l3_gf2_fast_length_signature 10852 + +OQS_SIG *OQS_SIG_sdith_l3_gf2_fast_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow) +#define OQS_SIG_sdith_l3_gf2_fast_cipherpow_length_public_key 98 +#define OQS_SIG_sdith_l3_gf2_fast_cipherpow_length_secret_key 208 +#define OQS_SIG_sdith_l3_gf2_fast_cipherpow_length_signature 10452 + +OQS_SIG *OQS_SIG_sdith_l3_gf2_fast_cipherpow_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short) +#define OQS_SIG_sdith_l5_gf2_short_length_public_key 132 +#define OQS_SIG_sdith_l5_gf2_short_length_secret_key 275 +#define OQS_SIG_sdith_l5_gf2_short_length_signature 15147 + +OQS_SIG *OQS_SIG_sdith_l5_gf2_short_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow) +#define OQS_SIG_sdith_l5_gf2_short_cipherpow_length_public_key 132 +#define OQS_SIG_sdith_l5_gf2_short_cipherpow_length_secret_key 275 +#define OQS_SIG_sdith_l5_gf2_short_cipherpow_length_signature 15147 + +OQS_SIG *OQS_SIG_sdith_l5_gf2_short_cipherpow_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast) +#define OQS_SIG_sdith_l5_gf2_fast_length_public_key 132 +#define OQS_SIG_sdith_l5_gf2_fast_length_secret_key 275 +#define OQS_SIG_sdith_l5_gf2_fast_length_signature 19144 + +OQS_SIG *OQS_SIG_sdith_l5_gf2_fast_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow) +#define OQS_SIG_sdith_l5_gf2_fast_cipherpow_length_public_key 132 +#define OQS_SIG_sdith_l5_gf2_fast_cipherpow_length_secret_key 275 +#define OQS_SIG_sdith_l5_gf2_fast_cipherpow_length_signature 19144 + +OQS_SIG *OQS_SIG_sdith_l5_gf2_fast_cipherpow_new(void); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *secret_key); +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx, size_t ctxlen, const uint8_t *public_key); +#endif + +#endif diff --git a/src/sig/sdith/sig_sdith_l1_gf2_fast.c b/src/sig/sdith/sig_sdith_l1_gf2_fast.c new file mode 100644 index 0000000000..4ca6de7983 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l1_gf2_fast.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast) +OQS_SIG *OQS_SIG_sdith_l1_gf2_fast_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l1_gf2_fast; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l1_gf2_fast_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l1_gf2_fast_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l1_gf2_fast_length_signature; + + sig->keypair = OQS_SIG_sdith_l1_gf2_fast_keypair; + sig->sign = OQS_SIG_sdith_l1_gf2_fast_sign; + sig->verify = OQS_SIG_sdith_l1_gf2_fast_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l1_gf2_fast_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l1_gf2_fast_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2) +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_fast_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_fast_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l1_gf2_fast_cipherpow.c b/src/sig/sdith/sig_sdith_l1_gf2_fast_cipherpow.c new file mode 100644 index 0000000000..a974daae88 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l1_gf2_fast_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow) +OQS_SIG *OQS_SIG_sdith_l1_gf2_fast_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l1_gf2_fast_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l1_gf2_fast_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l1_gf2_fast_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l1_gf2_fast_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_l1_gf2_fast_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign; + sig->verify = OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_fast_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_fast_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l1_gf2_short.c b/src/sig/sdith/sig_sdith_l1_gf2_short.c new file mode 100644 index 0000000000..61cfdb86bb --- /dev/null +++ b/src/sig/sdith/sig_sdith_l1_gf2_short.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short) +OQS_SIG *OQS_SIG_sdith_l1_gf2_short_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l1_gf2_short; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l1_gf2_short_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l1_gf2_short_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l1_gf2_short_length_signature; + + sig->keypair = OQS_SIG_sdith_l1_gf2_short_keypair; + sig->sign = OQS_SIG_sdith_l1_gf2_short_sign; + sig->verify = OQS_SIG_sdith_l1_gf2_short_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l1_gf2_short_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l1_gf2_short_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2) +extern int oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_short_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_short_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l1_gf2_short_cipherpow.c b/src/sig/sdith/sig_sdith_l1_gf2_short_cipherpow.c new file mode 100644 index 0000000000..fb3f1cc0a0 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l1_gf2_short_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow) +OQS_SIG *OQS_SIG_sdith_l1_gf2_short_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l1_gf2_short_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l1_gf2_short_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l1_gf2_short_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l1_gf2_short_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_l1_gf2_short_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_l1_gf2_short_cipherpow_sign; + sig->verify = OQS_SIG_sdith_l1_gf2_short_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l1_gf2_short_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l1_gf2_short_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l1_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_short_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l1_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l1_gf2_short_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l3_gf2_fast.c b/src/sig/sdith/sig_sdith_l3_gf2_fast.c new file mode 100644 index 0000000000..5c67367289 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l3_gf2_fast.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast) +OQS_SIG *OQS_SIG_sdith_l3_gf2_fast_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l3_gf2_fast; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l3_gf2_fast_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l3_gf2_fast_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l3_gf2_fast_length_signature; + + sig->keypair = OQS_SIG_sdith_l3_gf2_fast_keypair; + sig->sign = OQS_SIG_sdith_l3_gf2_fast_sign; + sig->verify = OQS_SIG_sdith_l3_gf2_fast_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l3_gf2_fast_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l3_gf2_fast_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2) +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_fast_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_fast_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l3_gf2_fast_cipherpow.c b/src/sig/sdith/sig_sdith_l3_gf2_fast_cipherpow.c new file mode 100644 index 0000000000..e344685357 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l3_gf2_fast_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow) +OQS_SIG *OQS_SIG_sdith_l3_gf2_fast_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l3_gf2_fast_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l3_gf2_fast_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l3_gf2_fast_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l3_gf2_fast_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_l3_gf2_fast_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign; + sig->verify = OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_fast_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_fast_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l3_gf2_short.c b/src/sig/sdith/sig_sdith_l3_gf2_short.c new file mode 100644 index 0000000000..f11774382d --- /dev/null +++ b/src/sig/sdith/sig_sdith_l3_gf2_short.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short) +OQS_SIG *OQS_SIG_sdith_l3_gf2_short_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l3_gf2_short; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l3_gf2_short_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l3_gf2_short_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l3_gf2_short_length_signature; + + sig->keypair = OQS_SIG_sdith_l3_gf2_short_keypair; + sig->sign = OQS_SIG_sdith_l3_gf2_short_sign; + sig->verify = OQS_SIG_sdith_l3_gf2_short_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l3_gf2_short_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l3_gf2_short_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2) +extern int oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_short_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_short_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l3_gf2_short_cipherpow.c b/src/sig/sdith/sig_sdith_l3_gf2_short_cipherpow.c new file mode 100644 index 0000000000..403bafcc67 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l3_gf2_short_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow) +OQS_SIG *OQS_SIG_sdith_l3_gf2_short_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l3_gf2_short_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l3_gf2_short_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l3_gf2_short_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l3_gf2_short_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_l3_gf2_short_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_l3_gf2_short_cipherpow_sign; + sig->verify = OQS_SIG_sdith_l3_gf2_short_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l3_gf2_short_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l3_gf2_short_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l3_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_short_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l3_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l3_gf2_short_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l5_gf2_fast.c b/src/sig/sdith/sig_sdith_l5_gf2_fast.c new file mode 100644 index 0000000000..b79bc02f06 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l5_gf2_fast.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast) +OQS_SIG *OQS_SIG_sdith_l5_gf2_fast_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l5_gf2_fast; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l5_gf2_fast_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l5_gf2_fast_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l5_gf2_fast_length_signature; + + sig->keypair = OQS_SIG_sdith_l5_gf2_fast_keypair; + sig->sign = OQS_SIG_sdith_l5_gf2_fast_sign; + sig->verify = OQS_SIG_sdith_l5_gf2_fast_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l5_gf2_fast_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l5_gf2_fast_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2) +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_fast_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_fast_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l5_gf2_fast_cipherpow.c b/src/sig/sdith/sig_sdith_l5_gf2_fast_cipherpow.c new file mode 100644 index 0000000000..01537c3e11 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l5_gf2_fast_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow) +OQS_SIG *OQS_SIG_sdith_l5_gf2_fast_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l5_gf2_fast_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l5_gf2_fast_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l5_gf2_fast_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l5_gf2_fast_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_l5_gf2_fast_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign; + sig->verify = OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_fast_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_fast_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l5_gf2_short.c b/src/sig/sdith/sig_sdith_l5_gf2_short.c new file mode 100644 index 0000000000..cc773f4d6c --- /dev/null +++ b/src/sig/sdith/sig_sdith_l5_gf2_short.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short) +OQS_SIG *OQS_SIG_sdith_l5_gf2_short_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l5_gf2_short; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l5_gf2_short_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l5_gf2_short_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l5_gf2_short_length_signature; + + sig->keypair = OQS_SIG_sdith_l5_gf2_short_keypair; + sig->sign = OQS_SIG_sdith_l5_gf2_short_sign; + sig->verify = OQS_SIG_sdith_l5_gf2_short_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l5_gf2_short_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l5_gf2_short_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2) +extern int oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_short_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_short_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_l5_gf2_short_cipherpow.c b/src/sig/sdith/sig_sdith_l5_gf2_short_cipherpow.c new file mode 100644 index 0000000000..c3254bfb90 --- /dev/null +++ b/src/sig/sdith/sig_sdith_l5_gf2_short_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow) +OQS_SIG *OQS_SIG_sdith_l5_gf2_short_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_l5_gf2_short_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_l5_gf2_short_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_l5_gf2_short_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_l5_gf2_short_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_l5_gf2_short_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_l5_gf2_short_cipherpow_sign; + sig->verify = OQS_SIG_sdith_l5_gf2_short_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_l5_gf2_short_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_l5_gf2_short_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith_l5_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_short_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_l5_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_l5_gf2_short_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l1_gf2_fast.c b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_fast.c new file mode 100644 index 0000000000..c7505c691f --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_fast.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast) +OQS_SIG *OQS_SIG_sdith_sdith3_l1_gf2_fast_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l1_gf2_fast; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l1_gf2_fast_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l1_gf2_fast_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l1_gf2_fast_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l1_gf2_fast_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l1_gf2_fast_sign; + sig->verify = OQS_SIG_sdith_sdith3_l1_gf2_fast_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_fast_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_fast_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_avx2) +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_fast_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_fast_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l1_gf2_fast_cipherpow.c b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_fast_cipherpow.c new file mode 100644 index 0000000000..86cd385fec --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_fast_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_cipherpow) +OQS_SIG *OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l1_gf2_fast_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_sign; + sig->verify = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_fast_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l1_gf2_short.c b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_short.c new file mode 100644 index 0000000000..ab5c6076fb --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_short.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short) +OQS_SIG *OQS_SIG_sdith_sdith3_l1_gf2_short_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l1_gf2_short; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l1_gf2_short_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l1_gf2_short_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l1_gf2_short_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l1_gf2_short_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l1_gf2_short_sign; + sig->verify = OQS_SIG_sdith_sdith3_l1_gf2_short_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_short_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_short_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_avx2) +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_short_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_short_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l1_gf2_short_cipherpow.c b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_short_cipherpow.c new file mode 100644 index 0000000000..e1ecc2f77d --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l1_gf2_short_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_cipherpow) +OQS_SIG *OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l1_gf2_short_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 1; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_sign; + sig->verify = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l1_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l1_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l1_gf2_short_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l3_gf2_fast.c b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_fast.c new file mode 100644 index 0000000000..0700fc936c --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_fast.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast) +OQS_SIG *OQS_SIG_sdith_sdith3_l3_gf2_fast_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l3_gf2_fast; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l3_gf2_fast_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l3_gf2_fast_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l3_gf2_fast_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l3_gf2_fast_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l3_gf2_fast_sign; + sig->verify = OQS_SIG_sdith_sdith3_l3_gf2_fast_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_fast_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_fast_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_avx2) +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_fast_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_fast_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l3_gf2_fast_cipherpow.c b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_fast_cipherpow.c new file mode 100644 index 0000000000..960091119c --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_fast_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_cipherpow) +OQS_SIG *OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l3_gf2_fast_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_sign; + sig->verify = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_fast_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l3_gf2_short.c b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_short.c new file mode 100644 index 0000000000..802b372e00 --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_short.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short) +OQS_SIG *OQS_SIG_sdith_sdith3_l3_gf2_short_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l3_gf2_short; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l3_gf2_short_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l3_gf2_short_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l3_gf2_short_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l3_gf2_short_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l3_gf2_short_sign; + sig->verify = OQS_SIG_sdith_sdith3_l3_gf2_short_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_short_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_short_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_avx2) +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_short_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_short_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l3_gf2_short_cipherpow.c b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_short_cipherpow.c new file mode 100644 index 0000000000..92a67143e4 --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l3_gf2_short_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_cipherpow) +OQS_SIG *OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l3_gf2_short_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 3; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_sign; + sig->verify = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l3_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l3_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l3_gf2_short_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l5_gf2_fast.c b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_fast.c new file mode 100644 index 0000000000..b1544c6aca --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_fast.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast) +OQS_SIG *OQS_SIG_sdith_sdith3_l5_gf2_fast_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l5_gf2_fast; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l5_gf2_fast_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l5_gf2_fast_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l5_gf2_fast_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l5_gf2_fast_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l5_gf2_fast_sign; + sig->verify = OQS_SIG_sdith_sdith3_l5_gf2_fast_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_fast_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_fast_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_avx2) +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_fast_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_fast_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l5_gf2_fast_cipherpow.c b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_fast_cipherpow.c new file mode 100644 index 0000000000..688ca789a9 --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_fast_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_cipherpow) +OQS_SIG *OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l5_gf2_fast_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_sign; + sig->verify = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_fast_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_fast_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l5_gf2_short.c b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_short.c new file mode 100644 index 0000000000..fcf97664a0 --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_short.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short) +OQS_SIG *OQS_SIG_sdith_sdith3_l5_gf2_short_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l5_gf2_short; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l5_gf2_short_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l5_gf2_short_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l5_gf2_short_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l5_gf2_short_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l5_gf2_short_sign; + sig->verify = OQS_SIG_sdith_sdith3_l5_gf2_short_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_short_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_short_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_avx2) +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_short_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_short_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sdith/sig_sdith_sdith3_l5_gf2_short_cipherpow.c b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_short_cipherpow.c new file mode 100644 index 0000000000..a07105029a --- /dev/null +++ b/src/sig/sdith/sig_sdith_sdith3_l5_gf2_short_cipherpow.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_cipherpow) +OQS_SIG *OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_new(void) { + + OQS_SIG *sig = OQS_MEM_calloc(1, sizeof(OQS_SIG)); + if (sig == NULL) { + return NULL; + } + sig->method_name = OQS_SIG_alg_sdith_sdith3_l5_gf2_short_cipherpow; + sig->alg_version = "round3"; + + sig->claimed_nist_level = 5; + sig->euf_cma = true; + sig->suf_cma = false; + sig->sig_with_ctx_support = false; + + sig->length_public_key = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_length_public_key; + sig->length_secret_key = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_length_secret_key; + sig->length_signature = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_length_signature; + + sig->keypair = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_keypair; + sig->sign = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_sign; + sig->verify = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_verify; + sig->sign_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_sign_with_ctx_str; + sig->verify_with_ctx_str = OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_verify_with_ctx_str; + + return sig; +} + +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); + +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_cipherpow_avx2) +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_avx2_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_avx2_crypto_sign_sign(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk); +extern int oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_avx2_crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk); +#endif + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_keypair(uint8_t *public_key, uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_avx2_crypto_sign_keypair(public_key, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_keypair(public_key, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_sign(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *secret_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_avx2_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_sign(signature, signature_len, message, message_len, secret_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_verify(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *public_key) { +#if defined(OQS_ENABLE_SIG_sdith_sdith3_l5_gf2_short_cipherpow_avx2) +#if defined(OQS_DIST_BUILD) + if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2) && OQS_CPU_has_extension(OQS_CPU_EXT_AVX) && OQS_CPU_has_extension(OQS_CPU_EXT_AES) && OQS_CPU_has_extension(OQS_CPU_EXT_PCLMULQDQ)) { +#endif /* OQS_DIST_BUILD */ + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_avx2_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#if defined(OQS_DIST_BUILD) + } else { + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); + } +#endif /* OQS_DIST_BUILD */ +#else + return (OQS_STATUS) oqs_sig_pubapi_sdith3_l5_gf2_short_cipherpow_crypto_sign_verify(signature, signature_len, message, message_len, public_key); +#endif +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_sign_with_ctx_str(uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *secret_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_sign(signature, signature_len, message, message_len, secret_key); + } else { + return OQS_ERROR; + } +} + +OQS_API OQS_STATUS OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_verify_with_ctx_str(const uint8_t *message, size_t message_len, const uint8_t *signature, size_t signature_len, const uint8_t *ctx_str, size_t ctx_str_len, const uint8_t *public_key) { + if (ctx_str == NULL && ctx_str_len == 0) { + return OQS_SIG_sdith_sdith3_l5_gf2_short_cipherpow_verify(message, message_len, signature, signature_len, public_key); + } else { + return OQS_ERROR; + } +} +#endif diff --git a/src/sig/sig.c b/src/sig/sig.c index 2d8bcb30ce..def1e242b6 100644 --- a/src/sig/sig.c +++ b/src/sig/sig.c @@ -124,7 +124,19 @@ OQS_API const char *OQS_SIG_alg_identifier(size_t i) { OQS_SIG_alg_mqom_mqom3_cat5_gf16_short_ct, OQS_SIG_alg_mqom_mqom3_cat5_gf16_short_ot, OQS_SIG_alg_mqom_mqom3_cat5_gf2_shorter_ct, - OQS_SIG_alg_mqom_mqom3_cat5_gf2_shorter_ot,///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ALG_IDENTIFIER_END + OQS_SIG_alg_mqom_mqom3_cat5_gf2_shorter_ot, + OQS_SIG_alg_sdith_l1_gf2_short, + OQS_SIG_alg_sdith_l1_gf2_short_cipherpow, + OQS_SIG_alg_sdith_l1_gf2_fast, + OQS_SIG_alg_sdith_l1_gf2_fast_cipherpow, + OQS_SIG_alg_sdith_l3_gf2_short, + OQS_SIG_alg_sdith_l3_gf2_short_cipherpow, + OQS_SIG_alg_sdith_l3_gf2_fast, + OQS_SIG_alg_sdith_l3_gf2_fast_cipherpow, + OQS_SIG_alg_sdith_l5_gf2_short, + OQS_SIG_alg_sdith_l5_gf2_short_cipherpow, + OQS_SIG_alg_sdith_l5_gf2_fast, + OQS_SIG_alg_sdith_l5_gf2_fast_cipherpow,///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ALG_IDENTIFIER_END ///// OQS_COPY_FROM_SLH_DSA_FRAGMENT_ALGID_START OQS_SIG_alg_slh_dsa_pure_sha2_128s, OQS_SIG_alg_slh_dsa_pure_sha2_128f, @@ -1070,6 +1082,90 @@ OQS_API int OQS_SIG_alg_is_enabled(const char *method_name) { #else return 0; #endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_short)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_short + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_short_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_fast)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_fast + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_fast_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_short)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_short + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_short_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_fast)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_fast + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_fast_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_short)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_short + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_short_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_fast)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_fast + return 1; +#else + return 0; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_fast_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow + return 1; +#else + return 0; +#endif ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ENABLED_CASE_END ///// OQS_COPY_FROM_SLH_DSA_FRAGMENT_ENABLED_START } else if (0 == strcasecmp(method_name, OQS_SIG_alg_slh_dsa_pure_sha2_128s)) { @@ -2789,6 +2885,90 @@ OQS_API OQS_SIG *OQS_SIG_new(const char *method_name) { #else return NULL; #endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_short)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_short + return OQS_SIG_sdith_l1_gf2_short_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_short_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_short_cipherpow + return OQS_SIG_sdith_l1_gf2_short_cipherpow_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_fast)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_fast + return OQS_SIG_sdith_l1_gf2_fast_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l1_gf2_fast_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l1_gf2_fast_cipherpow + return OQS_SIG_sdith_l1_gf2_fast_cipherpow_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_short)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_short + return OQS_SIG_sdith_l3_gf2_short_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_short_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_short_cipherpow + return OQS_SIG_sdith_l3_gf2_short_cipherpow_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_fast)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_fast + return OQS_SIG_sdith_l3_gf2_fast_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l3_gf2_fast_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l3_gf2_fast_cipherpow + return OQS_SIG_sdith_l3_gf2_fast_cipherpow_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_short)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_short + return OQS_SIG_sdith_l5_gf2_short_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_short_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_short_cipherpow + return OQS_SIG_sdith_l5_gf2_short_cipherpow_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_fast)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_fast + return OQS_SIG_sdith_l5_gf2_fast_new(); +#else + return NULL; +#endif + + } else if (0 == strcasecmp(method_name, OQS_SIG_alg_sdith_l5_gf2_fast_cipherpow)) { +#ifdef OQS_ENABLE_SIG_sdith_l5_gf2_fast_cipherpow + return OQS_SIG_sdith_l5_gf2_fast_cipherpow_new(); +#else + return NULL; +#endif ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_NEW_CASE_END ///// OQS_COPY_FROM_SLH_DSA_FRAGMENT_SIGNEW_START } else if (0 == strcasecmp(method_name, OQS_SIG_alg_slh_dsa_pure_sha2_128s)) { diff --git a/src/sig/sig.h b/src/sig/sig.h index 8aec30bc8c..ad9d18c6cd 100644 --- a/src/sig/sig.h +++ b/src/sig/sig.h @@ -252,6 +252,30 @@ extern "C" { #define OQS_SIG_alg_mqom_mqom3_cat5_gf2_shorter_ct "mqom3_cat5_gf2_shorter_ct" /** Algorithm identifier for mqom3_cat5_gf2_shorter_ot */ #define OQS_SIG_alg_mqom_mqom3_cat5_gf2_shorter_ot "mqom3_cat5_gf2_shorter_ot" +/** Algorithm identifier for SDitH3-L1-gf2-short */ +#define OQS_SIG_alg_sdith_l1_gf2_short "SDitH3-L1-gf2-short" +/** Algorithm identifier for SDitH3-L1-gf2-short-cipherpow */ +#define OQS_SIG_alg_sdith_l1_gf2_short_cipherpow "SDitH3-L1-gf2-short-cipherpow" +/** Algorithm identifier for SDitH3-L1-gf2-fast */ +#define OQS_SIG_alg_sdith_l1_gf2_fast "SDitH3-L1-gf2-fast" +/** Algorithm identifier for SDitH3-L1-gf2-fast-cipherpow */ +#define OQS_SIG_alg_sdith_l1_gf2_fast_cipherpow "SDitH3-L1-gf2-fast-cipherpow" +/** Algorithm identifier for SDitH3-L3-gf2-short */ +#define OQS_SIG_alg_sdith_l3_gf2_short "SDitH3-L3-gf2-short" +/** Algorithm identifier for SDitH3-L3-gf2-short-cipherpow */ +#define OQS_SIG_alg_sdith_l3_gf2_short_cipherpow "SDitH3-L3-gf2-short-cipherpow" +/** Algorithm identifier for SDitH3-L3-gf2-fast */ +#define OQS_SIG_alg_sdith_l3_gf2_fast "SDitH3-L3-gf2-fast" +/** Algorithm identifier for SDitH3-L3-gf2-fast-cipherpow */ +#define OQS_SIG_alg_sdith_l3_gf2_fast_cipherpow "SDitH3-L3-gf2-fast-cipherpow" +/** Algorithm identifier for SDitH3-L5-gf2-short */ +#define OQS_SIG_alg_sdith_l5_gf2_short "SDitH3-L5-gf2-short" +/** Algorithm identifier for SDitH3-L5-gf2-short-cipherpow */ +#define OQS_SIG_alg_sdith_l5_gf2_short_cipherpow "SDitH3-L5-gf2-short-cipherpow" +/** Algorithm identifier for SDitH3-L5-gf2-fast */ +#define OQS_SIG_alg_sdith_l5_gf2_fast "SDitH3-L5-gf2-fast" +/** Algorithm identifier for SDitH3-L5-gf2-fast-cipherpow */ +#define OQS_SIG_alg_sdith_l5_gf2_fast_cipherpow "SDitH3-L5-gf2-fast-cipherpow" ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ALG_IDENTIFIER_END ///// OQS_COPY_FROM_SLH_DSA_FRAGMENT_ALGID_START /** Algorithm identifier for slh_dsa_pure_sha2_128s */ @@ -576,7 +600,7 @@ extern "C" { ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ALGS_LENGTH_START /** Number of algorithm identifiers above. */ -#define OQS_SIG_algs_length 110 + OQS_SIG_SLH_DSA_algs_length +#define OQS_SIG_algs_length 122 + OQS_SIG_SLH_DSA_algs_length ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_ALGS_LENGTH_END /** @@ -848,6 +872,9 @@ OQS_API bool OQS_SIG_supports_ctx_str(const char *alg_name); #ifdef OQS_ENABLE_SIG_MQOM #include #endif /* OQS_ENABLE_SIG_MQOM */ +#ifdef OQS_ENABLE_SIG_SDITH +#include +#endif /* OQS_ENABLE_SIG_SDITH */ ///// OQS_COPY_FROM_UPSTREAM_FRAGMENT_INCLUDE_END ///// OQS_COPY_FROM_SLH_DSA_FRAGMENT_INCLUDE_START #ifdef OQS_ENABLE_SIG_SLH_DSA diff --git a/tests/KATs/sig/kats.json b/tests/KATs/sig/kats.json index 2df1447f32..6dad5a9244 100644 --- a/tests/KATs/sig/kats.json +++ b/tests/KATs/sig/kats.json @@ -211,6 +211,54 @@ "all": "97f422568fc3e0f468930f23c82fd89e3822c3b421096db1aeb9b46208ee8448", "single": "4d23b0b9cb780a2ccbd7c6558b3fc51c3b7ccb9df4c867e36d455524399dc0e7" }, + "SDitH3-L1-gf2-fast": { + "all": "8b3b847405bb92a4140af6b0c03dfbd9629732d93015e7dd429e233c00e0ddb2", + "single": "41ccb6bad2eefe684dca736393e8c29bec7f2f3672492df6cff17c84f333cc03" + }, + "SDitH3-L1-gf2-fast-cipherpow": { + "all": "893dbf70bbb7e7d5ff870d9d40da846e297ac5c69648d80118ee02e54bb47d58", + "single": "ce37d051dba74715aa3b5286970b688e2828a685279630e0ceac68b79c2e5607" + }, + "SDitH3-L1-gf2-short": { + "all": "873711fb0690ae4ab5e40674e5450ce1113999aea5aaf35a7e5e2f72fb5c0537", + "single": "d50d495fd8a0f2cb0463fcd3aef1398cf84b94bf0aff0fd69b5a1026b47e2047" + }, + "SDitH3-L1-gf2-short-cipherpow": { + "all": "5772f0d8473f9408001506db63b962ca9b2c7d12fcce60c5f73369d5e92b39cd", + "single": "cc0d9688a9c4b5f99e90746657da5cdd1804b5012b3c934975599512d5061e4c" + }, + "SDitH3-L3-gf2-fast": { + "all": "577cf4397deaa4a97b8fffd6f9e3e1166f023eb0bafc2661fd8879a272ef4e0e", + "single": "b4778b069b8c58c803cb8bc8e3d4557c67e0ec5555a6ba2e82186beb0fdb1309" + }, + "SDitH3-L3-gf2-fast-cipherpow": { + "all": "0e56d3d02ddb8dbb4b8e4afcb2871895a6cc02ddc2e8b075f9d3d449c5a68223", + "single": "e14a0f9964f77f455f633e5a498a0efc9657a7393c07a2226f730864aca79966" + }, + "SDitH3-L3-gf2-short": { + "all": "4fa8c3dde2e8a6e458d5f90711fa146d3bea867df840f3c92ccb2bb25e3fd648", + "single": "7fa8b98407d4ac073a01c754824b66d8c0a8f6eb1e984082593e1d101c83c9e1" + }, + "SDitH3-L3-gf2-short-cipherpow": { + "all": "22da728e98b2a7fa83609b38cbbfd71016126a989cd79087b27021146359ec4b", + "single": "e8a4ba0d333235fa061b79de0d65bc3932b73b6ee2322b3b6ed4fb3598356b4f" + }, + "SDitH3-L5-gf2-fast": { + "all": "d2b7eed450896d25daee050677fdec8728ba05e11be183caa26d62522a70bd88", + "single": "9ea0519ec21823dd72be5c81a8617decc67cff01345c2a93a7b1421fd59474e8" + }, + "SDitH3-L5-gf2-fast-cipherpow": { + "all": "2e80ec07e42009d5b632dd8bd28297d3b73ccc289e24ea1d8fa7d0e783ebbe92", + "single": "d5622fa5a18563a873dc3eb8aa4c324b64843dbc2449856d94ab5960941b0c90" + }, + "SDitH3-L5-gf2-short": { + "all": "477968076025d4bda5db0239ec48e19a4e174a660d0fda11e7d937b9c36c2c1d", + "single": "e37006ef04589adff3fb96948e35e370e4540d10bbf4a4c6c22eff83c8942062" + }, + "SDitH3-L5-gf2-short-cipherpow": { + "all": "9a5ec5e323ca8f291464e1ee8203d08d4070bfe44f020890c0af814e8cdfe3a3", + "single": "097cc28abf7afc193824ed98bf145ac8239a7f23757a687f30f3683f9b4e5495" + }, "SNOVA_III_B": { "all": "e8d7d7facc29e50333a88bb34b027c502b3ac4fd26ac6dbd5d95712bdb8d9d91", "single": "7175ce45fbd3e6b7eca08de8df339a8bb24116531478d1afa2f1e8cf7e59ace9" diff --git a/tests/constant_time/sig/issues.json b/tests/constant_time/sig/issues.json index bf749d7f72..0e692589ea 100644 --- a/tests/constant_time/sig/issues.json +++ b/tests/constant_time/sig/issues.json @@ -213,5 +213,17 @@ "QRUOV-5q31L3-aes": ["qruov"], "QRUOV-5q31L3-shake": ["qruov"], "QRUOV-5q7L10-aes": ["qruov"], - "QRUOV-5q7L10-shake": ["qruov"] + "QRUOV-5q7L10-shake": ["qruov"], + "SDitH3-L1-gf2-short": ["sdith"], + "SDitH3-L1-gf2-short-cipherpow": ["sdith"], + "SDitH3-L1-gf2-fast": ["sdith"], + "SDitH3-L1-gf2-fast-cipherpow": ["sdith"], + "SDitH3-L3-gf2-short": ["sdith"], + "SDitH3-L3-gf2-short-cipherpow": ["sdith"], + "SDitH3-L3-gf2-fast": ["sdith"], + "SDitH3-L3-gf2-fast-cipherpow": ["sdith"], + "SDitH3-L5-gf2-short": ["sdith"], + "SDitH3-L5-gf2-short-cipherpow": ["sdith"], + "SDitH3-L5-gf2-fast": ["sdith"], + "SDitH3-L5-gf2-fast-cipherpow": ["sdith"] } diff --git a/tests/constant_time/sig/issues/sdith b/tests/constant_time/sig/issues/sdith new file mode 100644 index 0000000000..1511cb3ef0 --- /dev/null +++ b/tests/constant_time/sig/issues/sdith @@ -0,0 +1,85 @@ +# These suppressions need to be verified as false positives +# This is tracked at https://github.com/open-quantum-safe/liboqs/issues/2609 +{ + TODO: verify CT claims + Memcheck:Cond + fun:oqs_sig_private_sdith_avx2_partition +} +{ + TODO: verify CT claims + Memcheck:Cond + src:rsd.c:61 # fun:oqs_sig_private_sdith_avx2_rsd_generate_random_instance_ref + fun:oqs_sig_private_sdith_avx2_sdith_keygen + fun:oqs_sig_pubapi_sdith_*_crypto_sign_keypair + fun:OQS_SIG_sdith_*_keypair + fun:OQS_SIG_keypair +} +{ + TODO: verify CT claims + Memcheck:Cond + fun:oqs_sig_private_sdith_avx2_bitvec_is_zero_nonct + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} +{ + TODO: verify CT claims + Memcheck:Cond + fun:oqs_sig_private_sdith_avx2_estimate_topen + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} +{ + TODO: verify CT claims (vole_expansion.c:665/672/681) + Memcheck:Cond + fun:oqs_sig_private_sdith_avx2_full_ggm_tree_open_sibling_path_from_root + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} +{ + TODO: verify CT claims + Memcheck:Cond + fun:oqs_sig_private_sdith_avx2_*_proofow_grind_avx2 + fun:oqs_sig_private_sdith_avx2_proofow_grind_w_cipher_cat?_avx + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} +{ + TODO: verify CT claims () + Memcheck:Cond + fun:oqs_sig_private_sdith_avx2_proofow_grind_w_shake_cat?_4way + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} +{ + TODO: verify CT claims + Memcheck:Cond + src:matrix_vector_products_f2_avx2.c:423 # fun:matrix_vector_product_f2_block_256 + fun:oqs_sig_private_sdith_avx2_matrix_f2_times_vector_flambda_avx2 + fun:oqs_sig_private_sdith_avx2_prover_vole_consistency_check + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} +{ + TODO: verify the address lookup is downstream of public data + Memcheck:Value8 + fun:_mm256_loadu_si256 + fun:matrix_vector_product_f2_block_256 + fun:oqs_sig_private_sdith_avx2_matrix_f2_times_vector_flambda_avx2 + fun:oqs_sig_private_sdith_avx2_prover_vole_consistency_check + fun:oqs_sig_private_sdith_avx2_sdith_sign + fun:oqs_sig_pubapi_sdith_*_avx2_crypto_sign_sign + fun:OQS_SIG_sdith_*_sign + fun:OQS_SIG_sign +} diff --git a/tests/kat_sig.c b/tests/kat_sig.c index 0a3b51092f..909df4bc7f 100644 --- a/tests/kat_sig.c +++ b/tests/kat_sig.c @@ -1113,6 +1113,126 @@ OQS_STATUS combine_message_signature(uint8_t **signed_msg, size_t *signed_msg_le memcpy(*signed_msg + msg_len, signature, signature_len); return OQS_SUCCESS; } else if (0 == strcmp(sig->method_name, "mqom3_cat5_gf2_shorter_ot")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L1-gf2-short")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L1-gf2-short-cipherpow")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L1-gf2-fast")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L1-gf2-fast-cipherpow")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L3-gf2-short")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L3-gf2-short-cipherpow")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L3-gf2-fast")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L3-gf2-fast-cipherpow")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L5-gf2-short")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L5-gf2-short-cipherpow")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L5-gf2-fast")) { + // signed_msg = msg || signature + *signed_msg_len = msg_len + signature_len; + *signed_msg = OQS_MEM_malloc(*signed_msg_len); + if (*signed_msg == NULL) { + return OQS_ERROR; + } + memcpy(*signed_msg, msg, msg_len); + memcpy(*signed_msg + msg_len, signature, signature_len); + return OQS_SUCCESS; + } else if (0 == strcmp(sig->method_name, "SDitH3-L5-gf2-fast-cipherpow")) { // signed_msg = msg || signature *signed_msg_len = msg_len + signature_len; *signed_msg = OQS_MEM_malloc(*signed_msg_len); diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 8524e61617..0c7dab3ddd 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -156,6 +156,12 @@ if(CONFIG_LIBOQS) set(OQS_ENABLE_SIG_MQOM OFF) endif() + if(CONFIG_LIBOQS_ENABLE_SIG_SDITH) + set(OQS_ENABLE_SIG_SDITH ON) + else() + set(OQS_ENABLE_SIG_SDITH OFF) + endif() + # Add the actual liboqs targets add_subdirectory(.. build) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 9a1401a019..6ed3ce987f 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -81,4 +81,10 @@ config LIBOQS_ENABLE_SIG_MQOM default y depends on LIBOQS +config LIBOQS_ENABLE_SIG_SDITH + bool "Enable the SDitH signature algorithm" + default n + depends on LIBOQS + depends on 64BIT + endmenu diff --git a/zephyr/README.md b/zephyr/README.md index fd002879b5..5942ae3901 100644 --- a/zephyr/README.md +++ b/zephyr/README.md @@ -37,7 +37,10 @@ In the two provided sample applications (also see [Samples](#Samples)), a callba The port provides a variety of configurable options using Kconfig. Once you have the liboqs module enabled with `CONFIG_LIBOQS=y`, you can manually enable or disable specific KEM or Signature algorithms using the `LIBOQS_ENABLE_KEM_xxx` and `LIBOQS_ENABLE_SIG_xxx` options. -The algorithms to be standardized by NIST are enabled by default, all others are disabled by default. +Most algorithms to be standardized by NIST are enabled by default, all others are disabled by default. +Some algorithms that are to be standardized which are disabled by default include: +* UOV +* SDitH due to large heap memory usage ### Supported architectures