From 4479e1f8a37f86b8bb4b97ab58656a536c579c87 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 14 Apr 2026 12:24:42 +0200 Subject: [PATCH 01/12] Introduce `LTC_NO_ACCEL`. Signed-off-by: Steffen Jaeckel --- appveyor.yml | 8 +++++--- src/headers/tomcrypt_cfg.h | 10 +++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 29cbf812b..655f2be2e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,10 +31,12 @@ build_script: cp test.exe test-stock.exe cp timing.exe timing-stock.exe nmake -f makefile.msvc clean - nmake -f makefile.msvc all CFLAGS="/Ox /DUSE_LTM /DLTM_DESC /DLTC_NO_AES_NI /I../libtommath" + nmake -f makefile.msvc all CFLAGS="/Ox /DUSE_LTM /DLTM_DESC /DLTC_NO_ACCEL /I../libtommath" test_script: - cmd: >- test-stock.exe test.exe - timing-stock.exe cipher_ecb - timing.exe cipher_ecb + timing-stock.exe cipher_ecb aes + timing.exe cipher_ecb aes + timing-stock.exe hash sha + timing.exe hash sha diff --git a/src/headers/tomcrypt_cfg.h b/src/headers/tomcrypt_cfg.h index 6f82aa9a3..9b51b6a74 100644 --- a/src/headers/tomcrypt_cfg.h +++ b/src/headers/tomcrypt_cfg.h @@ -243,14 +243,22 @@ typedef unsigned long ltc_mp_digit; #undef ENDIAN_32BITWORD #undef ENDIAN_64BITWORD #undef LTC_FAST - #define LTC_NO_AES_NI + #define LTC_NO_ACCEL #define LTC_NO_BSWAP #define LTC_NO_CLZL #define LTC_NO_CTZL #define LTC_NO_ROLC #define LTC_NO_ROTATE +#endif + +/* Just portable C implementations */ +#ifdef LTC_NO_ACCEL + #define LTC_NO_AES_NI #define LTC_NO_GCM_PCLMUL #define LTC_NO_GCM_PMULL + #define LTC_NO_SHA1_X86 + #define LTC_NO_SHA224_X86 + #define LTC_NO_SHA256_X86 #endif /* No LTC_FAST if: explicitly disabled OR non-gcc/non-clang compiler OR old gcc OR using -ansi -std=c99 */ From d7afb5551077755fb1e8e6ba3cd38aae311f5873 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 14 Apr 2026 16:44:59 +0200 Subject: [PATCH 02/12] Clean-up some defines. Signed-off-by: Steffen Jaeckel --- src/encauth/gcm/gcm_gf_mult.c | 3 +++ src/headers/tomcrypt_cfg.h | 19 +++++-------------- src/headers/tomcrypt_private.h | 3 +++ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/encauth/gcm/gcm_gf_mult.c b/src/encauth/gcm/gcm_gf_mult.c index 0b7a1c83c..b19259e43 100644 --- a/src/encauth/gcm/gcm_gf_mult.c +++ b/src/encauth/gcm/gcm_gf_mult.c @@ -9,6 +9,9 @@ #if defined(LTC_GCM_MODE) || defined(LTC_LRW_MODE) #if defined(LTC_GCM_PCLMUL) + +#define LTC_GCM_PCLMUL_TARGET LTC_ATTRIBUTE((__target__("pclmul,ssse3"))) + #if defined(_MSC_VER) #include #else diff --git a/src/headers/tomcrypt_cfg.h b/src/headers/tomcrypt_cfg.h index 9b51b6a74..8f649b237 100644 --- a/src/headers/tomcrypt_cfg.h +++ b/src/headers/tomcrypt_cfg.h @@ -315,10 +315,14 @@ typedef unsigned long ltc_mp_digit; #define LTC_HAVE_CTZL_BUILTIN #endif -#if (defined(__x86_64__) || defined(_M_X64)) +#if (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) #if !defined(LTC_NO_AES_NI) #define LTC_AES_NI #endif + #if !defined(LTC_NO_GCM_PCLMUL) + #define LTC_GCM_PCLMUL + #undef LTC_GCM_TABLES + #endif #if !defined(LTC_NO_SHA1_X86) #define LTC_SHA1_X86 #endif @@ -392,19 +396,6 @@ typedef unsigned long ltc_mp_digit; # define LTC_ATTRIBUTE(x) #endif -#if !defined(LTC_NO_GCM_PCLMUL) && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) -#define LTC_GCM_PCLMUL -#undef LTC_GCM_TABLES -#endif - -#if defined(__clang__) || defined(__GNUC__) -#define LTC_GCM_PCLMUL_TARGET __attribute__((target("pclmul,ssse3"))) -#define LTC_SHA_TARGET __attribute__((__target__("sse2,ssse3,sse4.1,sha"))) -#else -#define LTC_GCM_PCLMUL_TARGET -#define LTC_SHA_TARGET -#endif - #if !defined(LTC_NO_GCM_PMULL) && (defined(__aarch64__) || defined(_M_ARM64)) #define LTC_GCM_PMULL #undef LTC_GCM_TABLES diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 1658cca7a..39c56454d 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -182,6 +182,9 @@ int func_name (hash_state * md, const unsigned char *in, unsigned long inlen) return CRYPT_OK; \ } + +#define LTC_SHA_TARGET LTC_ATTRIBUTE((__target__("sse2,ssse3,sse4.1,sha"))) + #ifdef LTC_SHA1 int sha1_test_desc(const struct ltc_hash_descriptor *desc, const char *name); #endif From e7f32b86e53e04212a241683007d406cb7933863 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 14 Apr 2026 16:46:37 +0200 Subject: [PATCH 03/12] Use `s_x86_cpuid()` in `s_{aesni,pclmul}_is_supported()`. Hopefully at one point we can get rid of its duplication. Why again don't we use inline functions as they should be used? Signed-off-by: Steffen Jaeckel --- src/ciphers/aes/aes_desc.c | 48 ++++++++++++++++++++--------------- src/encauth/gcm/gcm_gf_mult.c | 43 +++++++++++++++++++------------ 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/ciphers/aes/aes_desc.c b/src/ciphers/aes/aes_desc.c index 2ff913e83..d4f3aeeda 100644 --- a/src/ciphers/aes/aes_desc.c +++ b/src/ciphers/aes/aes_desc.c @@ -48,36 +48,42 @@ const struct ltc_cipher_descriptor aes_enc_desc = #endif -/* Code partially borrowed from https://software.intel.com/content/www/us/en/develop/articles/intel-sha-extensions.html */ #if defined(LTC_AES_NI) + +#if !defined (LTC_S_X86_CPUID) +#define LTC_S_X86_CPUID +static LTC_INLINE void s_x86_cpuid(int* regs, int leaf) +{ +#if defined _MSC_VER + __cpuid(regs, leaf); +#else + int a, b, c, d; + + a = leaf; + b = c = d = 0; + asm volatile ("cpuid" + :"=a"(a), "=b"(b), "=c"(c), "=d"(d) + :"a"(a), "c"(c) + ); + regs[0] = a; + regs[1] = b; + regs[2] = c; + regs[3] = d; +#endif +} +#endif /* LTC_S_X86_CPUID */ + static LTC_INLINE int s_aesni_is_supported(void) { static int initialized = 0, is_supported = 0; if (initialized == 0) { - int a, b, c, d; - /* Look for CPUID.1.0.ECX[19] (SSE4.1) and CPUID.1.0.ECX[25] (AES-NI) * EAX = 1, ECX = 0 */ - a = 1; - c = 0; - -#if defined(_MSC_VER) && !defined(__clang__) - int arr[4]; - __cpuidex(arr, a, c); - a = arr[0]; - b = arr[1]; - c = arr[2]; - d = arr[3]; -#else - __asm__ volatile ("cpuid" - :"=a"(a), "=b"(b), "=c"(c), "=d"(d) - :"a"(a), "c"(c) - ); -#endif - - is_supported = ((c >> 19) & 1) && ((c >> 25) & 1); + int regs[4]; + s_x86_cpuid(regs, 1); + is_supported = ((regs[2] >> 19) & 1) && ((regs[2] >> 25) & 1); initialized = 1; } diff --git a/src/encauth/gcm/gcm_gf_mult.c b/src/encauth/gcm/gcm_gf_mult.c index b19259e43..39ce9de18 100644 --- a/src/encauth/gcm/gcm_gf_mult.c +++ b/src/encauth/gcm/gcm_gf_mult.c @@ -21,27 +21,38 @@ #include #include +#if !defined (LTC_S_X86_CPUID) +#define LTC_S_X86_CPUID +static LTC_INLINE void s_x86_cpuid(int* regs, int leaf) +{ +#if defined _MSC_VER + __cpuid(regs, leaf); +#else + int a, b, c, d; + + a = leaf; + b = c = d = 0; + asm volatile ("cpuid" + :"=a"(a), "=b"(b), "=c"(c), "=d"(d) + :"a"(a), "c"(c) + ); + regs[0] = a; + regs[1] = b; + regs[2] = c; + regs[3] = d; +#endif +} +#endif /* LTC_S_X86_CPUID */ + static LTC_INLINE int s_pclmul_is_supported(void) { static int initialized = 0, is_supported = 0; if (initialized == 0) { - /* Test CPUID.1.0.ECX[1] - * EAX = 1, ECX = 0 */ -#if defined(_MSC_VER) - int cpuInfo[4]; - __cpuid(cpuInfo, 1); - is_supported = ((cpuInfo[2] >> 1) & 1); -#else - int a = 1 , b, c = 0, d; - - asm volatile ("cpuid" - :"=a"(a), "=b"(b), "=c"(c), "=d"(d) - :"a"(a), "c"(c) - ); - - is_supported = ((c >> 1) & 1); -#endif + int regs[4]; + s_x86_cpuid(regs, 1); + /* Test CPUID.1.0.ECX[1] (PCLMUL) and CPUID.1.0.ECX[9] (SSSE3) */ + is_supported = ((regs[2] >> 1) & 1) && ((regs[2] >> 9) & 1); initialized = 1; } From 34829584ab72f1776bc0c72771c1b488b085b097 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 14 Apr 2026 16:50:55 +0200 Subject: [PATCH 04/12] Make HW-accel checkers always available. Since the SHA-NI checker does the same for all three versions, we only have to make one version public. This also now enables explicit testing of the SHA-NI blocks. Signed-off-by: Steffen Jaeckel --- src/ciphers/aes/aes_desc.c | 84 +++++++++++++++++------------------ src/hashes/sha2/sha256_desc.c | 53 +++++++++++++--------- src/headers/tomcrypt_cfg.h | 1 + src/headers/tomcrypt_cipher.h | 2 +- src/headers/tomcrypt_hash.h | 2 + src/misc/crypt/crypt.c | 7 ++- tests/cipher_hash_test.c | 21 +++++++++ tests/test.c | 3 ++ 8 files changed, 106 insertions(+), 67 deletions(-) diff --git a/src/ciphers/aes/aes_desc.c b/src/ciphers/aes/aes_desc.c index d4f3aeeda..c03e1bb36 100644 --- a/src/ciphers/aes/aes_desc.c +++ b/src/ciphers/aes/aes_desc.c @@ -9,46 +9,7 @@ #include "tomcrypt_private.h" -#if defined(LTC_RIJNDAEL) - -#ifndef ENCRYPT_ONLY - -#define AES_SETUP aes_setup -#define AES_ENC aes_ecb_encrypt -#define AES_DEC aes_ecb_decrypt -#define AES_DONE aes_done -#define AES_TEST aes_test -#define AES_KS aes_keysize - -const struct ltc_cipher_descriptor aes_desc = -{ - "aes", - 6, - 16, 32, 16, 10, - AES_SETUP, AES_ENC, AES_DEC, AES_TEST, AES_DONE, AES_KS, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -#else - -#define AES_SETUP aes_enc_setup -#define AES_ENC aes_enc_ecb_encrypt -#define AES_DONE aes_enc_done -#define AES_TEST aes_enc_test -#define AES_KS aes_enc_keysize - -const struct ltc_cipher_descriptor aes_enc_desc = -{ - "aes", - 6, - 16, 32, 16, 10, - AES_SETUP, AES_ENC, NULL, NULL, AES_DONE, AES_KS, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -#endif - -#if defined(LTC_AES_NI) +#if defined(LTC_ARCH_X86) && (defined(LTC_AES_NI) || !defined(ENCRYPT_ONLY)) #if !defined (LTC_S_X86_CPUID) #define LTC_S_X86_CPUID @@ -89,17 +50,56 @@ static LTC_INLINE int s_aesni_is_supported(void) return is_supported; } -#endif +#endif /* LTC_ARCH_X86 */ #ifndef ENCRYPT_ONLY int aesni_is_supported(void) { -#ifdef LTC_AES_NI +#if defined(LTC_ARCH_X86) return s_aesni_is_supported(); #else return 0; #endif } +#endif /* ENCRYPT_ONLY */ + +#if defined(LTC_RIJNDAEL) + +#ifndef ENCRYPT_ONLY + +#define AES_SETUP aes_setup +#define AES_ENC aes_ecb_encrypt +#define AES_DEC aes_ecb_decrypt +#define AES_DONE aes_done +#define AES_TEST aes_test +#define AES_KS aes_keysize + +const struct ltc_cipher_descriptor aes_desc = +{ + "aes", + 6, + 16, 32, 16, 10, + AES_SETUP, AES_ENC, AES_DEC, AES_TEST, AES_DONE, AES_KS, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#else + +#define AES_SETUP aes_enc_setup +#define AES_ENC aes_enc_ecb_encrypt +#define AES_DONE aes_enc_done +#define AES_TEST aes_enc_test +#define AES_KS aes_enc_keysize + +const struct ltc_cipher_descriptor aes_enc_desc = +{ + "aes", + 6, + 16, 32, 16, 10, + AES_SETUP, AES_ENC, NULL, NULL, AES_DONE, AES_KS, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + #endif /** diff --git a/src/hashes/sha2/sha256_desc.c b/src/hashes/sha2/sha256_desc.c index 7367ec20b..f144bfd17 100644 --- a/src/hashes/sha2/sha256_desc.c +++ b/src/hashes/sha2/sha256_desc.c @@ -2,27 +2,7 @@ /* SPDX-License-Identifier: Unlicense */ #include "tomcrypt_private.h" -#ifdef LTC_SHA256 - -const struct ltc_hash_descriptor sha256_desc = -{ - "sha256", - 0, - 32, - 64, - - /* OID */ - { 2, 16, 840, 1, 101, 3, 4, 2, 1, }, - 9, - - &sha256_init, - &sha256_process, - &sha256_done, - &sha256_test, - NULL -}; - -#if defined LTC_SHA256_X86 +#if defined LTC_ARCH_X86 #if !defined (LTC_S_X86_CPUID) #define LTC_S_X86_CPUID @@ -70,7 +50,36 @@ static LTC_INLINE int s_sha256_x86_is_supported(void) } return is_supported; } -#endif /* LTC_SHA256_X86 */ +#endif /* LTC_ARCH_X86 */ + +int shani_is_supported(void) +{ +#ifdef LTC_ARCH_X86 + return s_sha256_x86_is_supported(); +#else + return 0; +#endif +} + +#ifdef LTC_SHA256 + +const struct ltc_hash_descriptor sha256_desc = +{ + "sha256", + 0, + 32, + 64, + + /* OID */ + { 2, 16, 840, 1, 101, 3, 4, 2, 1, }, + 9, + + &sha256_init, + &sha256_process, + &sha256_done, + &sha256_test, + NULL +}; /** Initialize the hash state diff --git a/src/headers/tomcrypt_cfg.h b/src/headers/tomcrypt_cfg.h index 8f649b237..f0f5051e2 100644 --- a/src/headers/tomcrypt_cfg.h +++ b/src/headers/tomcrypt_cfg.h @@ -316,6 +316,7 @@ typedef unsigned long ltc_mp_digit; #endif #if (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) + #define LTC_ARCH_X86 #if !defined(LTC_NO_AES_NI) #define LTC_AES_NI #endif diff --git a/src/headers/tomcrypt_cipher.h b/src/headers/tomcrypt_cipher.h index b370fedb0..0f07f2417 100644 --- a/src/headers/tomcrypt_cipher.h +++ b/src/headers/tomcrypt_cipher.h @@ -711,9 +711,9 @@ void rijndael_enc_done(symmetric_key *skey); int rijndael_enc_keysize(int *keysize); extern const struct ltc_cipher_descriptor rijndael_desc; extern const struct ltc_cipher_descriptor rijndael_enc_desc; +#endif int aesni_is_supported(void); -#endif #if defined(LTC_AES_NI) int aesni_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); diff --git a/src/headers/tomcrypt_hash.h b/src/headers/tomcrypt_hash.h index a6bd75028..c80ad9590 100644 --- a/src/headers/tomcrypt_hash.h +++ b/src/headers/tomcrypt_hash.h @@ -375,6 +375,8 @@ int sha512_224_test(void); extern const struct ltc_hash_descriptor sha512_224_desc; #endif /* LTC_SHA512_224 */ +int shani_is_supported(void); + #ifdef LTC_SHA256 int sha256_init(hash_state * md); int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen); diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index ccef4a0c7..3851006d9 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -13,9 +13,12 @@ const char *crypt_build_settings = "LibTomCrypt " SCRYPT " (www.libtom.net)\n" "LibTomCrypt is public domain software.\n" #if defined(INCLUDE_BUILD_DATE) - "Built on " __DATE__ " at " __TIME__ "\n" + "Built on " __DATE__ " at " __TIME__ "\n\n" #endif - "\n\nEndianness: " +#if defined(LTC_ARCH_X86) + "LTC_ARCH_X86\n" +#endif + "\nEndianness: " #if defined(ENDIAN_NEUTRAL) "neutral/" #endif diff --git a/tests/cipher_hash_test.c b/tests/cipher_hash_test.c index 92e082307..699b7d365 100644 --- a/tests/cipher_hash_test.c +++ b/tests/cipher_hash_test.c @@ -56,6 +56,27 @@ int cipher_hash_test(void) DOX(hash_descriptor[x].test(), hash_descriptor[x].name); } + /* explicit SHA-NI + portable implementations tests */ + if (shani_is_supported()) { +#if defined(LTC_SHA256) && defined(LTC_SHA256_X86) + DO(sha256_x86_test()); +#endif +#if defined(LTC_SHA224) && defined(LTC_SHA224_X86) + DO(sha224_x86_test()); +#endif +#if defined(LTC_SHA1) && defined(LTC_SHA1_X86) + DO(sha1_x86_test()); +#endif + } +#if defined(LTC_SHA256) + DO(sha256_c_test()); +#endif +#if defined(LTC_SHA224) + DO(sha224_c_test()); +#endif +#if defined(LTC_SHA1) + DO(sha1_c_test()); +#endif #ifdef LTC_SHA3 /* SHAKE128 + SHAKE256 tests are a bit special */ DOX(sha3_shake_test(), "sha3_shake"); diff --git a/tests/test.c b/tests/test.c index 8eb7d7d0b..f2f5ed0c5 100644 --- a/tests/test.c +++ b/tests/test.c @@ -344,6 +344,9 @@ int main(int argc, char **argv) printf("LTC_VERSION = %s\n%s\n\n", GIT_VERSION, crypt_build_settings); + printf("AES-NI CPU support = %d\n", aesni_is_supported()); + printf("SHA-NI CPU support = %d\n\n", shani_is_supported()); + #ifdef USE_LTM mpi_provider = "ltm"; #elif defined(USE_TFM) From 30fbcb9ebb642dee361d612cfd1a36663bb8d56c Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 14 Apr 2026 16:51:43 +0200 Subject: [PATCH 05/12] Further improve timing demo. Filtering is now possible for all classes besides public key crypto. Signed-off-by: Steffen Jaeckel --- demos/timing.c | 371 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 259 insertions(+), 112 deletions(-) diff --git a/demos/timing.c b/demos/timing.c index 1d9bd5ca8..a5e177cfb 100644 --- a/demos/timing.c +++ b/demos/timing.c @@ -1054,130 +1054,206 @@ static void time_ecc(void) static void time_ecc(void) { fprintf(stderr, "NO ECC\n"); } #endif -static void time_macs_(unsigned long MAC_SIZE) +typedef struct mac_ctx { + unsigned char *buf, key[32], tag[16]; + unsigned long size; + int cipher_idx, hash_idx; +} mac_ctx; + +#ifdef LTC_OMAC +static void time_omac(mac_ctx *ctx) { -#if defined(LTC_OMAC) || defined(LTC_XCBC) || defined(LTC_F9_MODE) || defined(LTC_PMAC) || defined(LTC_PELICAN) || defined(LTC_HMAC) - unsigned char *buf, key[16], tag[16]; ulong64 t1, t2; unsigned long x, z; - int err, cipher_idx, hash_idx; - - fprintf(stderr, "\nMAC Timings (cycles/byte on %luKB blocks):\n", MAC_SIZE); - - buf = XMALLOC(MAC_SIZE*1024); - if (buf == NULL) { - fprintf(stderr, "\n\nout of heap yo\n\n"); - exit(EXIT_FAILURE); - } - - cipher_idx = find_cipher("aes"); - hash_idx = find_hash("sha1"); + int err; - if (cipher_idx == -1 || hash_idx == -1) { - fprintf(stderr, "Warning the MAC tests requires AES and SHA1 to operate... so sorry\n"); - exit(EXIT_FAILURE); - } - - yarrow_read(buf, MAC_SIZE*1024, &yarrow_prng); - yarrow_read(key, 16, &yarrow_prng); - -#ifdef LTC_OMAC t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = omac_memory(cipher_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) { - fprintf(stderr, "\n\nomac-%s error... %s\n", cipher_descriptor[cipher_idx].name, error_to_string(err)); + if ((err = omac_memory(ctx->cipher_idx, ctx->key, 16, ctx->buf, ctx->size, ctx->tag, &z)) != CRYPT_OK) { + fprintf(stderr, "\n\nomac-%s error... %s\n", cipher_descriptor[ctx->cipher_idx].name, error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "OMAC-%s\t\t%9"PRI64"u\n", cipher_descriptor[cipher_idx].name, t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "OMAC-%s\t\t%9"PRI64"u\n", cipher_descriptor[ctx->cipher_idx].name, t2/(ulong64)(ctx->size)); +} #endif #ifdef LTC_XCBC +static void time_xcbc(mac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = xcbc_memory(cipher_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) { - fprintf(stderr, "\n\nxcbc-%s error... %s\n", cipher_descriptor[cipher_idx].name, error_to_string(err)); + if ((err = xcbc_memory(ctx->cipher_idx, ctx->key, 16, ctx->buf, ctx->size, ctx->tag, &z)) != CRYPT_OK) { + fprintf(stderr, "\n\nxcbc-%s error... %s\n", cipher_descriptor[ctx->cipher_idx].name, error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "XCBC-%s\t\t%9"PRI64"u\n", cipher_descriptor[cipher_idx].name, t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "XCBC-%s\t\t%9"PRI64"u\n", cipher_descriptor[ctx->cipher_idx].name, t2/(ulong64)(ctx->size)); +} #endif #ifdef LTC_F9_MODE +static void time_f9(mac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = f9_memory(cipher_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) { - fprintf(stderr, "\n\nF9-%s error... %s\n", cipher_descriptor[cipher_idx].name, error_to_string(err)); + if ((err = f9_memory(ctx->cipher_idx, ctx->key, 16, ctx->buf, ctx->size, ctx->tag, &z)) != CRYPT_OK) { + fprintf(stderr, "\n\nF9-%s error... %s\n", cipher_descriptor[ctx->cipher_idx].name, error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "F9-%s\t\t\t%9"PRI64"u\n", cipher_descriptor[cipher_idx].name, t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "F9-%s\t\t\t%9"PRI64"u\n", cipher_descriptor[ctx->cipher_idx].name, t2/(ulong64)(ctx->size)); +} #endif #ifdef LTC_PMAC +static void time_pmac(mac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = pmac_memory(cipher_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) { - fprintf(stderr, "\n\npmac-%s error... %s\n", cipher_descriptor[cipher_idx].name, error_to_string(err)); + if ((err = pmac_memory(ctx->cipher_idx, ctx->key, 16, ctx->buf, ctx->size, ctx->tag, &z)) != CRYPT_OK) { + fprintf(stderr, "\n\npmac-%s error... %s\n", cipher_descriptor[ctx->cipher_idx].name, error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "PMAC-%s\t\t%9"PRI64"u\n", cipher_descriptor[cipher_idx].name, t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "PMAC-%s\t\t%9"PRI64"u\n", cipher_descriptor[ctx->cipher_idx].name, t2/(ulong64)(ctx->size)); +} #endif #ifdef LTC_PELICAN +static void time_pelican(mac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); - z = 16; - if ((err = pelican_memory(key, 16, buf, MAC_SIZE*1024, tag)) != CRYPT_OK) { + if ((err = pelican_memory(ctx->key, 16, ctx->buf, ctx->size, ctx->tag)) != CRYPT_OK) { fprintf(stderr, "\n\npelican error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "PELICAN \t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "PELICAN \t\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); +} #endif #ifdef LTC_HMAC +static void time_hmac(mac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = hmac_memory(hash_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) { - fprintf(stderr, "\n\nhmac-%s error... %s\n", hash_descriptor[hash_idx].name, error_to_string(err)); + if ((err = hmac_memory(ctx->hash_idx, ctx->key, 16, ctx->buf, ctx->size, ctx->tag, &z)) != CRYPT_OK) { + fprintf(stderr, "\n\nhmac-%s error... %s\n", hash_descriptor[ctx->hash_idx].name, error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "HMAC-%s\t\t%9"PRI64"u\n", hash_descriptor[hash_idx].name, t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "HMAC-%s\t\t%9"PRI64"u\n", hash_descriptor[ctx->hash_idx].name, t2/(ulong64)(ctx->size)); +} +#endif + +static void time_macs_(unsigned long MAC_SIZE) +{ +#if defined(LTC_OMAC) || defined(LTC_XCBC) || defined(LTC_F9_MODE) || defined(LTC_PMAC) || defined(LTC_PELICAN) || defined(LTC_HMAC) + mac_ctx ctx; + struct { + const char *name; + void (*time_fun)(mac_ctx*); + } time_funs[] = { +#define TIME_FUN(n) { #n, time_ ## n } +#ifdef LTC_OMAC + TIME_FUN(omac), +#endif +#ifdef LTC_XCBC + TIME_FUN(xcbc), +#endif +#ifdef LTC_F9_MODE + TIME_FUN(f9), #endif +#ifdef LTC_PMAC + TIME_FUN(pmac), +#endif +#ifdef LTC_PELICAN + TIME_FUN(pelican), +#endif +#ifdef LTC_HMAC + TIME_FUN(hmac), +#endif +#undef TIME_FUN + }; + unsigned long n; + + fprintf(stderr, "\nMAC Timings (cycles/byte on %luKB blocks):\n", MAC_SIZE); + + ctx.size = MAC_SIZE*1024; + ctx.buf = XMALLOC(ctx.size); + if (ctx.buf == NULL) { + fprintf(stderr, "\n\nout of heap yo\n\n"); + exit(EXIT_FAILURE); + } + + ctx.cipher_idx = find_cipher("aes"); + ctx.hash_idx = find_hash("sha1"); + + if (ctx.cipher_idx == -1 || ctx.hash_idx == -1) { + fprintf(stderr, "Warning the MAC tests requires AES and SHA1 to operate... so sorry\n"); + exit(EXIT_FAILURE); + } + + yarrow_read(ctx.buf, ctx.size, &yarrow_prng); + yarrow_read(ctx.key, 16, &yarrow_prng); + + for (n = 0; n < LTC_ARRAY_SIZE(time_funs); ++n) { + if (!should_skip(time_funs[n].name)) + time_funs[n].time_fun(&ctx); + } - XFREE(buf); + XFREE(ctx.buf); #else LTC_UNUSED_PARAM(MAC_SIZE); fprintf(stderr, "NO MACs\n"); @@ -1191,137 +1267,147 @@ static void time_macs(void) time_macs_(32); } -static void time_encmacs_(unsigned long MAC_SIZE) -{ -#if defined(LTC_EAX_MODE) || defined(LTC_OCB_MODE) || defined(LTC_OCB3_MODE) || \ - defined(LTC_CCM_MODE) || defined(LTC_GCM_MODE) || defined(LTC_SIV_MODE) -#if defined(LTC_SIV_MODE) - unsigned char *aad[4]; - unsigned long buflen; -#endif +typedef struct eac_ctx { unsigned char *buf, IV[16], key[32], tag[16]; + unsigned long size; + int cipher_idx; +} eac_ctx; + +#ifdef LTC_EAX_MODE +static void time_eax(eac_ctx *ctx) +{ ulong64 t1, t2; unsigned long x, z; - int err, cipher_idx; - symmetric_ECB skey; - - fprintf(stderr, "\nENC+MAC Timings (zero byte AAD, 16 byte IV, cycles/byte on %luKB blocks):\n", MAC_SIZE); + int err; - buf = XMALLOC(MAC_SIZE*1024); - if (buf == NULL) { - fprintf(stderr, "\n\nout of heap yo\n\n"); - exit(EXIT_FAILURE); - } - - cipher_idx = find_cipher("aes"); - - yarrow_read(buf, MAC_SIZE*1024, &yarrow_prng); - yarrow_read(key, sizeof(key), &yarrow_prng); - yarrow_read(IV, sizeof(IV), &yarrow_prng); - -#ifdef LTC_EAX_MODE t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = eax_encrypt_authenticate_memory(cipher_idx, key, 16, IV, 16, NULL, 0, buf, MAC_SIZE*1024, buf, tag, &z)) != CRYPT_OK) { + if ((err = eax_encrypt_authenticate_memory(ctx->cipher_idx, ctx->key, 16, ctx->IV, 16, NULL, 0, ctx->buf, ctx->size, ctx->buf, ctx->tag, &z)) != CRYPT_OK) { fprintf(stderr, "\nEAX error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "EAX \t\t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "EAX \t\t\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); +} #endif -#ifdef LTC_OCB_MODE +#if defined(LTC_OCB_MODE) +static void time_ocb(eac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = ocb_encrypt_authenticate_memory(cipher_idx, key, 16, IV, buf, MAC_SIZE*1024, buf, tag, &z)) != CRYPT_OK) { + if ((err = ocb_encrypt_authenticate_memory(ctx->cipher_idx, ctx->key, 16, ctx->IV, ctx->buf, ctx->size, ctx->buf, ctx->tag, &z)) != CRYPT_OK) { fprintf(stderr, "\nOCB error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "OCB \t\t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "OCB \t\t\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); +} #endif -#ifdef LTC_OCB3_MODE +#if defined(LTC_OCB3_MODE) +static void time_ocb3(eac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = ocb3_encrypt_authenticate_memory(cipher_idx, key, 16, IV, 15, (unsigned char*)"", 0, buf, MAC_SIZE*1024, buf, tag, &z)) != CRYPT_OK) { + if ((err = ocb3_encrypt_authenticate_memory(ctx->cipher_idx, ctx->key, 16, ctx->IV, 15, (unsigned char*)"", 0, ctx->buf, ctx->size, ctx->buf, ctx->tag, &z)) != CRYPT_OK) { fprintf(stderr, "\nOCB3 error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "OCB3 \t\t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "OCB3 \t\t\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); +} #endif -#ifdef LTC_CCM_MODE +#if defined(LTC_CCM_MODE) +static void time_ccm(eac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + symmetric_ECB skey; + t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = ccm_memory(cipher_idx, key, 16, NULL, IV, 16, NULL, 0, buf, MAC_SIZE*1024, buf, tag, &z, CCM_ENCRYPT)) != CRYPT_OK) { + if ((err = ccm_memory(ctx->cipher_idx, ctx->key, 16, NULL, ctx->IV, 16, NULL, 0, ctx->buf, ctx->size, ctx->buf, ctx->tag, &z, CCM_ENCRYPT)) != CRYPT_OK) { fprintf(stderr, "\nCCM error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "CCM (no-precomp) \t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "CCM (no-precomp) \t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); - ecb_start(cipher_idx, key, 16, 0, &skey); + ecb_start(ctx->cipher_idx, ctx->key, 16, 0, &skey); t2 = -1; for (x = 0; x < 10000; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = ccm_memory(cipher_idx, key, 16, &skey, IV, 16, NULL, 0, buf, MAC_SIZE*1024, buf, tag, &z, CCM_ENCRYPT)) != CRYPT_OK) { + if ((err = ccm_memory(ctx->cipher_idx, ctx->key, 16, &skey, ctx->IV, 16, NULL, 0, ctx->buf, ctx->size, ctx->buf, ctx->tag, &z, CCM_ENCRYPT)) != CRYPT_OK) { fprintf(stderr, "\nCCM error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "CCM (precomp) \t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "CCM (precomp) \t\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); ecb_done(&skey); +} #endif -#ifdef LTC_GCM_MODE +#if defined (LTC_GCM_MODE) +static void time_gcm(eac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + gcm_state gcm +#ifdef LTC_GCM_TABLES_SSE2 +__attribute__ ((aligned (16))) +#endif +; t2 = -1; for (x = 0; x < 100; x++) { t_start(); t1 = t_read(); z = 16; - if ((err = gcm_memory(cipher_idx, key, 16, IV, 16, NULL, 0, buf, MAC_SIZE*1024, buf, tag, &z, GCM_ENCRYPT)) != CRYPT_OK) { + if ((err = gcm_memory(ctx->cipher_idx, ctx->key, 16, ctx->IV, 16, NULL, 0, ctx->buf, ctx->size, ctx->buf, ctx->tag, &z, GCM_ENCRYPT)) != CRYPT_OK) { fprintf(stderr, "\nGCM error... %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "GCM (no-precomp)\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); - - { - gcm_state gcm -#ifdef LTC_GCM_TABLES_SSE2 -__attribute__ ((aligned (16))) -#endif -; + fprintf(stderr, "GCM (no-precomp)\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); - if ((err = gcm_init(&gcm, cipher_idx, key, 16)) != CRYPT_OK) { fprintf(stderr, "gcm_init: %s\n", error_to_string(err)); exit(EXIT_FAILURE); } + if ((err = gcm_init(&gcm, ctx->cipher_idx, ctx->key, 16)) != CRYPT_OK) { fprintf(stderr, "gcm_init: %s\n", error_to_string(err)); exit(EXIT_FAILURE); } t2 = -1; for (x = 0; x < 10000; x++) { t_start(); @@ -1331,7 +1417,7 @@ __attribute__ ((aligned (16))) fprintf(stderr, "\nGCM error[%d]... %s\n", __LINE__, error_to_string(err)); exit(EXIT_FAILURE); } - if ((err = gcm_add_iv(&gcm, IV, 16)) != CRYPT_OK) { + if ((err = gcm_add_iv(&gcm, ctx->IV, 16)) != CRYPT_OK) { fprintf(stderr, "\nGCM error[%d]... %s\n", __LINE__, error_to_string(err)); exit(EXIT_FAILURE); } @@ -1339,36 +1425,44 @@ __attribute__ ((aligned (16))) fprintf(stderr, "\nGCM error[%d]... %s\n", __LINE__, error_to_string(err)); exit(EXIT_FAILURE); } - if ((err = gcm_process(&gcm, buf, MAC_SIZE*1024, buf, GCM_ENCRYPT)) != CRYPT_OK) { + if ((err = gcm_process(&gcm, ctx->buf, ctx->size, ctx->buf, GCM_ENCRYPT)) != CRYPT_OK) { fprintf(stderr, "\nGCM error[%d]... %s\n", __LINE__, error_to_string(err)); exit(EXIT_FAILURE); } - if ((err = gcm_done(&gcm, tag, &z)) != CRYPT_OK) { + if ((err = gcm_done(&gcm, ctx->tag, &z)) != CRYPT_OK) { fprintf(stderr, "\nGCM error[%d]... %s\n", __LINE__, error_to_string(err)); exit(EXIT_FAILURE); } t1 = t_read() - t1; if (t1 < t2) t2 = t1; } - fprintf(stderr, "GCM (precomp)\t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024)); - } + fprintf(stderr, "GCM (precomp)\t\t%9"PRI64"u\n", t2/(ulong64)(ctx->size)); +} #endif -#ifdef LTC_SIV_MODE +#if defined(LTC_SIV_MODE) +static void time_siv(eac_ctx *ctx) +{ + ulong64 t1, t2; + unsigned long x, z; + int err; + unsigned char *aad[4]; + unsigned long buflen; + for(z = 0; z < 4; z++) { - aad[z] = IV + z * 4; + aad[z] = ctx->IV + z * 4; } for(z = 0; z < 4; z++) { t2 = -1; for (x = 0; x < 10000; x++) { - buflen = MAC_SIZE*1024; + buflen = ctx->size; t_start(); t1 = t_read(); - if ((err = siv_memory(cipher_idx, LTC_ENCRYPT, - key, 32, - buf, MAC_SIZE*1024 - 16, - buf, &buflen, + if ((err = siv_memory(ctx->cipher_idx, LTC_ENCRYPT, + ctx->key, 32, + ctx->buf, ctx->size - 16, + ctx->buf, &buflen, aad[0], 16, aad[1], 12, aad[2], 8, @@ -1381,11 +1475,64 @@ __attribute__ ((aligned (16))) if (t1 < t2) t2 = t1; } aad[3-z] = NULL; - fprintf(stderr, "SIV (%lu x AAD)\t\t%9"PRI64"u\n", 4-z, t2/(ulong64)(MAC_SIZE*1024)); + fprintf(stderr, "SIV (%lu x AAD)\t\t%9"PRI64"u\n", 4-z, t2/(ulong64)(ctx->size)); } +} +#endif + +static void time_eacs_(unsigned long MAC_SIZE) +{ +#if defined(LTC_EAX_MODE) || defined(LTC_OCB_MODE) || defined(LTC_OCB3_MODE) || \ + defined(LTC_CCM_MODE) || defined(LTC_GCM_MODE) || defined(LTC_SIV_MODE) + eac_ctx ctx; + struct { + const char *name; + void (*time_fun)(eac_ctx*); + } time_funs[] = { +#define TIME_FUN(n) { #n, time_ ## n } +#ifdef LTC_EAX_MODE + TIME_FUN(eax), #endif +#ifdef LTC_OCB_MODE + TIME_FUN(ocb), +#endif +#ifdef LTC_OCB3_MODE + TIME_FUN(ocb3), +#endif +#ifdef LTC_CCM_MODE + TIME_FUN(ccm), +#endif +#ifdef LTC_GCM_MODE + TIME_FUN(gcm), +#endif +#ifdef LTC_SIV_MODE + TIME_FUN(siv), +#endif +#undef TIME_FUN + }; + unsigned long n; + + fprintf(stderr, "\nENC+MAC Timings (zero byte AAD, 16 byte IV, cycles/byte on %luKB blocks):\n", MAC_SIZE); + + ctx.size = MAC_SIZE*1024; + ctx.buf = XMALLOC(ctx.size); + if (ctx.buf == NULL) { + fprintf(stderr, "\n\nout of heap yo\n\n"); + exit(EXIT_FAILURE); + } + + ctx.cipher_idx = find_cipher("aes"); + + yarrow_read(ctx.buf, ctx.size, &yarrow_prng); + yarrow_read(ctx.key, sizeof(ctx.key), &yarrow_prng); + yarrow_read(ctx.IV, sizeof(ctx.IV), &yarrow_prng); + + for (n = 0; n < LTC_ARRAY_SIZE(time_funs); ++n) { + if (!should_skip(time_funs[n].name)) + time_funs[n].time_fun(&ctx); + } - XFREE(buf); + XFREE(ctx.buf); #else LTC_UNUSED_PARAM(MAC_SIZE); fprintf(stderr, "NO ENCMACs\n"); @@ -1393,11 +1540,11 @@ __attribute__ ((aligned (16))) } -static void time_encmacs(void) +static void time_eacs(void) { - time_encmacs_(1); - time_encmacs_(4); - time_encmacs_(32); + time_eacs_(1); + time_eacs_(4); + time_eacs_(32); } static void LTC_NORETURN die(int status) @@ -1434,7 +1581,7 @@ const struct LTC_TEST_FN(cipher_lrw), LTC_TEST_FN(hash), LTC_TEST_FN(macs), - LTC_TEST_FN(encmacs), + LTC_TEST_FN(eacs), LTC_TEST_FN(prng), LTC_TEST_FN(mult), LTC_TEST_FN(sqr), From f2f95f3de185fff09aef3739783a05a9b3220a8a Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 15 Apr 2026 18:17:54 +0200 Subject: [PATCH 06/12] Fix build with `-DLTC_MINIMAL`. Fixes: 661109f660a3 ("re-factor modes to use internal ECB implementation") Signed-off-by: Steffen Jaeckel --- src/headers/tomcrypt_custom.h | 1 + tests/ecc_test.c | 6 +++++- tests/file_test.c | 4 ++++ tests/multi_test.c | 7 +++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index ed1440082..914d190aa 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -126,6 +126,7 @@ #define LTC_RIJNDAEL #define LTC_SHA256 #define LTC_YARROW + #define LTC_ECB_MODE #define LTC_CTR_MODE #define LTC_RNG_MAKE_PRNG diff --git a/tests/ecc_test.c b/tests/ecc_test.c index f2c5ee1bf..33d6363e8 100644 --- a/tests/ecc_test.c +++ b/tests/ecc_test.c @@ -2098,5 +2098,9 @@ int ecc_test(void) #endif return CRYPT_OK; } - +#else +int ecc_test(void) +{ + return CRYPT_NOP; +} #endif diff --git a/tests/file_test.c b/tests/file_test.c index c410d8963..294e95500 100644 --- a/tests/file_test.c +++ b/tests/file_test.c @@ -28,6 +28,10 @@ int file_test(void) isha256 = find_hash("sha256"); iaes = find_cipher("aes"); + /* Suppress warnings when building with -DLTC_MINIMAL */ + LTC_UNUSED_PARAM(iaes); + LTC_UNUSED_PARAM(key); + len = sizeof(buf); if ((in = fopen(fname, "rb")) == NULL) return CRYPT_FILE_NOTFOUND; err = hash_filehandle(isha256, in, buf, &len); diff --git a/tests/multi_test.c b/tests/multi_test.c index e02940554..94236c1b1 100644 --- a/tests/multi_test.c +++ b/tests/multi_test.c @@ -9,10 +9,16 @@ int multi_test(void) unsigned char buf[2][MAXBLOCKSIZE]; unsigned long len, len2; + /* Suppress warnings when building with -DLTC_MINIMAL */ + LTC_UNUSED_PARAM(key); + LTC_UNUSED_PARAM(buf); + LTC_UNUSED_PARAM(len); + LTC_UNUSED_PARAM(len2); /* register algos */ register_hash(&sha256_desc); register_cipher(&aes_desc); +#ifdef LTC_HASH_HELPERS /* HASH testing */ len = sizeof(buf[0]); #if defined(ENDIAN_32BITWORD) || defined(_WIN32) || defined(ENDIAN_64BITWORD_ILP32) @@ -43,6 +49,7 @@ int multi_test(void) printf("Failed: %d %lu %lu\n", __LINE__, len, len2); return CRYPT_FAIL_TESTVECTOR; } +#endif #ifdef LTC_HMAC len = sizeof(buf[0]); From ab8721fe8f0f6c6d255df38b4dcfc2a6b610d27c Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 15 Apr 2026 18:23:39 +0200 Subject: [PATCH 07/12] Fix some `ifdefs`, include guards and a function call. Fixes: 7ac05df90261 ("Add x86-optimized SHA1.") Fixes: 874e095a19c1 ("SHA-256 & SHA-224 x86") Signed-off-by: Steffen Jaeckel --- src/hashes/sha1_x86.c | 2 +- src/hashes/sha2/sha224_desc.c | 2 +- src/hashes/sha2/sha224_x86.c | 4 ++-- src/misc/crypt/crypt.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hashes/sha1_x86.c b/src/hashes/sha1_x86.c index 8f65665da..a42134352 100644 --- a/src/hashes/sha1_x86.c +++ b/src/hashes/sha1_x86.c @@ -8,7 +8,7 @@ */ -#ifdef LTC_SHA1_X86 +#if defined(LTC_SHA1) && defined(LTC_SHA1_X86) #if defined(__GNUC__) #pragma GCC diagnostic push diff --git a/src/hashes/sha2/sha224_desc.c b/src/hashes/sha2/sha224_desc.c index ccf4b9e89..4a6c9ba36 100644 --- a/src/hashes/sha2/sha224_desc.c +++ b/src/hashes/sha2/sha224_desc.c @@ -27,7 +27,7 @@ const struct ltc_hash_descriptor sha224_desc = NULL }; -#if defined LTC_SHA256_X86 +#if defined LTC_SHA224_X86 #if !defined (LTC_S_X86_CPUID) #define LTC_S_X86_CPUID diff --git a/src/hashes/sha2/sha224_x86.c b/src/hashes/sha2/sha224_x86.c index 8f9dd831b..f562b34a0 100644 --- a/src/hashes/sha2/sha224_x86.c +++ b/src/hashes/sha2/sha224_x86.c @@ -7,7 +7,7 @@ #include "tomcrypt_private.h" -#if defined(LTC_SHA224) && defined(LTC_SHA256) && defined(LTC_SHA224_X86) +#if defined(LTC_SHA224) && defined(LTC_SHA256) && defined(LTC_SHA224_X86) && defined(LTC_SHA256_X86) const struct ltc_hash_descriptor sha224_x86_desc = { @@ -66,7 +66,7 @@ int sha224_x86_done(hash_state * md, unsigned char *out) LTC_ARGCHK(md != NULL); LTC_ARGCHK(out != NULL); - err = sha256_done(md, buf); + err = sha256_x86_done(md, buf); XMEMCPY(out, buf, 28); #ifdef LTC_CLEAN_STACK zeromem(buf, sizeof(buf)); diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index 3851006d9..26fe4fbb3 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -505,13 +505,13 @@ const char *crypt_build_settings = #if defined(LTC_PEM_SSH) " OpenSSH-PEM " #endif -#if defined(LTC_SHA1_X86) +#if defined(LTC_SHA1) && defined(LTC_SHA1_X86) " SHA1-NI " #endif -#if defined(LTC_SHA224_X86) +#if defined(LTC_SHA224) && defined(LTC_SHA224_X86) " SHA224-NI " #endif -#if defined(LTC_SHA256_X86) +#if defined(LTC_SHA256) && defined(LTC_SHA256_X86) " SHA256-NI " #endif #if defined(LTC_DEVRANDOM) From 31a69672ba3a6a332127d677db20cd6704f6ee8d Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Apr 2026 10:11:22 +0200 Subject: [PATCH 08/12] Replace `int* recid` hack in ECC. Link: libtom/libtomcrypt#724 Signed-off-by: Steffen Jaeckel --- src/headers/tomcrypt_pk.h | 3 ++- src/pk/ecc/ecc_recover_key.c | 2 +- src/pk/ecc/ecc_sign_hash_eth27.c | 10 ++++------ src/pk/ecc/ecc_sign_hash_internal.c | 4 ++-- tests/ecc_test.c | 20 ++++++++++---------- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 5fee1a2ba..25876f970 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -404,7 +404,8 @@ typedef struct ltc_ecc_sig_opts { * This must be set in case one requires the recovery ID of a * signature operation. */ - int *recid; + unsigned char enable_recovery_id; + int recovery_id; /** The hash algorithm to use when creating a signature. * Setting this will enable RFC6979 compatible signature generation. diff --git a/src/pk/ecc/ecc_recover_key.c b/src/pk/ecc/ecc_recover_key.c index ebd1a410d..7d1e01e4c 100644 --- a/src/pk/ecc/ecc_recover_key.c +++ b/src/pk/ecc/ecc_recover_key.c @@ -65,7 +65,7 @@ int ecc_recover_key(const unsigned char *sig, unsigned long siglen, err = CRYPT_MEM; goto error; } - recid = (opts->recid != NULL) ? *(opts->recid) : -1; + recid = (opts->enable_recovery_id) ? opts->recovery_id : -1; if (opts->type == LTC_ECCSIG_RFC7518) { /* RFC7518 format - raw (r,s) */ diff --git a/src/pk/ecc/ecc_sign_hash_eth27.c b/src/pk/ecc/ecc_sign_hash_eth27.c index 4944d4527..d340070d5 100644 --- a/src/pk/ecc/ecc_sign_hash_eth27.c +++ b/src/pk/ecc/ecc_sign_hash_eth27.c @@ -19,7 +19,7 @@ int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, ltc_ecc_sig_opts *opts, const ecc_key *key) { - int err, recid; + int err; void *r, *s; unsigned long i; @@ -37,9 +37,9 @@ int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen, return CRYPT_BUFFER_OVERFLOW; } + opts->enable_recovery_id = 1; + if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err; - if (opts->recid == NULL) - opts->recid = &recid; if ((err = ecc_sign_hash_internal(in, inlen, r, s, opts, key)) != CRYPT_OK) goto error; zeromem(out, 65); @@ -48,12 +48,10 @@ int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen, if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error; i = ltc_mp_unsigned_bin_size(s); if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error; - out[64] = (unsigned char)(*(opts->recid) + 27); /* Recovery ID is 27/28 for Ethereum */ + out[64] = (unsigned char)(opts->recovery_id + 27); /* Recovery ID is 27/28 for Ethereum */ err = CRYPT_OK; error: - if (opts->recid == &recid) - opts->recid = NULL; ltc_mp_deinit_multi(r, s, LTC_NULL); return err; } diff --git a/src/pk/ecc/ecc_sign_hash_internal.c b/src/pk/ecc/ecc_sign_hash_internal.c index 9e2db46bc..670fbe66f 100644 --- a/src/pk/ecc/ecc_sign_hash_internal.c +++ b/src/pk/ecc/ecc_sign_hash_internal.c @@ -67,7 +67,7 @@ int ecc_sign_hash_internal(const unsigned char *in, unsigned long inlen, /* find r = x1 mod n */ if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; } - if (opts->recid) { + if (opts->enable_recovery_id) { /* find recovery ID (if needed) */ v = 0; if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK) { goto error; } @@ -102,7 +102,7 @@ int ecc_sign_hash_internal(const unsigned char *in, unsigned long inlen, goto errnokey; } - if (opts->recid) *opts->recid = v; + if (opts->enable_recovery_id) opts->recovery_id = v; goto errnokey; error: diff --git a/tests/ecc_test.c b/tests/ecc_test.c index 33d6363e8..90293ed35 100644 --- a/tests/ecc_test.c +++ b/tests/ecc_test.c @@ -643,21 +643,21 @@ static int s_ecc_new_api(void) #ifdef LTC_ECC_SHAMIR if (strcmp(ltc_mp.name, "TomsFastMath") != 0) { /* XXX-FIXME: TFM does not support sqrtmod_prime */ - int found = 0, recid; + int found = 0; ecc_key reckey; /* test recovery */ - sig_opts.recid = &recid; + sig_opts.enable_recovery_id = 1; len = sizeof(buf); DO(ecc_sign_hash_v2(data16, privkey.dp.size, buf, &len, &sig_opts, &privkey)); DO(ecc_set_curve(dp, &reckey)); for (k = 0; k < 2*(1+privkey.dp.cofactor); k++) { - recid = k; + sig_opts.recovery_id = k; stat = ecc_recover_key(buf, len, data16, privkey.dp.size, &sig_opts, &reckey); if (stat != CRYPT_OK) continue; /* last two will almost always fail, only possible if x<(prime mod order) */ stat = ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey); if (stat == CRYPT_OK) found++; } - sig_opts.recid = NULL; + sig_opts.enable_recovery_id = 0; if (found != 1) return CRYPT_FAIL_TESTVECTOR; /* unique match */ ecc_free(&reckey); } @@ -995,7 +995,7 @@ static int s_ecc_rfc6979(void) } }, { - NULL + 0 } }; @@ -1971,7 +1971,7 @@ static int s_ecc_test_ethereum(void) static int s_ecc_test_recovery(void) { - int i, recid, stat; + int i, stat; const ltc_ecc_curve* dp; ecc_key key, privkey, pubkey, reckey; unsigned char buf[1000]; @@ -1998,7 +1998,7 @@ static int s_ecc_test_recovery(void) ltc_ecc_sig_opts sig_opts = { .prng = &yarrow_prng, .wprng = find_prng ("yarrow"), - .recid = &recid + .enable_recovery_id = 1, }; /* XXX-FIXME: TFM does not support sqrtmod_prime */ @@ -2011,14 +2011,14 @@ static int s_ecc_test_recovery(void) DO(ecc_set_key(eth_pubkey, sizeof(eth_pubkey), PK_PUBLIC, &pubkey)); DO(ecc_set_curve(dp, &reckey)); - recid = 0; + sig_opts.recovery_id = 0; sig_opts.type = LTC_ECCSIG_RFC7518; DO(ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), &sig_opts, &reckey)); DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey)); ecc_free(&reckey); DO(ecc_set_curve(dp, &reckey)); - recid = -1; + sig_opts.recovery_id = -1; sig_opts.type = LTC_ECCSIG_ETH27; DO(ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), &sig_opts, &reckey)); DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey)); @@ -2055,7 +2055,7 @@ static int s_ecc_test_recovery(void) /* test signature */ len = sizeof(buf); - recid = 0; + sig_opts.recovery_id = 0; DO(ecc_sign_hash_v2(data16, 16, buf, &len, &sig_opts, &privkey)); /* test verification */ From d7c45063e5cfde6016d9951f277362c1dbfaa904 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Apr 2026 10:15:32 +0200 Subject: [PATCH 09/12] Branch once, not on each iteration. Even though the branch predictor should get this, it's unnecessary. Signed-off-by: Steffen Jaeckel --- src/math/rand_prime.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/math/rand_prime.c b/src/math/rand_prime.c index 0cd6c0dce..6f13806ce 100644 --- a/src/math/rand_prime.c +++ b/src/math/rand_prime.c @@ -9,21 +9,19 @@ Generate a random prime, Tom St Denis */ -#define USE_BBS 1 - int rand_prime(void *N, long len, prng_state *prng, int wprng) { - int err, res, type; - unsigned char *buf; + int err, res; + unsigned char *buf, bbs; LTC_ARGCHK(N != NULL); - /* get type */ if (len < 0) { - type = USE_BBS; + /* Create BBS (Blum Blum Shub) style prime */ + bbs = 0x02; len = -len; } else { - type = 0; + bbs = 0x00; } /* allow sizes between 2 and 512 bytes for a prime size */ @@ -51,7 +49,7 @@ int rand_prime(void *N, long len, prng_state *prng, int wprng) /* munge bits */ buf[0] |= 0x80 | 0x40; - buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00); + buf[len-1] |= 0x01 | bbs; /* load value */ if ((err = ltc_mp_read_unsigned_bin(N, buf, len)) != CRYPT_OK) { From 3df108f1315f72ee30e6154bece63d69ed118120 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Apr 2026 10:16:29 +0200 Subject: [PATCH 10/12] Suppress warning emitted by Clang. Fixes: 46e0137e555b ("Optimize gcm_gf_mult using PCLMULQDQ and PMULL") Signed-off-by: Steffen Jaeckel --- src/encauth/gcm/gcm_gf_mult.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/encauth/gcm/gcm_gf_mult.c b/src/encauth/gcm/gcm_gf_mult.c index 39ce9de18..10d0ef754 100644 --- a/src/encauth/gcm/gcm_gf_mult.c +++ b/src/encauth/gcm/gcm_gf_mult.c @@ -130,10 +130,11 @@ static void s_gcm_gf_mult_pclmul(const unsigned char *a, const unsigned char *b, #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wbad-function-cast" -#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wcast-align" #pragma GCC diagnostic ignored "-Wmissing-braces" -#pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wunused-parameter" #endif #include #if defined(__GNUC__) From 04beed53e94e02869e9b1182da947e7b72eb28fc Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Apr 2026 10:29:31 +0200 Subject: [PATCH 11/12] Update PR template. Signed-off-by: Steffen Jaeckel --- .github/PULL_REQUEST_TEMPLATE.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8cd461414..eed63fdd1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,7 +2,11 @@ Thank you for your pull request. -If this fixes an existing github issue, make sure to have a line saying 'Fixes #XXXX' (without quotes) in the commit message. +If this fixes an existing github issue, make sure to have a line saying 'Fixes: ' (without quotes) in the commit message. +Please use the long format to refer to an issue 'libtom/libtomcrypt#'. + +If this fixes something (even if there exists no github issue), make sure to have a line saying 'Fixes: ("Description")' +This can be created via e.g. `git --no-pager log -1 --pretty=fixes --> @@ -11,3 +15,4 @@ If this fixes an existing github issue, make sure to have a line saying 'Fixes # * [ ] documentation is added or updated * [ ] tests are added or updated +* [ ] if this fixes something: added a `Fixes:` tag to the commit message From 3f575bb8ae12bb7872e4316784313ee0716fe084 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Apr 2026 12:17:28 +0200 Subject: [PATCH 12/12] Add a sentence about the origins of the CHC hash. Signed-off-by: Steffen Jaeckel --- doc/crypt.tex | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/crypt.tex b/doc/crypt.tex index fc879fa9a..0328543e5 100644 --- a/doc/crypt.tex +++ b/doc/crypt.tex @@ -3027,10 +3027,15 @@ \subsection{Hash Registration} applicable block ciphers (such as AES) can be turned into hash functions that other LTC functions can use. In particular this allows a cryptosystem to be designed using very few moving parts. +The \code{CHC} mode implements a Miyaguchi–Preneel Hash Construction +\footnote{\href{https://en.wikipedia.org/wiki/One-way_compression_function\#Miyaguchi–Preneel}{\nolinkurl{https://en.wikipedia.org/wiki/One-way_compression_function\#Miyaguchi-Preneel}}} +(MPHC), but provides an improved, \code{chc\_done()} implementation. + + In order to use the CHC system the developer will have to take a few extra steps. First the \textit{chc\_desc} hash -descriptor must be registered with register\_hash(). At this point the CHC hash cannot be used to hash +descriptor must be registered with \code{register\_hash()}. At this point the CHC hash cannot be used to hash data. While it is in the hash system you still have to tell the CHC code which cipher to use. This is accomplished -via the chc\_register() function. +via the \code{chc\_register()} function. \index{chc\_register()} \begin{verbatim} @@ -3038,7 +3043,7 @@ \subsection{Hash Registration} \end{verbatim} A cipher has to be registered with CHC (and also in the cipher descriptor tables with -register\_cipher()). The chc\_register() function will bind a cipher to the CHC system. Only one cipher can +\code{register\_cipher()}). The \code{chc\_register()} function will bind a cipher to the CHC system. Only one cipher can be bound to the CHC hash at a time. There are additional requirements for the system to work. \begin{enumerate}