From cada4e633d4316a53e3299e01eaadcbe47cd3efd 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`. Related-to: libtom/libtomcrypt#727 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 299607dbf1a4d7d6b1012981ba6e3edd6aaa58ec 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 5364528e0f51eb162e81ea0ebb215abc22f2d38b 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 52b1df9f987482706a8c134ec41fd663d5130ddc 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 c77e3bcf233ae1776ccc3e55f67326ccfc1d7bd4 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 12a9c3d6e3f1ac1be3256f53a9e29b9a476d4eed 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 76e8da48d0bf4967d16560cdff89eaed1c287596 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 44e086ce7ca54661ea3da02e11b7f6b40fa9e174 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 71b20ff1567f4a94db6b222f064bafd1c0955e03 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 b9933e6fdc0e2ec4f493204b6725a46b99183cba Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 16 Apr 2026 10:16:29 +0200 Subject: [PATCH 10/12] Suppress warnings emitted by Clang. Fixes: 874e095a19c1 ("SHA-256 & SHA-224 x86") Fixes: 7ac05df90261 ("Add x86-optimized SHA1.") Fixes: 46e0137e555b ("Optimize gcm_gf_mult using PCLMULQDQ and PMULL") Fixes: 31c7f891aa84 ("add support for AES-NI instructions") Signed-off-by: Steffen Jaeckel --- src/ciphers/aes/aesni.c | 8 ++++++++ src/encauth/gcm/gcm_gf_mult.c | 13 +++++++++++-- src/hashes/sha1_x86.c | 2 +- src/hashes/sha2/sha256_x86.c | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/ciphers/aes/aesni.c b/src/ciphers/aes/aesni.c index d74722919..c4b981dda 100644 --- a/src/ciphers/aes/aesni.c +++ b/src/ciphers/aes/aesni.c @@ -20,9 +20,17 @@ const struct ltc_cipher_descriptor aesni_desc = NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" +#endif #include #include #include +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #define setup_mix(t, c) _mm_extract_epi32(_mm_aeskeygenassist_si128(t, 0), c) #define temp_load(k) _mm_loadu_si128((__m128i*)(k)) diff --git a/src/encauth/gcm/gcm_gf_mult.c b/src/encauth/gcm/gcm_gf_mult.c index 39ce9de18..c9f968ecb 100644 --- a/src/encauth/gcm/gcm_gf_mult.c +++ b/src/encauth/gcm/gcm_gf_mult.c @@ -12,6 +12,11 @@ #define LTC_GCM_PCLMUL_TARGET LTC_ATTRIBUTE((__target__("pclmul,ssse3"))) +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" +#endif #if defined(_MSC_VER) #include #else @@ -20,6 +25,9 @@ #include #include #include +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #if !defined (LTC_S_X86_CPUID) #define LTC_S_X86_CPUID @@ -130,10 +138,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__) diff --git a/src/hashes/sha1_x86.c b/src/hashes/sha1_x86.c index a42134352..c1c5408be 100644 --- a/src/hashes/sha1_x86.c +++ b/src/hashes/sha1_x86.c @@ -7,11 +7,11 @@ SHA1 code by Marek Knapek */ - #if defined(LTC_SHA1) && defined(LTC_SHA1_X86) #if defined(__GNUC__) #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" #pragma GCC diagnostic ignored "-Wuninitialized" #pragma GCC diagnostic ignored "-Wunused-function" diff --git a/src/hashes/sha2/sha256_x86.c b/src/hashes/sha2/sha256_x86.c index de79b4167..43a23c913 100644 --- a/src/hashes/sha2/sha256_x86.c +++ b/src/hashes/sha2/sha256_x86.c @@ -11,6 +11,7 @@ #if defined(__GNUC__) #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" #pragma GCC diagnostic ignored "-Wuninitialized" #pragma GCC diagnostic ignored "-Wunused-function" From f518d1787c668884c97e125844a00c5a0de575ad 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 16a690d6b02178520a4d7ec0ea30206f519c9bd6 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}