Those new files are derived from the kernel tree, namely:
tools/perf/util/sha1.c from lib/crypto/sha1.c
tools/perf/util/sha1.h from include/crypto/sha1.h
tools/perf/util/sha1_base.h from include/crypto/sha1_base.h
tools/perf/util/sha1_generic.c from crypto/sha1_generic.c
The reason that we are not syncing them with the kernel tree like other
tools header files is because of the deep dependency in
include/crypto/hash.h. It's painful to import the whole kernel crypto
driver infrastructure into tools.
The derived files get rid of struct shash_desc definition, and directly
operates on the struct sha1_state.
Signed-off-by: Yuzhuo Jing <yuzhuo@google.com>
---
tools/perf/util/Build | 2 +
tools/perf/util/sha1.c | 122 +++++++++++++++++++++++++++++++++
tools/perf/util/sha1.h | 41 +++++++++++
tools/perf/util/sha1_base.h | 103 ++++++++++++++++++++++++++++
tools/perf/util/sha1_generic.c | 49 +++++++++++++
5 files changed, 317 insertions(+)
create mode 100644 tools/perf/util/sha1.c
create mode 100644 tools/perf/util/sha1.h
create mode 100644 tools/perf/util/sha1_base.h
create mode 100644 tools/perf/util/sha1_generic.c
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 7910d908c814..ecee96b3f3fa 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -41,6 +41,8 @@ perf-util-y += rbtree.o
perf-util-y += libstring.o
perf-util-y += bitmap.o
perf-util-y += hweight.o
+perf-util-y += sha1.o
+perf-util-y += sha1_generic.o
perf-util-y += smt.o
perf-util-y += strbuf.o
perf-util-y += string.o
diff --git a/tools/perf/util/sha1.c b/tools/perf/util/sha1.c
new file mode 100644
index 000000000000..5ae658afb56b
--- /dev/null
+++ b/tools/perf/util/sha1.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
+ * and to avoid unnecessary copies into the context array.
+ *
+ * This was based on the git SHA1 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/unaligned.h>
+
+#include "sha1.h"
+
+/*
+ * If you have 32 registers or more, the compiler can (and should)
+ * try to change the array[] accesses into registers. However, on
+ * machines with less than ~25 registers, that won't really work,
+ * and at least gcc will make an unholy mess of it.
+ *
+ * So to avoid that mess which just slows things down, we force
+ * the stores to memory to actually happen (we might be better off
+ * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
+ * suggested by Artur Skawina - that will also make gcc unable to
+ * try to do the silly "optimize away loads" part because it won't
+ * see what the value will be).
+ *
+ * Ben Herrenschmidt reports that on PPC, the C version comes close
+ * to the optimized asm with this (ie on PPC you don't want that
+ * 'volatile', since there are lots of registers).
+ *
+ * On ARM we get the best code generation by forcing a full memory barrier
+ * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
+ * the stack frame size simply explode and performance goes down the drain.
+ */
+
+#ifdef CONFIG_X86
+ #define setW(x, val) (*(volatile __u32 *)&W(x) = (val))
+#elif defined(CONFIG_ARM)
+ #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
+#else
+ #define setW(x, val) (W(x) = (val))
+#endif
+
+/* This "rolls" over the 512-bit array */
+#define W(x) (array[(x)&15])
+
+/*
+ * Where do we get the source from? The first 16 iterations get it from
+ * the input data, the next mix it from the 512-bit array.
+ */
+#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t)
+#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
+
+#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
+ __u32 TEMP = input(t); setW(t, TEMP); \
+ E += TEMP + rol32(A,5) + (fn) + (constant); \
+ B = ror32(B, 2); \
+ TEMP = E; E = D; D = C; C = B; B = A; A = TEMP; } while (0)
+
+#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
+#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
+#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
+
+/**
+ * sha1_transform - single block SHA1 transform (deprecated)
+ *
+ * @digest: 160 bit digest to update
+ * @data: 512 bits of data to hash
+ * @array: 16 words of workspace (see note)
+ *
+ * This function executes SHA-1's internal compression function. It updates the
+ * 160-bit internal state (@digest) with a single 512-bit data block (@data).
+ *
+ * Don't use this function. SHA-1 is no longer considered secure. And even if
+ * you do have to use SHA-1, this isn't the correct way to hash something with
+ * SHA-1 as this doesn't handle padding and finalization.
+ *
+ * Note: If the hash is security sensitive, the caller should be sure
+ * to clear the workspace. This is left to the caller to avoid
+ * unnecessary clears between chained hashing operations.
+ */
+void sha1_transform(__u32 *digest, const char *data, __u32 *array)
+{
+ __u32 A, B, C, D, E;
+ unsigned int i = 0;
+
+ A = digest[0];
+ B = digest[1];
+ C = digest[2];
+ D = digest[3];
+ E = digest[4];
+
+ /* Round 1 - iterations 0-16 take their input from 'data' */
+ for (; i < 16; ++i)
+ T_0_15(i, A, B, C, D, E);
+
+ /* Round 1 - tail. Input from 512-bit mixing array */
+ for (; i < 20; ++i)
+ T_16_19(i, A, B, C, D, E);
+
+ /* Round 2 */
+ for (; i < 40; ++i)
+ T_20_39(i, A, B, C, D, E);
+
+ /* Round 3 */
+ for (; i < 60; ++i)
+ T_40_59(i, A, B, C, D, E);
+
+ /* Round 4 */
+ for (; i < 80; ++i)
+ T_60_79(i, A, B, C, D, E);
+
+ digest[0] += A;
+ digest[1] += B;
+ digest[2] += C;
+ digest[3] += D;
+ digest[4] += E;
+}
diff --git a/tools/perf/util/sha1.h b/tools/perf/util/sha1.h
new file mode 100644
index 000000000000..9da4ece49bc6
--- /dev/null
+++ b/tools/perf/util/sha1.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common values for SHA-1 algorithms
+ */
+
+#ifndef _CRYPTO_SHA1_H
+#define _CRYPTO_SHA1_H
+
+#include <linux/types.h>
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_BLOCK_SIZE 64
+
+#define SHA1_H0 0x67452301UL
+#define SHA1_H1 0xefcdab89UL
+#define SHA1_H2 0x98badcfeUL
+#define SHA1_H3 0x10325476UL
+#define SHA1_H4 0xc3d2e1f0UL
+
+struct sha1_state {
+ u32 state[SHA1_DIGEST_SIZE / 4];
+ u64 count;
+ u8 buffer[SHA1_BLOCK_SIZE];
+};
+
+extern int crypto_sha1_update(struct sha1_state *desc, const u8 *data,
+ unsigned int len);
+
+extern int crypto_sha1_finup(struct sha1_state *desc, const u8 *data,
+ unsigned int len, u8 *hash);
+
+/*
+ * An implementation of SHA-1's compression function. Don't use in new code!
+ * You shouldn't be using SHA-1, and even if you *have* to use SHA-1, this isn't
+ * the correct way to hash something with SHA-1 (use crypto_shash instead).
+ */
+#define SHA1_DIGEST_WORDS (SHA1_DIGEST_SIZE / 4)
+#define SHA1_WORKSPACE_WORDS 16
+void sha1_transform(__u32 *digest, const char *data, __u32 *W);
+
+#endif /* _CRYPTO_SHA1_H */
diff --git a/tools/perf/util/sha1_base.h b/tools/perf/util/sha1_base.h
new file mode 100644
index 000000000000..cea22c5a4952
--- /dev/null
+++ b/tools/perf/util/sha1_base.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * sha1_base.h - core logic for SHA-1 implementations
+ *
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ */
+
+#ifndef _CRYPTO_SHA1_BASE_H
+#define _CRYPTO_SHA1_BASE_H
+
+#include <linux/string.h>
+
+#include <linux/kernel.h>
+#include <linux/unaligned.h>
+
+#include "sha1.h"
+
+typedef void (sha1_block_fn)(struct sha1_state *sst, u8 const *src, int blocks);
+
+static inline int sha1_base_init(struct sha1_state *sctx)
+{
+ sctx->state[0] = SHA1_H0;
+ sctx->state[1] = SHA1_H1;
+ sctx->state[2] = SHA1_H2;
+ sctx->state[3] = SHA1_H3;
+ sctx->state[4] = SHA1_H4;
+ sctx->count = 0;
+
+ return 0;
+}
+
+static inline int sha1_base_do_update(struct sha1_state *sctx,
+ const u8 *data,
+ unsigned int len,
+ sha1_block_fn *block_fn)
+{
+ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+
+ sctx->count += len;
+
+ if (unlikely((partial + len) >= SHA1_BLOCK_SIZE)) {
+ int blocks;
+
+ if (partial) {
+ int p = SHA1_BLOCK_SIZE - partial;
+
+ memcpy(sctx->buffer + partial, data, p);
+ data += p;
+ len -= p;
+
+ block_fn(sctx, sctx->buffer, 1);
+ }
+
+ blocks = len / SHA1_BLOCK_SIZE;
+ len %= SHA1_BLOCK_SIZE;
+
+ if (blocks) {
+ block_fn(sctx, data, blocks);
+ data += blocks * SHA1_BLOCK_SIZE;
+ }
+ partial = 0;
+ }
+ if (len)
+ memcpy(sctx->buffer + partial, data, len);
+
+ return 0;
+}
+
+static inline int sha1_base_do_finalize(struct sha1_state *sctx,
+ sha1_block_fn *block_fn)
+{
+ const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
+ __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
+ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+
+ sctx->buffer[partial++] = 0x80;
+ if (partial > bit_offset) {
+ memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
+ partial = 0;
+
+ block_fn(sctx, sctx->buffer, 1);
+ }
+
+ memset(sctx->buffer + partial, 0x0, bit_offset - partial);
+ *bits = cpu_to_be64(sctx->count << 3);
+ block_fn(sctx, sctx->buffer, 1);
+
+ return 0;
+}
+
+static inline int sha1_base_finish(struct sha1_state *sctx, u8 *out)
+{
+ __be32 *digest = (__be32 *)out;
+ int i;
+
+ for (i = 0; i < SHA1_DIGEST_SIZE / (int)sizeof(__be32); i++)
+ put_unaligned_be32(sctx->state[i], digest++);
+
+ memzero_explicit(sctx, sizeof(*sctx));
+ return 0;
+}
+
+#endif /* _CRYPTO_SHA1_BASE_H */
diff --git a/tools/perf/util/sha1_generic.c b/tools/perf/util/sha1_generic.c
new file mode 100644
index 000000000000..b0a7af370d59
--- /dev/null
+++ b/tools/perf/util/sha1_generic.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cryptographic API.
+ *
+ * SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface.
+ *
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
+ */
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+#include "sha1_base.h"
+
+static void sha1_generic_block_fn(struct sha1_state *sst, u8 const *src,
+ int blocks)
+{
+ u32 temp[SHA1_WORKSPACE_WORDS];
+
+ while (blocks--) {
+ sha1_transform(sst->state, (const char *)src, temp);
+ src += SHA1_BLOCK_SIZE;
+ }
+ memzero_explicit(temp, sizeof(temp));
+}
+
+int crypto_sha1_update(struct sha1_state *desc, const u8 *data,
+ unsigned int len)
+{
+ return sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
+}
+
+static int sha1_final(struct sha1_state *desc, u8 *out)
+{
+ sha1_base_do_finalize(desc, sha1_generic_block_fn);
+ return sha1_base_finish(desc, out);
+}
+
+int crypto_sha1_finup(struct sha1_state *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
+ return sha1_final(desc, out);
+}
--
2.49.0.1164.gab81da1b16-goog
On Wed, May 21, 2025 at 03:53:05PM -0700, Yuzhuo Jing wrote:
> Those new files are derived from the kernel tree, namely:
>
> tools/perf/util/sha1.c from lib/crypto/sha1.c
> tools/perf/util/sha1.h from include/crypto/sha1.h
> tools/perf/util/sha1_base.h from include/crypto/sha1_base.h
> tools/perf/util/sha1_generic.c from crypto/sha1_generic.c
>
> The reason that we are not syncing them with the kernel tree like other
> tools header files is because of the deep dependency in
> include/crypto/hash.h. It's painful to import the whole kernel crypto
> driver infrastructure into tools.
This is failing:
⬢ [acme@toolbx perf-tools-next]$ git log --oneline -1 ; time make -C tools/perf build-test
<SNIP>
make_no_scripts_O: cd . && make NO_LIBPYTHON=1 NO_LIBPERL=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j32 O=/tmp/tmp.aknNhb7DZp DESTDIR=/tmp/tmp.8qecgbhwKa
make_extra_tests_O: cd . && make EXTRA_TESTS=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j32 O=/tmp/tmp.C1nM6OCHSS DESTDIR=/tmp/tmp.iWigrG5sDJ
make_debug_O: cd . && make DEBUG=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j32 O=/tmp/tmp.z8p7Unts6E DESTDIR=/tmp/tmp.k9856UvMRF
cd . && make DEBUG=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j32 O=/tmp/tmp.z8p7Unts6E DESTDIR=/tmp/tmp.k9856UvMRF
BUILD: Doing 'make -j32' parallel build
Warning: Kernel ABI header differences:
diff -u tools/arch/arm64/include/asm/cputype.h arch/arm64/include/asm/cputype.h
Makefile.config:955: No libllvm 13+ found, slower source file resolution, please install llvm-devel/llvm-dev
Makefile.config:1134: No openjdk development package found, please install JDK package, e.g. openjdk-8-jdk, java-1.8.0-openjdk-devel
GEN /tmp/tmp.z8p7Unts6E/common-cmds.h
CC /tmp/tmp.z8p7Unts6E/dlfilters/dlfilter-test-api-v0.o
CC /tmp/tmp.z8p7Unts6E/dlfilters/dlfilter-test-api-v2.o
<SNIP>
CC /tmp/tmp.z8p7Unts6E/util/strlist.o
CC /tmp/tmp.z8p7Unts6E/tests/demangle-java-test.o
LD /tmp/tmp.z8p7Unts6E/trace/beauty/tracepoints/perf-in.o
In file included from util/sha1_generic.c:18:
util/sha1_base.h: In function ‘sha1_base_do_finalize’:
util/sha1_base.h:77:21: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Werror=sign-compare]
77 | if (partial > bit_offset) {
| ^
cc1: all warnings being treated as errors
CC /tmp/tmp.z8p7Unts6E/tests/demangle-ocaml-test.o
CC /tmp/tmp.z8p7Unts6E/util/strfilter.o
make[6]: *** [/home/acme/git/perf-tools-next/tools/build/Makefile.build:86: /tmp/tmp.z8p7Unts6E/util/sha1_generic.o] Error 1
make[6]: *** Waiting for unfinished jobs....
LD /tmp/tmp.z8p7Unts6E/trace/beauty/perf-in.o
CC /tmp/tmp.z8p7Unts6E/tests/demangle-rust-v0-test.o
<SNIP>
LD /tmp/tmp.z8p7Unts6E/util/scripting-engines/perf-util-in.o
make[5]: *** [/home/acme/git/perf-tools-next/tools/build/Makefile.build:142: util] Error 2
make[4]: *** [Makefile.perf:795: /tmp/tmp.z8p7Unts6E/perf-util-in.o] Error 2
make[4]: *** Waiting for unfinished jobs....
CC /tmp/tmp.z8p7Unts6E/pmu-events/pmu-events.o
LD /tmp/tmp.z8p7Unts6E/pmu-events/pmu-events-in.o
make[3]: *** [Makefile.perf:287: sub-make] Error 2
make[2]: *** [Makefile:76: all] Error 2
make[1]: *** [tests/make:339: make_debug_O] Error 1
make: *** [Makefile:109: build-test] Error 2
make: Leaving directory '/home/acme/git/perf-tools-next/tools/perf'
real 2m10.250s
user 20m47.352s
sys 3m50.484s
⬢ [acme@toolbx perf-tools-next]$
Humm that part is the same as in the kernel...
⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f include/crypto/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/original
⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f tools/perf/util/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/copy
⬢ [acme@toolbx perf-tools-next]$ diff -u /tmp/original /tmp/copy
--- /tmp/original 2025-05-22 14:48:31.338406860 -0300
+++ /tmp/copy 2025-05-22 14:48:58.401603439 -0300
@@ -1,3 +1,7 @@
+
+ return 0;
+}
+
static inline int sha1_base_do_finalize(struct shash_desc *desc,
sha1_block_fn *block_fn)
{
@@ -13,10 +17,3 @@
block_fn(sctx, sctx->buffer, 1);
}
-
- memset(sctx->buffer + partial, 0x0, bit_offset - partial);
- *bits = cpu_to_be64(sctx->count << 3);
- block_fn(sctx, sctx->buffer, 1);
-
- return 0;
-}
⬢ [acme@toolbx perf-tools-next]$
If I try the quick fix:
⬢ [acme@toolbx perf-tools-next]$ git diff
diff --git a/tools/perf/util/sha1_base.h b/tools/perf/util/sha1_base.h
index cea22c5a49520998..5994c55748e40a79 100644
--- a/tools/perf/util/sha1_base.h
+++ b/tools/perf/util/sha1_base.h
@@ -71,7 +71,7 @@ static inline int sha1_base_do_finalize(struct sha1_state *sctx,
{
const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
__be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
- unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+ int partial = sctx->count % SHA1_BLOCK_SIZE;
sctx->buffer[partial++] = 0x80;
if (partial > bit_offset) {
⬢ [acme@toolbx perf-tools-next]$
IT works, to test it quicker try, before the above:
$ make -C tools/perf -f tests/make make_debug
<SNIP>
CC util/bpf_map.o
In file included from util/sha1_generic.c:18:
util/sha1_base.h: In function ‘sha1_base_do_finalize’:
util/sha1_base.h:77:21: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Werror=sign-compare]
77 | if (partial > bit_offset) {
| ^
cc1: all warnings being treated as errors
<SNIP>
After the above patch:
⬢ [acme@toolbx perf-tools-next]$ rm -f tools/perf/make_debug tools/perf/make_debug_O
⬢ [acme@toolbx perf-tools-next]$ make -C tools/perf -f tests/make make_debug
make: Entering directory '/home/acme/git/perf-tools-next/tools/perf'
Testing Makefile
make_debug: cd . && make DEBUG=1 DESTDIR=/tmp/tmp.yfg6I4SlFY
make: Leaving directory '/home/acme/git/perf-tools-next/tools/perf'
⬢ [acme@toolbx perf-tools-next]$
- Arnaldo
> The derived files get rid of struct shash_desc definition, and directly
> operates on the struct sha1_state.
>
> Signed-off-by: Yuzhuo Jing <yuzhuo@google.com>
> ---
> tools/perf/util/Build | 2 +
> tools/perf/util/sha1.c | 122 +++++++++++++++++++++++++++++++++
> tools/perf/util/sha1.h | 41 +++++++++++
> tools/perf/util/sha1_base.h | 103 ++++++++++++++++++++++++++++
> tools/perf/util/sha1_generic.c | 49 +++++++++++++
> 5 files changed, 317 insertions(+)
> create mode 100644 tools/perf/util/sha1.c
> create mode 100644 tools/perf/util/sha1.h
> create mode 100644 tools/perf/util/sha1_base.h
> create mode 100644 tools/perf/util/sha1_generic.c
>
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 7910d908c814..ecee96b3f3fa 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -41,6 +41,8 @@ perf-util-y += rbtree.o
> perf-util-y += libstring.o
> perf-util-y += bitmap.o
> perf-util-y += hweight.o
> +perf-util-y += sha1.o
> +perf-util-y += sha1_generic.o
> perf-util-y += smt.o
> perf-util-y += strbuf.o
> perf-util-y += string.o
> diff --git a/tools/perf/util/sha1.c b/tools/perf/util/sha1.c
> new file mode 100644
> index 000000000000..5ae658afb56b
> --- /dev/null
> +++ b/tools/perf/util/sha1.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * SHA1 routine optimized to do word accesses rather than byte accesses,
> + * and to avoid unnecessary copies into the context array.
> + *
> + * This was based on the git SHA1 implementation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/string.h>
> +#include <linux/unaligned.h>
> +
> +#include "sha1.h"
> +
> +/*
> + * If you have 32 registers or more, the compiler can (and should)
> + * try to change the array[] accesses into registers. However, on
> + * machines with less than ~25 registers, that won't really work,
> + * and at least gcc will make an unholy mess of it.
> + *
> + * So to avoid that mess which just slows things down, we force
> + * the stores to memory to actually happen (we might be better off
> + * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
> + * suggested by Artur Skawina - that will also make gcc unable to
> + * try to do the silly "optimize away loads" part because it won't
> + * see what the value will be).
> + *
> + * Ben Herrenschmidt reports that on PPC, the C version comes close
> + * to the optimized asm with this (ie on PPC you don't want that
> + * 'volatile', since there are lots of registers).
> + *
> + * On ARM we get the best code generation by forcing a full memory barrier
> + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
> + * the stack frame size simply explode and performance goes down the drain.
> + */
> +
> +#ifdef CONFIG_X86
> + #define setW(x, val) (*(volatile __u32 *)&W(x) = (val))
> +#elif defined(CONFIG_ARM)
> + #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
> +#else
> + #define setW(x, val) (W(x) = (val))
> +#endif
> +
> +/* This "rolls" over the 512-bit array */
> +#define W(x) (array[(x)&15])
> +
> +/*
> + * Where do we get the source from? The first 16 iterations get it from
> + * the input data, the next mix it from the 512-bit array.
> + */
> +#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t)
> +#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
> +
> +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
> + __u32 TEMP = input(t); setW(t, TEMP); \
> + E += TEMP + rol32(A,5) + (fn) + (constant); \
> + B = ror32(B, 2); \
> + TEMP = E; E = D; D = C; C = B; B = A; A = TEMP; } while (0)
> +
> +#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
> +#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
> +#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
> +#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
> +#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
> +
> +/**
> + * sha1_transform - single block SHA1 transform (deprecated)
> + *
> + * @digest: 160 bit digest to update
> + * @data: 512 bits of data to hash
> + * @array: 16 words of workspace (see note)
> + *
> + * This function executes SHA-1's internal compression function. It updates the
> + * 160-bit internal state (@digest) with a single 512-bit data block (@data).
> + *
> + * Don't use this function. SHA-1 is no longer considered secure. And even if
> + * you do have to use SHA-1, this isn't the correct way to hash something with
> + * SHA-1 as this doesn't handle padding and finalization.
> + *
> + * Note: If the hash is security sensitive, the caller should be sure
> + * to clear the workspace. This is left to the caller to avoid
> + * unnecessary clears between chained hashing operations.
> + */
> +void sha1_transform(__u32 *digest, const char *data, __u32 *array)
> +{
> + __u32 A, B, C, D, E;
> + unsigned int i = 0;
> +
> + A = digest[0];
> + B = digest[1];
> + C = digest[2];
> + D = digest[3];
> + E = digest[4];
> +
> + /* Round 1 - iterations 0-16 take their input from 'data' */
> + for (; i < 16; ++i)
> + T_0_15(i, A, B, C, D, E);
> +
> + /* Round 1 - tail. Input from 512-bit mixing array */
> + for (; i < 20; ++i)
> + T_16_19(i, A, B, C, D, E);
> +
> + /* Round 2 */
> + for (; i < 40; ++i)
> + T_20_39(i, A, B, C, D, E);
> +
> + /* Round 3 */
> + for (; i < 60; ++i)
> + T_40_59(i, A, B, C, D, E);
> +
> + /* Round 4 */
> + for (; i < 80; ++i)
> + T_60_79(i, A, B, C, D, E);
> +
> + digest[0] += A;
> + digest[1] += B;
> + digest[2] += C;
> + digest[3] += D;
> + digest[4] += E;
> +}
> diff --git a/tools/perf/util/sha1.h b/tools/perf/util/sha1.h
> new file mode 100644
> index 000000000000..9da4ece49bc6
> --- /dev/null
> +++ b/tools/perf/util/sha1.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Common values for SHA-1 algorithms
> + */
> +
> +#ifndef _CRYPTO_SHA1_H
> +#define _CRYPTO_SHA1_H
> +
> +#include <linux/types.h>
> +
> +#define SHA1_DIGEST_SIZE 20
> +#define SHA1_BLOCK_SIZE 64
> +
> +#define SHA1_H0 0x67452301UL
> +#define SHA1_H1 0xefcdab89UL
> +#define SHA1_H2 0x98badcfeUL
> +#define SHA1_H3 0x10325476UL
> +#define SHA1_H4 0xc3d2e1f0UL
> +
> +struct sha1_state {
> + u32 state[SHA1_DIGEST_SIZE / 4];
> + u64 count;
> + u8 buffer[SHA1_BLOCK_SIZE];
> +};
> +
> +extern int crypto_sha1_update(struct sha1_state *desc, const u8 *data,
> + unsigned int len);
> +
> +extern int crypto_sha1_finup(struct sha1_state *desc, const u8 *data,
> + unsigned int len, u8 *hash);
> +
> +/*
> + * An implementation of SHA-1's compression function. Don't use in new code!
> + * You shouldn't be using SHA-1, and even if you *have* to use SHA-1, this isn't
> + * the correct way to hash something with SHA-1 (use crypto_shash instead).
> + */
> +#define SHA1_DIGEST_WORDS (SHA1_DIGEST_SIZE / 4)
> +#define SHA1_WORKSPACE_WORDS 16
> +void sha1_transform(__u32 *digest, const char *data, __u32 *W);
> +
> +#endif /* _CRYPTO_SHA1_H */
> diff --git a/tools/perf/util/sha1_base.h b/tools/perf/util/sha1_base.h
> new file mode 100644
> index 000000000000..cea22c5a4952
> --- /dev/null
> +++ b/tools/perf/util/sha1_base.h
> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * sha1_base.h - core logic for SHA-1 implementations
> + *
> + * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
> + */
> +
> +#ifndef _CRYPTO_SHA1_BASE_H
> +#define _CRYPTO_SHA1_BASE_H
> +
> +#include <linux/string.h>
> +
> +#include <linux/kernel.h>
> +#include <linux/unaligned.h>
> +
> +#include "sha1.h"
> +
> +typedef void (sha1_block_fn)(struct sha1_state *sst, u8 const *src, int blocks);
> +
> +static inline int sha1_base_init(struct sha1_state *sctx)
> +{
> + sctx->state[0] = SHA1_H0;
> + sctx->state[1] = SHA1_H1;
> + sctx->state[2] = SHA1_H2;
> + sctx->state[3] = SHA1_H3;
> + sctx->state[4] = SHA1_H4;
> + sctx->count = 0;
> +
> + return 0;
> +}
> +
> +static inline int sha1_base_do_update(struct sha1_state *sctx,
> + const u8 *data,
> + unsigned int len,
> + sha1_block_fn *block_fn)
> +{
> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +
> + sctx->count += len;
> +
> + if (unlikely((partial + len) >= SHA1_BLOCK_SIZE)) {
> + int blocks;
> +
> + if (partial) {
> + int p = SHA1_BLOCK_SIZE - partial;
> +
> + memcpy(sctx->buffer + partial, data, p);
> + data += p;
> + len -= p;
> +
> + block_fn(sctx, sctx->buffer, 1);
> + }
> +
> + blocks = len / SHA1_BLOCK_SIZE;
> + len %= SHA1_BLOCK_SIZE;
> +
> + if (blocks) {
> + block_fn(sctx, data, blocks);
> + data += blocks * SHA1_BLOCK_SIZE;
> + }
> + partial = 0;
> + }
> + if (len)
> + memcpy(sctx->buffer + partial, data, len);
> +
> + return 0;
> +}
> +
> +static inline int sha1_base_do_finalize(struct sha1_state *sctx,
> + sha1_block_fn *block_fn)
> +{
> + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +
> + sctx->buffer[partial++] = 0x80;
> + if (partial > bit_offset) {
> + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
> + partial = 0;
> +
> + block_fn(sctx, sctx->buffer, 1);
> + }
> +
> + memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> + *bits = cpu_to_be64(sctx->count << 3);
> + block_fn(sctx, sctx->buffer, 1);
> +
> + return 0;
> +}
> +
> +static inline int sha1_base_finish(struct sha1_state *sctx, u8 *out)
> +{
> + __be32 *digest = (__be32 *)out;
> + int i;
> +
> + for (i = 0; i < SHA1_DIGEST_SIZE / (int)sizeof(__be32); i++)
> + put_unaligned_be32(sctx->state[i], digest++);
> +
> + memzero_explicit(sctx, sizeof(*sctx));
> + return 0;
> +}
> +
> +#endif /* _CRYPTO_SHA1_BASE_H */
> diff --git a/tools/perf/util/sha1_generic.c b/tools/perf/util/sha1_generic.c
> new file mode 100644
> index 000000000000..b0a7af370d59
> --- /dev/null
> +++ b/tools/perf/util/sha1_generic.c
> @@ -0,0 +1,49 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Cryptographic API.
> + *
> + * SHA1 Secure Hash Algorithm.
> + *
> + * Derived from cryptoapi implementation, adapted for in-place
> + * scatterlist interface.
> + *
> + * Copyright (c) Alan Smithee.
> + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
> + * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
> + */
> +#include <linux/types.h>
> +#include <linux/string.h>
> +#include <asm/byteorder.h>
> +
> +#include "sha1_base.h"
> +
> +static void sha1_generic_block_fn(struct sha1_state *sst, u8 const *src,
> + int blocks)
> +{
> + u32 temp[SHA1_WORKSPACE_WORDS];
> +
> + while (blocks--) {
> + sha1_transform(sst->state, (const char *)src, temp);
> + src += SHA1_BLOCK_SIZE;
> + }
> + memzero_explicit(temp, sizeof(temp));
> +}
> +
> +int crypto_sha1_update(struct sha1_state *desc, const u8 *data,
> + unsigned int len)
> +{
> + return sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
> +}
> +
> +static int sha1_final(struct sha1_state *desc, u8 *out)
> +{
> + sha1_base_do_finalize(desc, sha1_generic_block_fn);
> + return sha1_base_finish(desc, out);
> +}
> +
> +int crypto_sha1_finup(struct sha1_state *desc, const u8 *data,
> + unsigned int len, u8 *out)
> +{
> + sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
> + return sha1_final(desc, out);
> +}
> --
> 2.49.0.1164.gab81da1b16-goog
Hi Arnaldo,
Thanks for testing the patches!
> In file included from util/sha1_generic.c:18:
> util/sha1_base.h: In function ‘sha1_base_do_finalize’:
> util/sha1_base.h:77:21: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Werror=sign-compare]
> 77 | if (partial > bit_offset) {
> | ^
> cc1: all warnings being treated as errors
Oh, I didn't see that on my GCC 14.2. A quick fix would work:
--- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
+++ tools/perf/util/sha1_base.h 2025-06-03 15:43:39.194036707 -0700
@@ -71,7 +69,7 @@
static inline int sha1_base_do_finalize(struct sha1_state *sctx,
sha1_block_fn *block_fn)
{
- const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
+ const unsigned int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
__be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
To test it, I added -Werror=sign-compare to my local Makefile.config to
force the error.
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index d19d1f132726..9909611be301 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -225,9 +225,9 @@ endif
# Treat warnings as errors unless directed not to
ifneq ($(WERROR),0)
- CORE_CFLAGS += -Werror
- CXXFLAGS += -Werror
- HOSTCFLAGS += -Werror
+ CORE_CFLAGS += -Werror=sign-compare -Werror
+ CXXFLAGS += -Werror=sign-compare -Werror
+ HOSTCFLAGS += -Werror=sign-compare -Werror
endif
ifndef DEBUG
While testing with "make -C tools/perf -f tests/make make_debug", I saw
similar compile errors in libjvmti.c:
jvmti/libjvmti.c: In function ‘copy_class_filename’:
jvmti/libjvmti.c:148:39: error: comparison of integer expressions of
different signedness: ‘int’ and ‘long unsigned int’
[-Werror=sign-compare]
148 | for (i = 0; i < (size_t)(p - class_sign); i++)
| ^
jvmti/libjvmti.c:155:31: error: comparison of integer expressions of
different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’}
[-Werror=sign-compare]
155 | for (j = 0; i < (max_length - 1) && file_name
&& j < strlen(file_name); j++, i++)
| ^
jvmti/libjvmti.c:155:68: error: comparison of integer expressions of
different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’}
[-Werror=sign-compare]
155 | for (j = 0; i < (max_length - 1) && file_name
&& j < strlen(file_name); j++, i++)
| ^
I've just sent a separate patch to the mailing list:
https://lore.kernel.org/lkml/20250604173632.2362759-1-yuzhuo@google.com/T/
> Humm that part is the same as in the kernel...
>
> ⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f include/crypto/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
> ⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/original
> ⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f tools/perf/util/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
> ⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/copy
> ⬢ [acme@toolbx perf-tools-next]$ diff -u /tmp/original /tmp/copy
> --- /tmp/original 2025-05-22 14:48:31.338406860 -0300
> +++ /tmp/copy 2025-05-22 14:48:58.401603439 -0300
> @@ -1,3 +1,7 @@
> +
> + return 0;
> +}
> +
> static inline int sha1_base_do_finalize(struct shash_desc *desc,
> sha1_block_fn *block_fn)
> {
> @@ -13,10 +17,3 @@
>
> block_fn(sctx, sctx->buffer, 1);
> }
> -
> - memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> - *bits = cpu_to_be64(sctx->count << 3);
> - block_fn(sctx, sctx->buffer, 1);
> -
> - return 0;
> -}
> ⬢ [acme@toolbx perf-tools-next]$
There were some other fixes that I made only to the perf tree version,
while maintaining verbatim for other parts. Here's a script that
retains and compares only the copied parts.
# Ignore everything after sha1_transform
diff -u -B -I "^#include " <(sed -n
'/EXPORT_SYMBOL(sha1_transform)/q;p' lib/crypto/sha1.c)
tools/perf/util/sha1.c
diff -u -B -I "^#include " -I "sha1_zero_message_hash" -I "^struct
sha1_state;$" -I "^void sha1_init(__u32 \*buf);$" \
<(sed 's/shash_desc/sha1_state/g;' include/crypto/sha1.h)
tools/perf/util/sha1.h
diff -u -B -I "^EXPORT_SYMBOL" -I "^#include " \
<(sed 's/shash_desc \*desc/sha1_state *sctx/g;
/shash_desc_ctx(desc)/d' include/crypto/sha1_base.h)
tools/perf/util/sha1_base.h
# Ignore everything after crypto_sha1_finup
diff -u -B -I "^EXPORT_SYMBOL" -I "^#include " \
<(sed -n -e '/const u8
sha1_zero_message_hash/,/EXPORT_SYMBOL_GPL(sha1_zero_message_hash)/d'
\
-e 's/shash_desc/sha1_state/g;
/EXPORT_SYMBOL(crypto_sha1_finup)/q;p' crypto/sha1_generic.c) \
tools/perf/util/sha1_generic.c
And the changes are as below (including the quick fix above), with one
changing the sign and integer type and another fixing type mismatch from
const u8 * to const char *.
Should we send another patch to the kernel tree version to fix the sign
error, or we add rules to allow perf tree only changes?
--- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
+++ tools/perf/util/sha1_base.h 2025-06-03 15:43:39.194036707 -0700
@@ -71,7 +69,7 @@
static inline int sha1_base_do_finalize(struct sha1_state *sctx,
sha1_block_fn *block_fn)
{
- const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
+ const unsigned int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
__be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
@@ -95,7 +93,7 @@
__be32 *digest = (__be32 *)out;
int i;
- for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
+ for (i = 0; i < SHA1_DIGEST_SIZE / (int)sizeof(__be32); i++)
put_unaligned_be32(sctx->state[i], digest++);
memzero_explicit(sctx, sizeof(*sctx));
--- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
+++ tools/perf/util/sha1_generic.c 2025-05-16 10:52:59.219531034 -0700
@@ -27,7 +23,7 @@
u32 temp[SHA1_WORKSPACE_WORDS];
while (blocks--) {
- sha1_transform(sst->state, src, temp);
+ sha1_transform(sst->state, (const char *)src, temp);
src += SHA1_BLOCK_SIZE;
}
memzero_explicit(temp, sizeof(temp));
Thanks!
Best regards,
Yuzhuo
On Wed, Jun 4, 2025 at 11:17 AM Yuzhuo Jing <yuzhuo@google.com> wrote:
>
> Hi Arnaldo,
>
> Thanks for testing the patches!
>
> > In file included from util/sha1_generic.c:18:
> > util/sha1_base.h: In function ‘sha1_base_do_finalize’:
> > util/sha1_base.h:77:21: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Werror=sign-compare]
> > 77 | if (partial > bit_offset) {
> > | ^
> > cc1: all warnings being treated as errors
>
> Oh, I didn't see that on my GCC 14.2. A quick fix would work:
>
> --- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
> +++ tools/perf/util/sha1_base.h 2025-06-03 15:43:39.194036707 -0700
> @@ -71,7 +69,7 @@
> static inline int sha1_base_do_finalize(struct sha1_state *sctx,
> sha1_block_fn *block_fn)
> {
> - const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> + const unsigned int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
>
>
> To test it, I added -Werror=sign-compare to my local Makefile.config to
> force the error.
>
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index d19d1f132726..9909611be301 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
> @@ -225,9 +225,9 @@ endif
>
> # Treat warnings as errors unless directed not to
> ifneq ($(WERROR),0)
> - CORE_CFLAGS += -Werror
> - CXXFLAGS += -Werror
> - HOSTCFLAGS += -Werror
> + CORE_CFLAGS += -Werror=sign-compare -Werror
> + CXXFLAGS += -Werror=sign-compare -Werror
> + HOSTCFLAGS += -Werror=sign-compare -Werror
> endif
>
> ifndef DEBUG
>
>
> While testing with "make -C tools/perf -f tests/make make_debug", I saw
> similar compile errors in libjvmti.c:
>
> jvmti/libjvmti.c: In function ‘copy_class_filename’:
> jvmti/libjvmti.c:148:39: error: comparison of integer expressions of
> different signedness: ‘int’ and ‘long unsigned int’
> [-Werror=sign-compare]
> 148 | for (i = 0; i < (size_t)(p - class_sign); i++)
> | ^
> jvmti/libjvmti.c:155:31: error: comparison of integer expressions of
> different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’}
> [-Werror=sign-compare]
> 155 | for (j = 0; i < (max_length - 1) && file_name
> && j < strlen(file_name); j++, i++)
> | ^
> jvmti/libjvmti.c:155:68: error: comparison of integer expressions of
> different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’}
> [-Werror=sign-compare]
> 155 | for (j = 0; i < (max_length - 1) && file_name
> && j < strlen(file_name); j++, i++)
> | ^
>
> I've just sent a separate patch to the mailing list:
> https://lore.kernel.org/lkml/20250604173632.2362759-1-yuzhuo@google.com/T/
Thanks Yuzhuo! I guess this happened because jvmti.h is missing in the
test container. It seems to make sense to add -Wsign-compare to the
standard CFLAGS to lower the chance of breaking this container again.
> > Humm that part is the same as in the kernel...
> >
> > ⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f include/crypto/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
> > ⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/original
> > ⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f tools/perf/util/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
> > ⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/copy
> > ⬢ [acme@toolbx perf-tools-next]$ diff -u /tmp/original /tmp/copy
> > --- /tmp/original 2025-05-22 14:48:31.338406860 -0300
> > +++ /tmp/copy 2025-05-22 14:48:58.401603439 -0300
> > @@ -1,3 +1,7 @@
> > +
> > + return 0;
> > +}
> > +
> > static inline int sha1_base_do_finalize(struct shash_desc *desc,
> > sha1_block_fn *block_fn)
> > {
> > @@ -13,10 +17,3 @@
> >
> > block_fn(sctx, sctx->buffer, 1);
> > }
> > -
> > - memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> > - *bits = cpu_to_be64(sctx->count << 3);
> > - block_fn(sctx, sctx->buffer, 1);
> > -
> > - return 0;
> > -}
> > ⬢ [acme@toolbx perf-tools-next]$
>
> There were some other fixes that I made only to the perf tree version,
> while maintaining verbatim for other parts. Here's a script that
> retains and compares only the copied parts.
>
> # Ignore everything after sha1_transform
> diff -u -B -I "^#include " <(sed -n
> '/EXPORT_SYMBOL(sha1_transform)/q;p' lib/crypto/sha1.c)
> tools/perf/util/sha1.c
> diff -u -B -I "^#include " -I "sha1_zero_message_hash" -I "^struct
> sha1_state;$" -I "^void sha1_init(__u32 \*buf);$" \
> <(sed 's/shash_desc/sha1_state/g;' include/crypto/sha1.h)
> tools/perf/util/sha1.h
> diff -u -B -I "^EXPORT_SYMBOL" -I "^#include " \
> <(sed 's/shash_desc \*desc/sha1_state *sctx/g;
> /shash_desc_ctx(desc)/d' include/crypto/sha1_base.h)
> tools/perf/util/sha1_base.h
> # Ignore everything after crypto_sha1_finup
> diff -u -B -I "^EXPORT_SYMBOL" -I "^#include " \
> <(sed -n -e '/const u8
> sha1_zero_message_hash/,/EXPORT_SYMBOL_GPL(sha1_zero_message_hash)/d'
> \
> -e 's/shash_desc/sha1_state/g;
> /EXPORT_SYMBOL(crypto_sha1_finup)/q;p' crypto/sha1_generic.c) \
> tools/perf/util/sha1_generic.c
>
> And the changes are as below (including the quick fix above), with one
> changing the sign and integer type and another fixing type mismatch from
> const u8 * to const char *.
>
> Should we send another patch to the kernel tree version to fix the sign
> error, or we add rules to allow perf tree only changes?
I believe there will need to be a set of patches for the kernel sha1
code (fixing -Wsign-compare, any other typing issues) and a set of
patches for perf with the check-headers.sh updated as your scripts
check above. The perf patches shouldn't assume kernel patches have
landed. The perf check-headers.sh produces a warning but doesn't stop
the perf build. When the kernel changes land we can update the perf
check-headers.sh expectations.
Thanks,
Ian
> --- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
> +++ tools/perf/util/sha1_base.h 2025-06-03 15:43:39.194036707 -0700
> @@ -71,7 +69,7 @@
> static inline int sha1_base_do_finalize(struct sha1_state *sctx,
> sha1_block_fn *block_fn)
> {
> - const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> + const unsigned int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
>
> @@ -95,7 +93,7 @@
> __be32 *digest = (__be32 *)out;
> int i;
>
> - for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
> + for (i = 0; i < SHA1_DIGEST_SIZE / (int)sizeof(__be32); i++)
> put_unaligned_be32(sctx->state[i], digest++);
>
> memzero_explicit(sctx, sizeof(*sctx));
> --- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
> +++ tools/perf/util/sha1_generic.c 2025-05-16 10:52:59.219531034 -0700
> @@ -27,7 +23,7 @@
> u32 temp[SHA1_WORKSPACE_WORDS];
>
> while (blocks--) {
> - sha1_transform(sst->state, src, temp);
> + sha1_transform(sst->state, (const char *)src, temp);
> src += SHA1_BLOCK_SIZE;
> }
> memzero_explicit(temp, sizeof(temp));
>
> Thanks!
>
> Best regards,
> Yuzhuo
On Fri, Jun 06, 2025 at 11:27:28AM -0700, Ian Rogers wrote:
> On Wed, Jun 4, 2025 at 11:17 AM Yuzhuo Jing <yuzhuo@google.com> wrote:
> > Thanks for testing the patches!
You're welcome!
> > > In file included from util/sha1_generic.c:18:
> > > util/sha1_base.h: In function ‘sha1_base_do_finalize’:
> > > util/sha1_base.h:77:21: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Werror=sign-compare]
> > > 77 | if (partial > bit_offset) {
> > > | ^
> > > cc1: all warnings being treated as errors
> >
> > Oh, I didn't see that on my GCC 14.2. A quick fix would work:
> >
> > --- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
> > +++ tools/perf/util/sha1_base.h 2025-06-03 15:43:39.194036707 -0700
> > @@ -71,7 +69,7 @@
> > static inline int sha1_base_do_finalize(struct sha1_state *sctx,
> > sha1_block_fn *block_fn)
> > {
> > - const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> > + const unsigned int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> > __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> > unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> >
> >
> > To test it, I added -Werror=sign-compare to my local Makefile.config to
> > force the error.
> >
> > diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> > index d19d1f132726..9909611be301 100644
> > --- a/tools/perf/Makefile.config
> > +++ b/tools/perf/Makefile.config
> > @@ -225,9 +225,9 @@ endif
> >
> > # Treat warnings as errors unless directed not to
> > ifneq ($(WERROR),0)
> > - CORE_CFLAGS += -Werror
> > - CXXFLAGS += -Werror
> > - HOSTCFLAGS += -Werror
> > + CORE_CFLAGS += -Werror=sign-compare -Werror
> > + CXXFLAGS += -Werror=sign-compare -Werror
> > + HOSTCFLAGS += -Werror=sign-compare -Werror
> > endif
> > ifndef DEBUG
> > While testing with "make -C tools/perf -f tests/make make_debug", I saw
> > similar compile errors in libjvmti.c:
> > jvmti/libjvmti.c: In function ‘copy_class_filename’:
> > jvmti/libjvmti.c:148:39: error: comparison of integer expressions of
> > different signedness: ‘int’ and ‘long unsigned int’
> > [-Werror=sign-compare]
> > 148 | for (i = 0; i < (size_t)(p - class_sign); i++)
> > | ^
> > jvmti/libjvmti.c:155:31: error: comparison of integer expressions of
> > different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’}
> > [-Werror=sign-compare]
> > 155 | for (j = 0; i < (max_length - 1) && file_name
> > && j < strlen(file_name); j++, i++)
> > | ^
> > jvmti/libjvmti.c:155:68: error: comparison of integer expressions of
> > different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’}
> > [-Werror=sign-compare]
> > 155 | for (j = 0; i < (max_length - 1) && file_name
> > && j < strlen(file_name); j++, i++)
> > | ^
> >
> > I've just sent a separate patch to the mailing list:
> > https://lore.kernel.org/lkml/20250604173632.2362759-1-yuzhuo@google.com/T/
> Thanks Yuzhuo! I guess this happened because jvmti.h is missing in the
> test container. It seems to make sense to add -Wsign-compare to the
> standard CFLAGS to lower the chance of breaking this container again.
> > > Humm that part is the same as in the kernel...
> > >
> > > ⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f include/crypto/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
> > > ⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/original
> > > ⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f tools/perf/util/sha1_base.h | awk '$1 == "sha1_base_do_finalize" {print $3}')
> > > ⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p include/crypto/sha1_base.h | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}' > /tmp/copy
> > > ⬢ [acme@toolbx perf-tools-next]$ diff -u /tmp/original /tmp/copy
> > > --- /tmp/original 2025-05-22 14:48:31.338406860 -0300
> > > +++ /tmp/copy 2025-05-22 14:48:58.401603439 -0300
> > > @@ -1,3 +1,7 @@
> > > +
> > > + return 0;
> > > +}
> > > +
> > > static inline int sha1_base_do_finalize(struct shash_desc *desc,
> > > sha1_block_fn *block_fn)
> > > {
> > > @@ -13,10 +17,3 @@
> > >
> > > block_fn(sctx, sctx->buffer, 1);
> > > }
> > > -
> > > - memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> > > - *bits = cpu_to_be64(sctx->count << 3);
> > > - block_fn(sctx, sctx->buffer, 1);
> > > -
> > > - return 0;
> > > -}
> > > ⬢ [acme@toolbx perf-tools-next]$
> >
> > There were some other fixes that I made only to the perf tree version,
> > while maintaining verbatim for other parts. Here's a script that
> > retains and compares only the copied parts.
> >
> > # Ignore everything after sha1_transform
> > diff -u -B -I "^#include " <(sed -n
> > '/EXPORT_SYMBOL(sha1_transform)/q;p' lib/crypto/sha1.c)
> > tools/perf/util/sha1.c
> > diff -u -B -I "^#include " -I "sha1_zero_message_hash" -I "^struct
> > sha1_state;$" -I "^void sha1_init(__u32 \*buf);$" \
> > <(sed 's/shash_desc/sha1_state/g;' include/crypto/sha1.h)
> > tools/perf/util/sha1.h
> > diff -u -B -I "^EXPORT_SYMBOL" -I "^#include " \
> > <(sed 's/shash_desc \*desc/sha1_state *sctx/g;
> > /shash_desc_ctx(desc)/d' include/crypto/sha1_base.h)
> > tools/perf/util/sha1_base.h
> > # Ignore everything after crypto_sha1_finup
> > diff -u -B -I "^EXPORT_SYMBOL" -I "^#include " \
> > <(sed -n -e '/const u8
> > sha1_zero_message_hash/,/EXPORT_SYMBOL_GPL(sha1_zero_message_hash)/d'
> > \
> > -e 's/shash_desc/sha1_state/g;
> > /EXPORT_SYMBOL(crypto_sha1_finup)/q;p' crypto/sha1_generic.c) \
> > tools/perf/util/sha1_generic.c
> >
> > And the changes are as below (including the quick fix above), with one
> > changing the sign and integer type and another fixing type mismatch from
> > const u8 * to const char *.
> >
> > Should we send another patch to the kernel tree version to fix the sign
> > error, or we add rules to allow perf tree only changes?
>
> I believe there will need to be a set of patches for the kernel sha1
> code (fixing -Wsign-compare, any other typing issues) and a set of
> patches for perf with the check-headers.sh updated as your scripts
> check above.
Right, we try to reuse bits from the kernel as there are more people
working there and its a more critical piece of software than tooling
like perf, so when we notice something in the copies we carry, we better
fix it first in the origin.
> The perf patches shouldn't assume kernel patches have
> landed. The perf check-headers.sh produces a warning but doesn't stop
> the perf build. When the kernel changes land we can update the perf
> check-headers.sh expectations.
Right,
Thanks,
- Arnaldo
> Thanks,
> Ian
>
> > --- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
> > +++ tools/perf/util/sha1_base.h 2025-06-03 15:43:39.194036707 -0700
> > @@ -71,7 +69,7 @@
> > static inline int sha1_base_do_finalize(struct sha1_state *sctx,
> > sha1_block_fn *block_fn)
> > {
> > - const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> > + const unsigned int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> > __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> > unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> >
> > @@ -95,7 +93,7 @@
> > __be32 *digest = (__be32 *)out;
> > int i;
> >
> > - for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
> > + for (i = 0; i < SHA1_DIGEST_SIZE / (int)sizeof(__be32); i++)
> > put_unaligned_be32(sctx->state[i], digest++);
> >
> > memzero_explicit(sctx, sizeof(*sctx));
> > --- /dev/fd/63 2025-06-04 09:54:42.344516115 -0700
> > +++ tools/perf/util/sha1_generic.c 2025-05-16 10:52:59.219531034 -0700
> > @@ -27,7 +23,7 @@
> > u32 temp[SHA1_WORKSPACE_WORDS];
> >
> > while (blocks--) {
> > - sha1_transform(sst->state, src, temp);
> > + sha1_transform(sst->state, (const char *)src, temp);
> > src += SHA1_BLOCK_SIZE;
> > }
> > memzero_explicit(temp, sizeof(temp));
> >
> > Thanks!
> >
> > Best regards,
> > Yuzhuo
On Wed, May 21, 2025 at 03:53:05PM -0700, Yuzhuo Jing wrote:
> Those new files are derived from the kernel tree, namely:
>
> tools/perf/util/sha1.c from lib/crypto/sha1.c
> tools/perf/util/sha1.h from include/crypto/sha1.h
> tools/perf/util/sha1_base.h from include/crypto/sha1_base.h
> tools/perf/util/sha1_generic.c from crypto/sha1_generic.c
>
> The reason that we are not syncing them with the kernel tree like other
> tools header files is because of the deep dependency in
That is ok, we do it in some other cases, but while looking at this
patchset I checked and the source code for sha1_transform() is verbatim
the same, as intended, I wonder if we could add infrastructure to
check_headers.h to instead of checking whole files, check if the source
code we got from the kernel is the same, something along the lines of:
⬢ [acme@toolbx perf-tools-next]$ line=$(ctags -x --c-kinds=f lib/crypto/sha1.c | awk '$1 == "sha1_transform" {print $3}')
⬢ [acme@toolbx perf-tools-next]$ sed -n $line,\$p lib/crypto/sha1.c | awk '{print} /\{/ {c++} /\}/ {c--; if (c==0) exit}'
void sha1_transform(__u32 *digest, const char *data, __u32 *array)
{
__u32 A, B, C, D, E;
unsigned int i = 0;
A = digest[0];
B = digest[1];
C = digest[2];
D = digest[3];
E = digest[4];
/* Round 1 - iterations 0-16 take their input from 'data' */
for (; i < 16; ++i)
T_0_15(i, A, B, C, D, E);
/* Round 1 - tail. Input from 512-bit mixing array */
for (; i < 20; ++i)
T_16_19(i, A, B, C, D, E);
/* Round 2 */
for (; i < 40; ++i)
T_20_39(i, A, B, C, D, E);
/* Round 3 */
for (; i < 60; ++i)
T_40_59(i, A, B, C, D, E);
/* Round 4 */
for (; i < 80; ++i)
T_60_79(i, A, B, C, D, E);
digest[0] += A;
digest[1] += B;
digest[2] += C;
digest[3] += D;
digest[4] += E;
}
⬢ [acme@toolbx perf-tools-next]$
But that can be done later :-)
- Arnaldo
> include/crypto/hash.h. It's painful to import the whole kernel crypto
> driver infrastructure into tools.
> The derived files get rid of struct shash_desc definition, and directly
> operates on the struct sha1_state.
> Signed-off-by: Yuzhuo Jing <yuzhuo@google.com>
> ---
> tools/perf/util/Build | 2 +
> tools/perf/util/sha1.c | 122 +++++++++++++++++++++++++++++++++
> tools/perf/util/sha1.h | 41 +++++++++++
> tools/perf/util/sha1_base.h | 103 ++++++++++++++++++++++++++++
> tools/perf/util/sha1_generic.c | 49 +++++++++++++
> 5 files changed, 317 insertions(+)
> create mode 100644 tools/perf/util/sha1.c
> create mode 100644 tools/perf/util/sha1.h
> create mode 100644 tools/perf/util/sha1_base.h
> create mode 100644 tools/perf/util/sha1_generic.c
>
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 7910d908c814..ecee96b3f3fa 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -41,6 +41,8 @@ perf-util-y += rbtree.o
> perf-util-y += libstring.o
> perf-util-y += bitmap.o
> perf-util-y += hweight.o
> +perf-util-y += sha1.o
> +perf-util-y += sha1_generic.o
> perf-util-y += smt.o
> perf-util-y += strbuf.o
> perf-util-y += string.o
> diff --git a/tools/perf/util/sha1.c b/tools/perf/util/sha1.c
> new file mode 100644
> index 000000000000..5ae658afb56b
> --- /dev/null
> +++ b/tools/perf/util/sha1.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * SHA1 routine optimized to do word accesses rather than byte accesses,
> + * and to avoid unnecessary copies into the context array.
> + *
> + * This was based on the git SHA1 implementation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/string.h>
> +#include <linux/unaligned.h>
> +
> +#include "sha1.h"
> +
> +/*
> + * If you have 32 registers or more, the compiler can (and should)
> + * try to change the array[] accesses into registers. However, on
> + * machines with less than ~25 registers, that won't really work,
> + * and at least gcc will make an unholy mess of it.
> + *
> + * So to avoid that mess which just slows things down, we force
> + * the stores to memory to actually happen (we might be better off
> + * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
> + * suggested by Artur Skawina - that will also make gcc unable to
> + * try to do the silly "optimize away loads" part because it won't
> + * see what the value will be).
> + *
> + * Ben Herrenschmidt reports that on PPC, the C version comes close
> + * to the optimized asm with this (ie on PPC you don't want that
> + * 'volatile', since there are lots of registers).
> + *
> + * On ARM we get the best code generation by forcing a full memory barrier
> + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
> + * the stack frame size simply explode and performance goes down the drain.
> + */
> +
> +#ifdef CONFIG_X86
> + #define setW(x, val) (*(volatile __u32 *)&W(x) = (val))
> +#elif defined(CONFIG_ARM)
> + #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
> +#else
> + #define setW(x, val) (W(x) = (val))
> +#endif
> +
> +/* This "rolls" over the 512-bit array */
> +#define W(x) (array[(x)&15])
> +
> +/*
> + * Where do we get the source from? The first 16 iterations get it from
> + * the input data, the next mix it from the 512-bit array.
> + */
> +#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t)
> +#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
> +
> +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
> + __u32 TEMP = input(t); setW(t, TEMP); \
> + E += TEMP + rol32(A,5) + (fn) + (constant); \
> + B = ror32(B, 2); \
> + TEMP = E; E = D; D = C; C = B; B = A; A = TEMP; } while (0)
> +
> +#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
> +#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
> +#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
> +#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
> +#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
> +
> +/**
> + * sha1_transform - single block SHA1 transform (deprecated)
> + *
> + * @digest: 160 bit digest to update
> + * @data: 512 bits of data to hash
> + * @array: 16 words of workspace (see note)
> + *
> + * This function executes SHA-1's internal compression function. It updates the
> + * 160-bit internal state (@digest) with a single 512-bit data block (@data).
> + *
> + * Don't use this function. SHA-1 is no longer considered secure. And even if
> + * you do have to use SHA-1, this isn't the correct way to hash something with
> + * SHA-1 as this doesn't handle padding and finalization.
> + *
> + * Note: If the hash is security sensitive, the caller should be sure
> + * to clear the workspace. This is left to the caller to avoid
> + * unnecessary clears between chained hashing operations.
> + */
> +void sha1_transform(__u32 *digest, const char *data, __u32 *array)
> +{
> + __u32 A, B, C, D, E;
> + unsigned int i = 0;
> +
> + A = digest[0];
> + B = digest[1];
> + C = digest[2];
> + D = digest[3];
> + E = digest[4];
> +
> + /* Round 1 - iterations 0-16 take their input from 'data' */
> + for (; i < 16; ++i)
> + T_0_15(i, A, B, C, D, E);
> +
> + /* Round 1 - tail. Input from 512-bit mixing array */
> + for (; i < 20; ++i)
> + T_16_19(i, A, B, C, D, E);
> +
> + /* Round 2 */
> + for (; i < 40; ++i)
> + T_20_39(i, A, B, C, D, E);
> +
> + /* Round 3 */
> + for (; i < 60; ++i)
> + T_40_59(i, A, B, C, D, E);
> +
> + /* Round 4 */
> + for (; i < 80; ++i)
> + T_60_79(i, A, B, C, D, E);
> +
> + digest[0] += A;
> + digest[1] += B;
> + digest[2] += C;
> + digest[3] += D;
> + digest[4] += E;
> +}
> diff --git a/tools/perf/util/sha1.h b/tools/perf/util/sha1.h
> new file mode 100644
> index 000000000000..9da4ece49bc6
> --- /dev/null
> +++ b/tools/perf/util/sha1.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Common values for SHA-1 algorithms
> + */
> +
> +#ifndef _CRYPTO_SHA1_H
> +#define _CRYPTO_SHA1_H
> +
> +#include <linux/types.h>
> +
> +#define SHA1_DIGEST_SIZE 20
> +#define SHA1_BLOCK_SIZE 64
> +
> +#define SHA1_H0 0x67452301UL
> +#define SHA1_H1 0xefcdab89UL
> +#define SHA1_H2 0x98badcfeUL
> +#define SHA1_H3 0x10325476UL
> +#define SHA1_H4 0xc3d2e1f0UL
> +
> +struct sha1_state {
> + u32 state[SHA1_DIGEST_SIZE / 4];
> + u64 count;
> + u8 buffer[SHA1_BLOCK_SIZE];
> +};
> +
> +extern int crypto_sha1_update(struct sha1_state *desc, const u8 *data,
> + unsigned int len);
> +
> +extern int crypto_sha1_finup(struct sha1_state *desc, const u8 *data,
> + unsigned int len, u8 *hash);
> +
> +/*
> + * An implementation of SHA-1's compression function. Don't use in new code!
> + * You shouldn't be using SHA-1, and even if you *have* to use SHA-1, this isn't
> + * the correct way to hash something with SHA-1 (use crypto_shash instead).
> + */
> +#define SHA1_DIGEST_WORDS (SHA1_DIGEST_SIZE / 4)
> +#define SHA1_WORKSPACE_WORDS 16
> +void sha1_transform(__u32 *digest, const char *data, __u32 *W);
> +
> +#endif /* _CRYPTO_SHA1_H */
> diff --git a/tools/perf/util/sha1_base.h b/tools/perf/util/sha1_base.h
> new file mode 100644
> index 000000000000..cea22c5a4952
> --- /dev/null
> +++ b/tools/perf/util/sha1_base.h
> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * sha1_base.h - core logic for SHA-1 implementations
> + *
> + * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
> + */
> +
> +#ifndef _CRYPTO_SHA1_BASE_H
> +#define _CRYPTO_SHA1_BASE_H
> +
> +#include <linux/string.h>
> +
> +#include <linux/kernel.h>
> +#include <linux/unaligned.h>
> +
> +#include "sha1.h"
> +
> +typedef void (sha1_block_fn)(struct sha1_state *sst, u8 const *src, int blocks);
> +
> +static inline int sha1_base_init(struct sha1_state *sctx)
> +{
> + sctx->state[0] = SHA1_H0;
> + sctx->state[1] = SHA1_H1;
> + sctx->state[2] = SHA1_H2;
> + sctx->state[3] = SHA1_H3;
> + sctx->state[4] = SHA1_H4;
> + sctx->count = 0;
> +
> + return 0;
> +}
> +
> +static inline int sha1_base_do_update(struct sha1_state *sctx,
> + const u8 *data,
> + unsigned int len,
> + sha1_block_fn *block_fn)
> +{
> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +
> + sctx->count += len;
> +
> + if (unlikely((partial + len) >= SHA1_BLOCK_SIZE)) {
> + int blocks;
> +
> + if (partial) {
> + int p = SHA1_BLOCK_SIZE - partial;
> +
> + memcpy(sctx->buffer + partial, data, p);
> + data += p;
> + len -= p;
> +
> + block_fn(sctx, sctx->buffer, 1);
> + }
> +
> + blocks = len / SHA1_BLOCK_SIZE;
> + len %= SHA1_BLOCK_SIZE;
> +
> + if (blocks) {
> + block_fn(sctx, data, blocks);
> + data += blocks * SHA1_BLOCK_SIZE;
> + }
> + partial = 0;
> + }
> + if (len)
> + memcpy(sctx->buffer + partial, data, len);
> +
> + return 0;
> +}
> +
> +static inline int sha1_base_do_finalize(struct sha1_state *sctx,
> + sha1_block_fn *block_fn)
> +{
> + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +
> + sctx->buffer[partial++] = 0x80;
> + if (partial > bit_offset) {
> + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
> + partial = 0;
> +
> + block_fn(sctx, sctx->buffer, 1);
> + }
> +
> + memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> + *bits = cpu_to_be64(sctx->count << 3);
> + block_fn(sctx, sctx->buffer, 1);
> +
> + return 0;
> +}
> +
> +static inline int sha1_base_finish(struct sha1_state *sctx, u8 *out)
> +{
> + __be32 *digest = (__be32 *)out;
> + int i;
> +
> + for (i = 0; i < SHA1_DIGEST_SIZE / (int)sizeof(__be32); i++)
> + put_unaligned_be32(sctx->state[i], digest++);
> +
> + memzero_explicit(sctx, sizeof(*sctx));
> + return 0;
> +}
> +
> +#endif /* _CRYPTO_SHA1_BASE_H */
> diff --git a/tools/perf/util/sha1_generic.c b/tools/perf/util/sha1_generic.c
> new file mode 100644
> index 000000000000..b0a7af370d59
> --- /dev/null
> +++ b/tools/perf/util/sha1_generic.c
> @@ -0,0 +1,49 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Cryptographic API.
> + *
> + * SHA1 Secure Hash Algorithm.
> + *
> + * Derived from cryptoapi implementation, adapted for in-place
> + * scatterlist interface.
> + *
> + * Copyright (c) Alan Smithee.
> + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
> + * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
> + */
> +#include <linux/types.h>
> +#include <linux/string.h>
> +#include <asm/byteorder.h>
> +
> +#include "sha1_base.h"
> +
> +static void sha1_generic_block_fn(struct sha1_state *sst, u8 const *src,
> + int blocks)
> +{
> + u32 temp[SHA1_WORKSPACE_WORDS];
> +
> + while (blocks--) {
> + sha1_transform(sst->state, (const char *)src, temp);
> + src += SHA1_BLOCK_SIZE;
> + }
> + memzero_explicit(temp, sizeof(temp));
> +}
> +
> +int crypto_sha1_update(struct sha1_state *desc, const u8 *data,
> + unsigned int len)
> +{
> + return sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
> +}
> +
> +static int sha1_final(struct sha1_state *desc, u8 *out)
> +{
> + sha1_base_do_finalize(desc, sha1_generic_block_fn);
> + return sha1_base_finish(desc, out);
> +}
> +
> +int crypto_sha1_finup(struct sha1_state *desc, const u8 *data,
> + unsigned int len, u8 *out)
> +{
> + sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
> + return sha1_final(desc, out);
> +}
> --
> 2.49.0.1164.gab81da1b16-goog
© 2016 - 2025 Red Hat, Inc.