aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--Makefile20
-rw-r--r--behex_lower.c15
-rw-r--r--behex_upper.c15
-rw-r--r--config-armv8.mk23
-rw-r--r--config-portable.mk (renamed from config.mk)10
-rw-r--r--config-x86.mk20
-rw-r--r--hmac_marshal.c8
-rw-r--r--hmac_unmarshal.c10
-rw-r--r--libsha2.74
-rw-r--r--libsha2.h2
-rw-r--r--libsha2_algorithm_output_size.32
-rw-r--r--libsha2_behex_lower.32
-rw-r--r--libsha2_behex_upper.32
-rw-r--r--libsha2_digest.32
-rw-r--r--libsha2_hmac_digest.32
-rw-r--r--libsha2_hmac_init.32
-rw-r--r--libsha2_hmac_marshal.32
-rw-r--r--libsha2_hmac_state_output_size.32
-rw-r--r--libsha2_hmac_unmarshal.32
-rw-r--r--libsha2_hmac_update.32
-rw-r--r--libsha2_init.32
-rw-r--r--libsha2_marshal.32
-rw-r--r--libsha2_state_output_size.32
-rw-r--r--libsha2_sum_fd.32
-rw-r--r--libsha2_unhex.32
-rw-r--r--libsha2_unmarshal.32
-rw-r--r--libsha2_update.32
-rw-r--r--marshal.c10
-rw-r--r--process.c266
-rw-r--r--sum_fd.c9
-rw-r--r--test.c4
-rw-r--r--unmarshal.c12
-rw-r--r--update.c4
34 files changed, 390 insertions, 78 deletions
diff --git a/LICENSE b/LICENSE
index 9f70356..27d8f80 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
ISC License
-© 2015, 2019, 2022 Mattias Andrée <maandree@kth.se>
+© 2015, 2019, 2022, 2026 Mattias Andrée <m@maandree.se>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/Makefile b/Makefile
index 76278fc..9931615 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,18 @@
.POSIX:
-CONFIGFILE = config.mk
+CONFIGFILE = config-x86.mk
+# config-x86.mk is the default because it is compatible
+# with and optimal for most machines, and if it is not
+# supported, the compilation will immediately fail. It
+# enables optimisations on x86 CPU's that have the
+# required features.
+#
+# Additionally config-arm.mk which uses optimisations
+# for ARMv8 is available.
+#
+# config-portable.mk is available for exotic CPU's
+# and compiler that do not support the features required
+# for the optimisations.
include $(CONFIGFILE)
OS = linux
@@ -11,7 +23,7 @@ include mk/$(OS).mk
LIB_MAJOR = 1
-LIB_MINOR = 0
+LIB_MINOR = 1
LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
@@ -69,7 +81,7 @@ SRC = $(OBJ:.o=.c)
all: libsha2.a libsha2.$(LIBEXT) test
-$(OBJ): $(HDR)
+$(OBJ) test.o: $(HDR)
$(LOBJ): $(HDR)
.c.o:
@@ -90,7 +102,7 @@ libsha2.a: $(OBJ)
$(AR) -s $@
check: test
- ./test
+ $(CHECK_PREFIX) ./test $(CHECK_FLAGS)
install:
mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
diff --git a/behex_lower.c b/behex_lower.c
index 575ff39..93969ad 100644
--- a/behex_lower.c
+++ b/behex_lower.c
@@ -5,10 +5,21 @@
void
libsha2_behex_lower(char *restrict output, const void *restrict hashsum_, size_t n)
{
+#define S(X)\
+ X"0", X"1", X"2", X"3", X"4", X"5", X"6", X"7",\
+ X"8", X"9", X"a", X"b", X"c", X"d", X"e", X"f"
+#if defined(__GNUC__)
+ __attribute__((__nonstring__))
+#endif
+ static const char lut[256][2] = {
+ S("0"), S("1"), S("2"), S("3"), S("4"), S("5"), S("6"), S("7"),
+ S("8"), S("9"), S("a"), S("b"), S("c"), S("d"), S("e"), S("f")
+ };
+
const unsigned char *restrict hashsum = hashsum_;
output[2 * n] = '\0';
while (n--) {
- output[2 * n + 0] = "0123456789abcdef"[(hashsum[n] >> 4) & 15];
- output[2 * n + 1] = "0123456789abcdef"[(hashsum[n] >> 0) & 15];
+ output[2 * n + 0] = lut[hashsum[n]][0];
+ output[2 * n + 1] = lut[hashsum[n]][1];
}
}
diff --git a/behex_upper.c b/behex_upper.c
index cad6778..ac56218 100644
--- a/behex_upper.c
+++ b/behex_upper.c
@@ -5,10 +5,21 @@
void
libsha2_behex_upper(char *restrict output, const void *restrict hashsum_, size_t n)
{
+#define S(X)\
+ X"0", X"1", X"2", X"3", X"4", X"5", X"6", X"7",\
+ X"8", X"9", X"A", X"B", X"C", X"D", X"E", X"F"
+#if defined(__GNUC__)
+ __attribute__((__nonstring__))
+#endif
+ static const char lut[256][2] = {
+ S("0"), S("1"), S("2"), S("3"), S("4"), S("5"), S("6"), S("7"),
+ S("8"), S("9"), S("A"), S("B"), S("C"), S("D"), S("E"), S("F")
+ };
+
const unsigned char *restrict hashsum = hashsum_;
output[2 * n] = '\0';
while (n--) {
- output[2 * n + 0] = "0123456789ABCDEF"[(hashsum[n] >> 4) & 15];
- output[2 * n + 1] = "0123456789ABCDEF"[(hashsum[n] >> 0) & 15];
+ output[2 * n + 0] = lut[hashsum[n]][0];
+ output[2 * n + 1] = lut[hashsum[n]][1];
}
}
diff --git a/config-armv8.mk b/config-armv8.mk
new file mode 100644
index 0000000..47efdc2
--- /dev/null
+++ b/config-armv8.mk
@@ -0,0 +1,23 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = cc -std=c11
+
+COMMON_SANITIZE = -fsanitize=alignment,shift,signed-integer-overflow,object-size,null,undefined,bounds,address
+CLANG_SANITIZE = -O1 $(COMMON_SANITIZE),cfi -flto -fvisibility=hidden -fno-sanitize-trap=cfi
+GCC_SANITIZE = -O1 $(COMMON_SANITIZE)
+#SANITIZE = $(CLANG_SANITIZE)
+#SANITIZE = $(GCC_SANITIZE)
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
+CFLAGS = $(SANITIZE) -Wall -O3 -march=native
+# If you cannot use -march=native, you should do e.g -march=armv8-a+crypto
+# however, you have to be careful selecting the exact version,
+# so you may have to replace armv8-a with something else.
+LDFLAGS = $(SANITIZE) -s
+
+# You can add -DALLOCA_LIMIT=# to CPPFLAGS, where # is a size_t
+# value, to put a limit on how large allocation the library is
+# allowed to make with alloca(3). For buffers that can have any
+# size this limit will be used if it wants to allocate a larger
+# buffer. Choose 0 to use malloc(3) instead of alloca(3).
diff --git a/config.mk b/config-portable.mk
index a79e63f..a905df1 100644
--- a/config.mk
+++ b/config-portable.mk
@@ -3,9 +3,15 @@ MANPREFIX = $(PREFIX)/share/man
CC = cc -std=c11
+COMMON_SANITIZE = -fsanitize=alignment,shift,signed-integer-overflow,object-size,null,undefined,bounds,address
+CLANG_SANITIZE = -O1 $(COMMON_SANITIZE),cfi -flto -fvisibility=hidden -fno-sanitize-trap=cfi
+GCC_SANITIZE = -O1 $(COMMON_SANITIZE)
+#SANITIZE = $(CLANG_SANITIZE)
+#SANITIZE = $(GCC_SANITIZE)
+
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
-CFLAGS = -Wall -O3 -msse4 -msha
-LDFLAGS = -s
+CFLAGS = $(SANITIZE) -Wall -O3
+LDFLAGS = $(SANITIZE) -s
# You can add -DALLOCA_LIMIT=# to CPPFLAGS, where # is a size_t
# value, to put a limit on how large allocation the library is
diff --git a/config-x86.mk b/config-x86.mk
new file mode 100644
index 0000000..bd96527
--- /dev/null
+++ b/config-x86.mk
@@ -0,0 +1,20 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = cc -std=c11
+
+COMMON_SANITIZE = -fsanitize=alignment,shift,signed-integer-overflow,object-size,null,undefined,bounds,address
+CLANG_SANITIZE = -O1 $(COMMON_SANITIZE),cfi -flto -fvisibility=hidden -fno-sanitize-trap=cfi
+GCC_SANITIZE = -O1 $(COMMON_SANITIZE)
+#SANITIZE = $(CLANG_SANITIZE)
+#SANITIZE = $(GCC_SANITIZE)
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
+CFLAGS = $(SANITIZE) -Wall -O3 -msse4 -msha
+LDFLAGS = $(SANITIZE) -s
+
+# You can add -DALLOCA_LIMIT=# to CPPFLAGS, where # is a size_t
+# value, to put a limit on how large allocation the library is
+# allowed to make with alloca(3). For buffers that can have any
+# size this limit will be used if it wants to allocate a larger
+# buffer. Choose 0 to use malloc(3) instead of alloca(3).
diff --git a/hmac_marshal.c b/hmac_marshal.c
index 6db8972..e234f76 100644
--- a/hmac_marshal.c
+++ b/hmac_marshal.c
@@ -5,21 +5,21 @@
size_t
libsha2_hmac_marshal(const struct libsha2_hmac_state *restrict state, void *restrict buf_)
{
- char *restrict buf = buf_;
+ unsigned char *restrict buf = buf_;
size_t off = 0;
if (buf)
- *(int *)buf = 0; /* version */
+ memcpy(buf, &(int){0}, sizeof(int)); /* version */
off += sizeof(int);
off += libsha2_marshal(&state->sha2_state, buf ? &buf[off] : NULL);
if (buf)
- *(size_t *)&buf[off] = state->outsize;
+ memcpy(&buf[off], &state->outsize, sizeof(size_t));
off += sizeof(size_t);
if (buf)
- *(unsigned char *)&buf[off] = state->inited;
+ buf[off] = state->inited;
off += sizeof(unsigned char);
if (buf)
diff --git a/hmac_unmarshal.c b/hmac_unmarshal.c
index 197ea32..5ce2a5e 100644
--- a/hmac_unmarshal.c
+++ b/hmac_unmarshal.c
@@ -5,16 +5,18 @@
size_t
libsha2_hmac_unmarshal(struct libsha2_hmac_state *restrict state, const void *restrict buf_, size_t bufsize)
{
- const char *restrict buf = buf_;
+ const unsigned char *restrict buf = buf_;
size_t off = 0;
size_t r;
+ int version;
if (bufsize < sizeof(int)) {
errno = EINVAL;
return 0;
}
- if (*(const int *)buf) { /* version */
+ memcpy(&version, buf, sizeof(int));
+ if (version != 0) {
errno = EINVAL;
return 0;
}
@@ -30,10 +32,10 @@ libsha2_hmac_unmarshal(struct libsha2_hmac_state *restrict state, const void *re
return 0;
}
- state->outsize = *(const size_t *)&buf[off];
+ memcpy(&state->outsize, &buf[off], sizeof(size_t));
off += sizeof(size_t);
- state->inited = *(const unsigned char *)&buf[off];
+ state->inited = buf[off];
off += sizeof(unsigned char);
memcpy(state->ipad, &buf[off], state->sha2_state.chunk_size);
diff --git a/libsha2.7 b/libsha2.7
index b78db0a..3da7907 100644
--- a/libsha2.7
+++ b/libsha2.7
@@ -1,8 +1,8 @@
-.TH LIBSHA2 7 2022-07-07 libsha1
+.TH LIBSHA2 7 LIBSHA2
.SH NAME
libsha2 \- SHA-2 hashing library
.SH DESCRIPTION
-.B libsha1
+.B libsha2
is an implementation of the SHA-2 family hashing functions:
SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256;
with support for state marshalling and HMAC.
diff --git a/libsha2.h b/libsha2.h
index 87c8c20..51b8344 100644
--- a/libsha2.h
+++ b/libsha2.h
@@ -67,7 +67,7 @@ struct libsha2_state {
* For 32-bit algorithms
*/
uint_least32_t b32[64];
-
+
/**
* For 64-bit algorithms
*/
diff --git a/libsha2_algorithm_output_size.3 b/libsha2_algorithm_output_size.3
index d083a38..32fb95a 100644
--- a/libsha2_algorithm_output_size.3
+++ b/libsha2_algorithm_output_size.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_ALGORITHM_OUTPUT_SIZE 3 2019-02-09 libsha2
+.TH LIBSHA2_ALGORITHM_OUTPUT_SIZE 3 LIBSHA2
.SH NAME
libsha2_algorithm_output_size \- Get the size of the output for a SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_behex_lower.3 b/libsha2_behex_lower.3
index 1172397..e0ce17f 100644
--- a/libsha2_behex_lower.3
+++ b/libsha2_behex_lower.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_BEHEX_LOWER 3 2019-02-09 libsha2
+.TH LIBSHA2_BEHEX_LOWER 3 LIBSHA2
.SH NAME
libsha2_behex_lower \- Convert binary to lower case hexadecimal
.SH SYNOPSIS
diff --git a/libsha2_behex_upper.3 b/libsha2_behex_upper.3
index c65202b..4d24b99 100644
--- a/libsha2_behex_upper.3
+++ b/libsha2_behex_upper.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_BEHEX_UPPER 3 2019-02-09 libsha2
+.TH LIBSHA2_BEHEX_UPPER 3 LIBSHA2
.SH NAME
libsha2_behex_upper \- Convert binary to upper case hexadecimal
.SH SYNOPSIS
diff --git a/libsha2_digest.3 b/libsha2_digest.3
index 127171d..afd4d10 100644
--- a/libsha2_digest.3
+++ b/libsha2_digest.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_DIGEST 3 2019-02-09 libsha2
+.TH LIBSHA2_DIGEST 3 LIBSHA2
.SH NAME
libsha2_digest \- Get the result of a SHA-2 hashing
.SH SYNOPSIS
diff --git a/libsha2_hmac_digest.3 b/libsha2_hmac_digest.3
index 1203049..faf6ab2 100644
--- a/libsha2_hmac_digest.3
+++ b/libsha2_hmac_digest.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_HMAC_DIGEST 3 2019-02-10 libsha2
+.TH LIBSHA2_HMAC_DIGEST 3 LIBSHA2
.SH NAME
libsha2_hmac_digest \- Get the result of a HMAC-SHA-2 hashing
.SH SYNOPSIS
diff --git a/libsha2_hmac_init.3 b/libsha2_hmac_init.3
index 6f09680..bffe76c 100644
--- a/libsha2_hmac_init.3
+++ b/libsha2_hmac_init.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_HMAC_INIT 3 2019-02-10 libsha2
+.TH LIBSHA2_HMAC_INIT 3 LIBSHA2
.SH NAME
libsha2_hmac_init \- Initialises hashing with an HMAC-SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_hmac_marshal.3 b/libsha2_hmac_marshal.3
index eca380c..48fe001 100644
--- a/libsha2_hmac_marshal.3
+++ b/libsha2_hmac_marshal.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_HMAC_MARSHAL 3 2019-02-10 libsha2
+.TH LIBSHA2_HMAC_MARSHAL 3 LIBSHA2
.SH NAME
libsha2_hmac_marshal \- Marshal an HMAC-SHA-2 hashing state
.SH SYNOPSIS
diff --git a/libsha2_hmac_state_output_size.3 b/libsha2_hmac_state_output_size.3
index aa96436..93c2daf 100644
--- a/libsha2_hmac_state_output_size.3
+++ b/libsha2_hmac_state_output_size.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_HMAC_STATE_OUTPUT_SIZE 3 2019-02-10 libsha2
+.TH LIBSHA2_HMAC_STATE_OUTPUT_SIZE 3 LIBSHA2
.SH NAME
libsha2_hmac_state_output_size \- Get the size of the output for a HMAC-SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_hmac_unmarshal.3 b/libsha2_hmac_unmarshal.3
index 6cc2967..467595c 100644
--- a/libsha2_hmac_unmarshal.3
+++ b/libsha2_hmac_unmarshal.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_HMAC_UNMARSHAL 3 2019-02-10 libsha2
+.TH LIBSHA2_HMAC_UNMARSHAL 3 LIBSHA2
.SH NAME
libsha2_hmac_unmarshal \- Unmarshal an HMAC-SHA-2 hashing state
.SH SYNOPSIS
diff --git a/libsha2_hmac_update.3 b/libsha2_hmac_update.3
index bb02a18..7764c6e 100644
--- a/libsha2_hmac_update.3
+++ b/libsha2_hmac_update.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_HMAC_UPDATE 3 2019-02-10 libsha2
+.TH LIBSHA2_HMAC_UPDATE 3 LIBSHA2
.SH NAME
libsha2_hmac_update \- Feed data into a HMAC-SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_init.3 b/libsha2_init.3
index 5823464..aca97b0 100644
--- a/libsha2_init.3
+++ b/libsha2_init.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_INIT 3 2019-02-09 libsha2
+.TH LIBSHA2_INIT 3 LIBSHA2
.SH NAME
libsha2_init \- Initialises hashing with a SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_marshal.3 b/libsha2_marshal.3
index 4b44533..ecb5031 100644
--- a/libsha2_marshal.3
+++ b/libsha2_marshal.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_MARSHAL 3 2019-02-09 libsha2
+.TH LIBSHA2_MARSHAL 3 LIBSHA2
.SH NAME
libsha2_marshal \- Marshal a SHA-2 hashing state
.SH SYNOPSIS
diff --git a/libsha2_state_output_size.3 b/libsha2_state_output_size.3
index 591eace..ef3130b 100644
--- a/libsha2_state_output_size.3
+++ b/libsha2_state_output_size.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_STATE_OUTPUT_SIZE 3 2019-02-09 libsha2
+.TH LIBSHA2_STATE_OUTPUT_SIZE 3 LIBSHA2
.SH NAME
libsha2_state_output_size \- Get the size of the output for a SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_sum_fd.3 b/libsha2_sum_fd.3
index 8850e01..07e1864 100644
--- a/libsha2_sum_fd.3
+++ b/libsha2_sum_fd.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_SUM_FD 3 2019-02-09 libsha2
+.TH LIBSHA2_SUM_FD 3 LIBSHA2
.SH NAME
libsha2_sum_fd \- Hash a file with a SHA-2 algorithm
.SH SYNOPSIS
diff --git a/libsha2_unhex.3 b/libsha2_unhex.3
index 7e009a0..5737057 100644
--- a/libsha2_unhex.3
+++ b/libsha2_unhex.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_UNHEX 3 2019-02-09 libsha2
+.TH LIBSHA2_UNHEX 3 LIBSHA2
.SH NAME
libsha2_unhex \- Covert hexadecimal to binary
.SH SYNOPSIS
diff --git a/libsha2_unmarshal.3 b/libsha2_unmarshal.3
index 5df4929..a33eec5 100644
--- a/libsha2_unmarshal.3
+++ b/libsha2_unmarshal.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_UNMARSHAL 3 2019-02-09 libsha2
+.TH LIBSHA2_UNMARSHAL 3 LIBSHA2
.SH NAME
libsha2_unmarshal \- Unmarshal a SHA-2 hashing state
.SH SYNOPSIS
diff --git a/libsha2_update.3 b/libsha2_update.3
index b7baf39..e64c972 100644
--- a/libsha2_update.3
+++ b/libsha2_update.3
@@ -1,4 +1,4 @@
-.TH LIBSHA2_UPDATE 3 2019-02-09 libsha2
+.TH LIBSHA2_UPDATE 3 LIBSHA2
.SH NAME
libsha2_update \- Feed data into a SHA-2 algorithm
.SH SYNOPSIS
diff --git a/marshal.c b/marshal.c
index 7596c03..d5ceb28 100644
--- a/marshal.c
+++ b/marshal.c
@@ -5,17 +5,17 @@
size_t
libsha2_marshal(const struct libsha2_state *restrict state, void *restrict buf_)
{
- char *restrict buf = buf_;
+ unsigned char *restrict buf = buf_;
size_t off = 0;
if (buf)
- *(int *)buf = 1; /* version */
+ memcpy(buf, &(int){1}, sizeof(int));
off += sizeof(int);
if (buf)
- *(enum libsha2_algorithm *)&buf[off] = state->algorithm;
+ memcpy(&buf[off], &state->algorithm, sizeof(enum libsha2_algorithm));
off += sizeof(enum libsha2_algorithm);
if (buf)
- *(size_t *)&buf[off] = state->message_size;
+ memcpy(&buf[off], &state->message_size, sizeof(size_t));
off += sizeof(size_t);
if (state->algorithm <= LIBSHA2_256) {
@@ -35,7 +35,7 @@ libsha2_marshal(const struct libsha2_state *restrict state, void *restrict buf_)
}
if (buf)
- *(size_t *)&buf[off] = state->chunk_size;
+ memcpy(&buf[off], &state->chunk_size, sizeof(size_t));
off += sizeof(size_t);
if (buf)
memcpy(&buf[off], state->chunk, (state->message_size / 8) % state->chunk_size);
diff --git a/process.c b/process.c
index eef61f8..020c33b 100644
--- a/process.c
+++ b/process.c
@@ -1,16 +1,35 @@
/* See LICENSE file for copyright and license details. */
#include "common.h"
+#include <errno.h>
#include <stdatomic.h>
#if defined(__SSE4_1__) && defined(__SSSE3__) && defined(__SSE2__) && defined(__SHA__)
-# define HAVE_X86_SHA_INTRINSICS
+# define HAVE_X86_SHA256_INTRINSICS
+#endif
+
+#if defined(__arm__) || defined(__aarch32__) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM)
+# if defined(__ARM_NEON) && (defined(__ARM_ACLE) || defined(__ARM_FEATURE_CRYPTO))
+# define HAVE_ARM_SHA2_INTRINSICS
+# endif
#endif
-#ifdef HAVE_X86_SHA_INTRINSICS
+#ifdef HAVE_X86_SHA256_INTRINSICS
# include <immintrin.h>
#endif
+#ifdef HAVE_ARM_SHA2_INTRINSICS
+# include <asm/hwcap.h>
+# include <sys/auxv.h>
+# include <arm_neon.h>
+# include <arm_acle.h>
+enum sha2_intrinsics {
+ INTRINSICS_UNKNOWN = 0xFF,
+ SHA256_INTRINSICS = 0x01,
+ SHA512_INTRINSICS = 0x02
+};
+#endif
+
/**
* Unified implementation (what can unified without performance impact)
@@ -37,13 +56,13 @@
* @param h Hash values
* @param work_h Space for temporary hash values
*/
-#define SHA2_IMPLEMENTATION(chunk, A, B, C, D, E, F, G, H, I, J, K, L, WORD_T, WORD_SIZE, TRUNC, k, w, h, work_h) \
+#define SHA2_IMPLEMENTATION(chunk, A, B, C, D, E, F, G, H, I, J, K, L, WORD_T, WORD_SIZE, TRUNC, k, w, h, work_h)\
memcpy(work_h, h, sizeof(work_h));\
\
memset(w, 0, 16 * sizeof(*(w)));\
for (i = 0; i < 16; i++)\
for (j = 0; j < WORD_SIZE; j++)\
- w[i] |= ((WORD_T)(chunk[(i + 1) * WORD_SIZE - j - 1])) << (j << 3);\
+ w[i] |= (WORD_T)(((WORD_T)(chunk[(i + 1) * WORD_SIZE - j - 1])) << (j << 3));\
\
for (i = 16; i < sizeof(k) / sizeof(*(k)); i++) {\
w[i] = w[i - 16] + w[i - 7];\
@@ -68,7 +87,7 @@
h[i] = TRUNC(h[i] + work_h[i]);
-#ifdef HAVE_X86_SHA_INTRINSICS
+#ifdef HAVE_X86_SHA256_INTRINSICS
static size_t
process_x86_sha256(struct libsha2_state *restrict state, const unsigned char *restrict data, size_t len)
@@ -79,8 +98,8 @@ process_x86_sha256(struct libsha2_state *restrict state, const unsigned char *re
const unsigned char *restrict chunk;
size_t off = 0;
- temp = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i *)&state->h.b32[0]), 0xB1);
- s1 = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i *)&state->h.b32[4]), 0x1B);
+ temp = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i *)(const unsigned char *)&state->h.b32[0]), 0xB1);
+ s1 = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i *)(const unsigned char *)&state->h.b32[4]), 0x1B);
s0 = _mm_alignr_epi8(temp, s1, 8);
s1 = _mm_blend_epi16(s1, temp, 0xF0);
@@ -90,6 +109,11 @@ process_x86_sha256(struct libsha2_state *restrict state, const unsigned char *re
abef_orig = s0;
cdgh_orig = s1;
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+
msg = _mm_loadu_si128((const __m128i *)&chunk[0]);
msg0 = _mm_shuffle_epi8(msg, SHUFFLE_MASK);
msg = _mm_add_epi32(msg0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCFULL, 0x71374491428A2F98ULL));
@@ -226,6 +250,10 @@ process_x86_sha256(struct libsha2_state *restrict state, const unsigned char *re
msg = _mm_shuffle_epi32(msg, 0x0E);
s0 = _mm_sha256rnds2_epu32(s0, s1, msg);
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+
s0 = _mm_add_epi32(s0, abef_orig);
s1 = _mm_add_epi32(s1, cdgh_orig);
}
@@ -247,14 +275,14 @@ __attribute__((__constructor__))
static int
have_sha_intrinsics(void)
{
- static volatile int ret = -1;
- static volatile atomic_flag spinlock = ATOMIC_FLAG_INIT;
+ static volatile int ret = -1;
+ static volatile atomic_flag spinlock = ATOMIC_FLAG_INIT;
int a, b, c, d;
if (ret != -1)
return ret;
- while (atomic_flag_test_and_set(&spinlock));
+ while (atomic_flag_test_and_set(&spinlock));
if (ret != -1)
goto out;
@@ -281,6 +309,200 @@ out:
#endif
+#ifdef HAVE_ARM_SHA2_INTRINSICS
+
+static size_t
+process_arm_sha256(struct libsha2_state *restrict state, const unsigned char *restrict data, size_t len)
+{
+ static const uint32_t rc[] = {
+ UINT32_C(0x428A2F98), UINT32_C(0x71374491), UINT32_C(0xB5C0FBCF), UINT32_C(0xE9B5DBA5),
+ UINT32_C(0x3956C25B), UINT32_C(0x59F111F1), UINT32_C(0x923F82A4), UINT32_C(0xAB1C5ED5),
+ UINT32_C(0xD807AA98), UINT32_C(0x12835B01), UINT32_C(0x243185BE), UINT32_C(0x550C7DC3),
+ UINT32_C(0x72BE5D74), UINT32_C(0x80DEB1FE), UINT32_C(0x9BDC06A7), UINT32_C(0xC19BF174),
+ UINT32_C(0xE49B69C1), UINT32_C(0xEFBE4786), UINT32_C(0x0FC19DC6), UINT32_C(0x240CA1CC),
+ UINT32_C(0x2DE92C6F), UINT32_C(0x4A7484AA), UINT32_C(0x5CB0A9DC), UINT32_C(0x76F988DA),
+ UINT32_C(0x983E5152), UINT32_C(0xA831C66D), UINT32_C(0xB00327C8), UINT32_C(0xBF597FC7),
+ UINT32_C(0xC6E00BF3), UINT32_C(0xD5A79147), UINT32_C(0x06CA6351), UINT32_C(0x14292967),
+ UINT32_C(0x27B70A85), UINT32_C(0x2E1B2138), UINT32_C(0x4D2C6DFC), UINT32_C(0x53380D13),
+ UINT32_C(0x650A7354), UINT32_C(0x766A0ABB), UINT32_C(0x81C2C92E), UINT32_C(0x92722C85),
+ UINT32_C(0xA2BFE8A1), UINT32_C(0xA81A664B), UINT32_C(0xC24B8B70), UINT32_C(0xC76C51A3),
+ UINT32_C(0xD192E819), UINT32_C(0xD6990624), UINT32_C(0xF40E3585), UINT32_C(0x106AA070),
+ UINT32_C(0x19A4C116), UINT32_C(0x1E376C08), UINT32_C(0x2748774C), UINT32_C(0x34B0BCB5),
+ UINT32_C(0x391C0CB3), UINT32_C(0x4ED8AA4A), UINT32_C(0x5B9CCA4F), UINT32_C(0x682E6FF3),
+ UINT32_C(0x748F82EE), UINT32_C(0x78A5636F), UINT32_C(0x84C87814), UINT32_C(0x8CC70208),
+ UINT32_C(0x90BEFFFA), UINT32_C(0xA4506CEB), UINT32_C(0xBEF9A3F7), UINT32_C(0xC67178F2)
+ };
+
+ uint32x4_t abcd, efgh, abcd_orig, efgh_orig;
+ uint32x4_t msg0, msg1, msg2, msg3, tmp0, tmp1, tmp2;
+ const unsigned char *restrict chunk;
+ size_t off = 0;
+
+ abcd_orig = vld1q_u32(&state->h.b32[0]);
+ efgh_orig = vld1q_u32(&state->h.b32[4]);
+
+ for (; len - off >= state->chunk_size; off += state->chunk_size) {
+ abcd = abcd_orig;
+ efgh = efgh_orig;
+
+ chunk = &data[off];
+ msg0 = vld1q_u32((const uint32_t *)&chunk[0]);
+ msg1 = vld1q_u32((const uint32_t *)&chunk[16]);
+ msg2 = vld1q_u32((const uint32_t *)&chunk[32]);
+ msg3 = vld1q_u32((const uint32_t *)&chunk[48]);
+ msg0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(msg0)));
+ msg1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(msg1)));
+ msg2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(msg2)));
+ msg3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(msg3)));
+
+ tmp0 = vaddq_u32(msg0, vld1q_u32(&rc[0 * 4]));
+
+ msg0 = vsha256su0q_u32(msg0, msg1);
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg1, vld1q_u32(&rc[1 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+ msg0 = vsha256su1q_u32(msg0, msg2, msg3);
+
+ msg1 = vsha256su0q_u32(msg1, msg2);
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg2, vld1q_u32(&rc[2 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+ msg1 = vsha256su1q_u32(msg1, msg3, msg0);
+
+ msg2 = vsha256su0q_u32(msg2, msg3);
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg3, vld1q_u32(&rc[3 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+ msg2 = vsha256su1q_u32(msg2, msg0, msg1);
+
+ msg3 = vsha256su0q_u32(msg3, msg0);
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg0, vld1q_u32(&rc[4 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+ msg3 = vsha256su1q_u32(msg3, msg1, msg2);
+
+ msg0 = vsha256su0q_u32(msg0, msg1);
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg1, vld1q_u32(&rc[5 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+ msg0 = vsha256su1q_u32(msg0, msg2, msg3);
+
+ msg1 = vsha256su0q_u32(msg1, msg2);
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg2, vld1q_u32(&rc[6 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+ msg1 = vsha256su1q_u32(msg1, msg3, msg0);
+
+ msg2 = vsha256su0q_u32(msg2, msg3);
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg3, vld1q_u32(&rc[7 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+ msg2 = vsha256su1q_u32(msg2, msg0, msg1);
+
+ msg3 = vsha256su0q_u32(msg3, msg0);
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg0, vld1q_u32(&rc[8 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+ msg3 = vsha256su1q_u32(msg3, msg1, msg2);
+
+ msg0 = vsha256su0q_u32(msg0, msg1);
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg1, vld1q_u32(&rc[9 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+ msg0 = vsha256su1q_u32(msg0, msg2, msg3);
+
+ msg1 = vsha256su0q_u32(msg1, msg2);
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg2, vld1q_u32(&rc[10 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+ msg1 = vsha256su1q_u32(msg1, msg3, msg0);
+
+ msg2 = vsha256su0q_u32(msg2, msg3);
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg3, vld1q_u32(&rc[11 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+ msg2 = vsha256su1q_u32(msg2, msg0, msg1);
+
+ msg3 = vsha256su0q_u32(msg3, msg0);
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg0, vld1q_u32(&rc[12 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+ msg3 = vsha256su1q_u32(msg3, msg1, msg2);
+
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg1, vld1q_u32(&rc[13 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+
+ tmp2 = abcd;
+ tmp0 = vaddq_u32(msg2, vld1q_u32(&rc[14 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+
+ tmp2 = abcd;
+ tmp1 = vaddq_u32(msg3, vld1q_u32(&rc[15 * 4]));
+ abcd = vsha256hq_u32(abcd, efgh, tmp0);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp0);
+
+ tmp2 = abcd;
+ abcd = vsha256hq_u32(abcd, efgh, tmp1);
+ efgh = vsha256h2q_u32(efgh, tmp2, tmp1);
+
+ abcd_orig = vaddq_u32(abcd_orig, abcd);
+ efgh_orig = vaddq_u32(efgh_orig, efgh);
+ }
+
+ vst1q_u32(&state->h.b32[0], abcd_orig);
+ vst1q_u32(&state->h.b32[4], efgh_orig);
+
+ return off;
+}
+
+# if defined(__GNUC__)
+__attribute__((__constructor__))
+# endif
+static enum sha2_intrinsics
+have_sha_intrinsics(void)
+{
+ static volatile enum sha2_intrinsics ret = INTRINSICS_UNKNOWN;
+ static volatile atomic_flag spinlock = ATOMIC_FLAG_INIT;
+ unsigned long int caps;
+ enum sha2_intrinsics x;
+ int saved_errno;
+
+ if (ret != INTRINSICS_UNKNOWN)
+ return ret;
+
+ while (atomic_flag_test_and_set(&spinlock));
+
+ saved_errno = errno;
+ caps = getauxval(AT_HWCAP);
+ errno = saved_errno;
+ x = (caps & HWCAP_SHA2) ? SHA256_INTRINSICS : 0;
+ x |= (caps & HWCAP_SHA512) ? SHA512_INTRINSICS : 0;
+ ret = x;
+
+ if (ret != INTRINSICS_UNKNOWN)
+ goto out;
+
+out:
+ atomic_flag_clear(&spinlock);
+ return ret;
+}
+
+#endif
size_t
libsha2_process(struct libsha2_state *restrict state, const unsigned char *restrict data, size_t len)
@@ -289,6 +511,11 @@ libsha2_process(struct libsha2_state *restrict state, const unsigned char *restr
size_t off = 0;
if (state->algorithm <= LIBSHA2_256) {
+#if defined(HAVE_ARM_SHA2_INTRINSICS)
+ if (have_sha_intrinsics() & SHA256_INTRINSICS)
+ return process_arm_sha256(state, data, len);
+#else
+# define ROTR(X, N) TRUNC32(((X) >> (N)) | ((X) << (32 - (N))))
uint_least32_t s0, s1;
size_t i, j;
@@ -296,36 +523,33 @@ libsha2_process(struct libsha2_state *restrict state, const unsigned char *restr
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmemset-elt-size"
#endif
-#define ROTR(X, N) TRUNC32(((X) >> (N)) | ((X) << (32 - (N))))
-
-#ifdef HAVE_X86_SHA_INTRINSICS
+# ifdef HAVE_X86_SHA256_INTRINSICS
if (have_sha_intrinsics())
return process_x86_sha256(state, data, len);
-#endif
-
+# endif
for (; len - off >= state->chunk_size; off += state->chunk_size) {
chunk = &data[off];
SHA2_IMPLEMENTATION(chunk, 7, 18, 3, 17, 19, 10, 6, 11, 25, 2, 13, 22, uint_least32_t, 4,
TRUNC32, state->k.b32, state->w.b32, state->h.b32, state->work_h.b32);
}
-
-#undef ROTR
-#if defined(__GNUC__)
-# pragma GCC diagnostic pop
+# if defined(__GNUC__)
+# pragma GCC diagnostic pop
+# endif
+# undef ROTR
#endif
} else {
+#define ROTR(X, N) TRUNC64(((X) >> (N)) | ((X) << (64 - (N))))
uint_least64_t s0, s1;
size_t i, j;
-#define ROTR(X, N) TRUNC64(((X) >> (N)) | ((X) << (64 - (N))))
+ /* TODO Add optimisation using ARMv8.2 SHA-512 intrinsics (when I've access to a machine supporting it) */
for (; len - off >= state->chunk_size; off += state->chunk_size) {
chunk = &data[off];
SHA2_IMPLEMENTATION(chunk, 1, 8, 7, 19, 61, 6, 14, 18, 41, 28, 34, 39, uint_least64_t, 8,
TRUNC64, state->k.b64, state->w.b64, state->h.b64, state->work_h.b64);
}
-
#undef ROTR
}
diff --git a/sum_fd.c b/sum_fd.c
index 196efe4..23e4ca5 100644
--- a/sum_fd.c
+++ b/sum_fd.c
@@ -18,15 +18,15 @@ libsha2_sum_fd(int fd, enum libsha2_algorithm algorithm, void *restrict hashsum)
#ifndef _WIN32
if (fstat(fd, &attr) == 0 && attr.st_blksize > 0)
- blksize = (size_t)(attr.st_blksize);
+ blksize = (size_t)attr.st_blksize;
#endif
#if ALLOCA_LIMIT > 0
if (blksize > (size_t)ALLOCA_LIMIT) {
blksize = (size_t)ALLOCA_LIMIT;
- blksize -= blksize % sizeof(((struct libsha2_state)NULL)->chunk);
+ blksize -= blksize % sizeof(((struct libsha2_state *)NULL)->chunk);
if (!blksize)
- blksize = sizeof(((struct libsha2_state)NULL)->chunk);
+ blksize = sizeof(((struct libsha2_state *)NULL)->chunk);
}
# if defined(__clang__)
/* We are using a limit so it's just like declaring an array
@@ -60,8 +60,9 @@ libsha2_sum_fd(int fd, enum libsha2_algorithm algorithm, void *restrict hashsum)
}
libsha2_digest(&state, NULL, 0, hashsum);
+
#if ALLOCA_LIMIT <= 0
- free(chunk);
+ free(chunk);
#endif
return 0;
}
diff --git a/test.c b/test.c
index 9059939..b5fba45 100644
--- a/test.c
+++ b/test.c
@@ -102,7 +102,7 @@
int
main(int argc, char *argv[])
{
- char buf[8096], str[2048];
+ char buf[8192 * 32], str[2048];
struct libsha2_state s;
struct libsha2_hmac_state hs;
int skip_huge, fds[2], status;
@@ -349,7 +349,9 @@ main(int argc, char *argv[])
exit(0);
}
close(fds[1]);
+ test(!errno);
test(!libsha2_sum_fd(fds[0], LIBSHA2_256, buf));
+ errno = 0; /* malloc(3) as been found to set errno=ENOENT on success */
test(waitpid(pid, &status, 0) == pid);
test(!status);
close(fds[0]);
diff --git a/unmarshal.c b/unmarshal.c
index 8c5780d..0bfecfd 100644
--- a/unmarshal.c
+++ b/unmarshal.c
@@ -5,7 +5,7 @@
size_t
libsha2_unmarshal(struct libsha2_state *restrict state, const void *restrict buf_, size_t bufsize)
{
- const char *restrict buf = buf_;
+ const unsigned char *restrict buf = buf_;
size_t off = 0;
int version;
@@ -14,16 +14,16 @@ libsha2_unmarshal(struct libsha2_state *restrict state, const void *restrict buf
return 0;
}
- version = *(const int *)buf;
- if (version < 0 || version > 1) { /* version */
+ memcpy(&version, buf, sizeof(int));
+ if (version < 0 || version > 1) {
errno = EINVAL;
return 0;
}
off += sizeof(int);
- state->algorithm = *(const enum libsha2_algorithm *)&buf[off];
+ memcpy(&state->algorithm, &buf[off], sizeof(enum libsha2_algorithm));
off += sizeof(enum libsha2_algorithm);
- state->message_size = *(const size_t *)&buf[off];
+ memcpy(&state->message_size, &buf[off], sizeof(size_t));
off += sizeof(size_t);
switch (state->algorithm) {
@@ -68,7 +68,7 @@ libsha2_unmarshal(struct libsha2_state *restrict state, const void *restrict buf
errno = EINVAL;
return 0;
}
- state->chunk_size = *(const size_t *)&buf[off];
+ memcpy(&state->chunk_size, &buf[off], sizeof(size_t));
off += sizeof(size_t);
if (bufsize - off < (state->message_size / 8) % state->chunk_size) {
diff --git a/update.c b/update.c
index 3c46f28..5d2a8e6 100644
--- a/update.c
+++ b/update.c
@@ -5,7 +5,7 @@
void
libsha2_update(struct libsha2_state *restrict state, const void *restrict message_, size_t msglen)
{
- const char *restrict message = message_;
+ const unsigned char *restrict message = message_;
size_t n, off;
off = (state->message_size / 8) % state->chunk_size;
@@ -21,7 +21,7 @@ libsha2_update(struct libsha2_state *restrict state, const void *restrict messag
msglen -= n;
}
- off = libsha2_process(state, (const unsigned char *)message, msglen);
+ off = libsha2_process(state, message, msglen);
if (msglen > off)
memcpy(state->chunk, &message[off], msglen - off);