mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-02 03:30:08 -04:00
perf util: Add BLAKE2s support
Add BLAKE2s support to the perf utility library. The code is borrowed from the kernel. This will replace the use of SHA-1 in genelf.c. Signed-off-by: Eric Biggers <ebiggers@kernel.org> Tested-by: Ian Rogers <irogers@google.com> Acked-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Fangrui Song <maskray@sourceware.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jason A. Donenfeld <Jason@zx2c4.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Pablo Galindo <pablogsal@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
b6ee9b6e20
commit
8d3b664949
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "tests.h"
|
||||
#include "util/blake2s.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/sha1.h"
|
||||
|
||||
@@ -59,8 +60,79 @@ static int test_sha1(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Maximum data length tested by test_blake2s() */
|
||||
#define MAX_DATA_LEN 512
|
||||
|
||||
/*
|
||||
* Hash length tested by test_blake2s(). BLAKE2s supports variable-length
|
||||
* hashes. However, the only user of BLAKE2s in 'perf' uses 20-byte hashes,
|
||||
* matching the length of the ELF build ID field. So that's the length we test.
|
||||
*/
|
||||
#define HASH_LEN 20
|
||||
|
||||
/* Test the implementation of the BLAKE2s hash algorithm. */
|
||||
static int test_blake2s(void)
|
||||
{
|
||||
u8 data[MAX_DATA_LEN];
|
||||
u8 hash[HASH_LEN];
|
||||
u8 hash2[HASH_LEN];
|
||||
struct blake2s_ctx main_ctx;
|
||||
/*
|
||||
* This value was generated by the following Python code:
|
||||
*
|
||||
* import hashlib
|
||||
*
|
||||
* data = bytes(i % 256 for i in range(513))
|
||||
* h = hashlib.blake2s(digest_size=20)
|
||||
* for i in range(513):
|
||||
* h.update(hashlib.blake2s(data=data[:i], digest_size=20).digest())
|
||||
* print(h.hexdigest())
|
||||
*/
|
||||
static const u8 expected_hash_of_hashes[20] = {
|
||||
0xef, 0x9b, 0x13, 0x98, 0x78, 0x8e, 0x74, 0x59, 0x9c, 0xd5,
|
||||
0x0c, 0xf0, 0x33, 0x97, 0x79, 0x3d, 0x3e, 0xd0, 0x95, 0xa6
|
||||
};
|
||||
size_t i;
|
||||
|
||||
/* Generate MAX_DATA_LEN bytes of data. */
|
||||
for (i = 0; i < MAX_DATA_LEN; i++)
|
||||
data[i] = i;
|
||||
|
||||
blake2s_init(&main_ctx, sizeof(hash));
|
||||
for (i = 0; i <= MAX_DATA_LEN; i++) {
|
||||
struct blake2s_ctx ctx;
|
||||
|
||||
/* Compute the BLAKE2s hash of 'i' data bytes. */
|
||||
blake2s_init(&ctx, HASH_LEN);
|
||||
blake2s_update(&ctx, data, i);
|
||||
blake2s_final(&ctx, hash);
|
||||
|
||||
/* Verify that multiple updates produce the same result. */
|
||||
blake2s_init(&ctx, HASH_LEN);
|
||||
blake2s_update(&ctx, data, i / 2);
|
||||
blake2s_update(&ctx, &data[i / 2], i - (i / 2));
|
||||
blake2s_final(&ctx, hash2);
|
||||
TEST_ASSERT_VAL("inconsistent BLAKE2s hashes",
|
||||
memcmp(hash, hash2, HASH_LEN) == 0);
|
||||
|
||||
/*
|
||||
* Pass the hash to another BLAKE2s context, so that we
|
||||
* incrementally compute the hash of all the hashes.
|
||||
*/
|
||||
blake2s_update(&main_ctx, hash, HASH_LEN);
|
||||
}
|
||||
|
||||
/* Verify the hash of all the hashes. */
|
||||
blake2s_final(&main_ctx, hash);
|
||||
TEST_ASSERT_VAL("wrong BLAKE2s hashes",
|
||||
memcmp(hash, expected_hash_of_hashes, HASH_LEN) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_unused)
|
||||
{
|
||||
int ret;
|
||||
|
||||
TEST_ASSERT_VAL("empty string", test_strreplace(' ', "", "123", ""));
|
||||
TEST_ASSERT_VAL("no match", test_strreplace('5', "123", "4", "123"));
|
||||
TEST_ASSERT_VAL("replace 1", test_strreplace('3', "123", "4", "124"));
|
||||
@@ -68,7 +140,11 @@ static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_u
|
||||
TEST_ASSERT_VAL("replace long", test_strreplace('a', "abcabc", "longlong",
|
||||
"longlongbclonglongbc"));
|
||||
|
||||
return test_sha1();
|
||||
ret = test_sha1();
|
||||
if (ret != TEST_OK)
|
||||
return ret;
|
||||
|
||||
return test_blake2s();
|
||||
}
|
||||
|
||||
DEFINE_SUITE("util", util);
|
||||
|
||||
@@ -5,6 +5,7 @@ perf-util-y += arm64-frame-pointer-unwind-support.o
|
||||
perf-util-y += addr2line.o
|
||||
perf-util-y += addr_location.o
|
||||
perf-util-y += annotate.o
|
||||
perf-util-y += blake2s.o
|
||||
perf-util-y += block-info.o
|
||||
perf-util-y += block-range.o
|
||||
perf-util-y += build-id.o
|
||||
|
||||
151
tools/perf/util/blake2s.c
Normal file
151
tools/perf/util/blake2s.c
Normal file
@@ -0,0 +1,151 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
*
|
||||
* This is an implementation of the BLAKE2s hash and PRF functions.
|
||||
*
|
||||
* Information: https://blake2.net/
|
||||
*/
|
||||
|
||||
#include "blake2s.h"
|
||||
#include <linux/kernel.h>
|
||||
|
||||
static inline u32 ror32(u32 v, int n)
|
||||
{
|
||||
return (v >> n) | (v << (32 - n));
|
||||
}
|
||||
|
||||
static inline void le32_to_cpu_array(u32 a[], size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
a[i] = le32_to_cpu((__force __le32)a[i]);
|
||||
}
|
||||
|
||||
static inline void cpu_to_le32_array(u32 a[], size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
a[i] = (__force u32)cpu_to_le32(a[i]);
|
||||
}
|
||||
|
||||
static const u8 blake2s_sigma[10][16] = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
|
||||
};
|
||||
|
||||
static inline void blake2s_increment_counter(struct blake2s_ctx *ctx, u32 inc)
|
||||
{
|
||||
ctx->t[0] += inc;
|
||||
ctx->t[1] += (ctx->t[0] < inc);
|
||||
}
|
||||
|
||||
static void blake2s_compress(struct blake2s_ctx *ctx,
|
||||
const u8 *data, size_t nblocks, u32 inc)
|
||||
{
|
||||
u32 m[16];
|
||||
u32 v[16];
|
||||
int i;
|
||||
|
||||
while (nblocks > 0) {
|
||||
blake2s_increment_counter(ctx, inc);
|
||||
memcpy(m, data, BLAKE2S_BLOCK_SIZE);
|
||||
le32_to_cpu_array(m, ARRAY_SIZE(m));
|
||||
memcpy(v, ctx->h, 32);
|
||||
v[ 8] = BLAKE2S_IV0;
|
||||
v[ 9] = BLAKE2S_IV1;
|
||||
v[10] = BLAKE2S_IV2;
|
||||
v[11] = BLAKE2S_IV3;
|
||||
v[12] = BLAKE2S_IV4 ^ ctx->t[0];
|
||||
v[13] = BLAKE2S_IV5 ^ ctx->t[1];
|
||||
v[14] = BLAKE2S_IV6 ^ ctx->f[0];
|
||||
v[15] = BLAKE2S_IV7 ^ ctx->f[1];
|
||||
|
||||
#define G(r, i, a, b, c, d) do { \
|
||||
a += b + m[blake2s_sigma[r][2 * i + 0]]; \
|
||||
d = ror32(d ^ a, 16); \
|
||||
c += d; \
|
||||
b = ror32(b ^ c, 12); \
|
||||
a += b + m[blake2s_sigma[r][2 * i + 1]]; \
|
||||
d = ror32(d ^ a, 8); \
|
||||
c += d; \
|
||||
b = ror32(b ^ c, 7); \
|
||||
} while (0)
|
||||
|
||||
#define ROUND(r) do { \
|
||||
G(r, 0, v[0], v[ 4], v[ 8], v[12]); \
|
||||
G(r, 1, v[1], v[ 5], v[ 9], v[13]); \
|
||||
G(r, 2, v[2], v[ 6], v[10], v[14]); \
|
||||
G(r, 3, v[3], v[ 7], v[11], v[15]); \
|
||||
G(r, 4, v[0], v[ 5], v[10], v[15]); \
|
||||
G(r, 5, v[1], v[ 6], v[11], v[12]); \
|
||||
G(r, 6, v[2], v[ 7], v[ 8], v[13]); \
|
||||
G(r, 7, v[3], v[ 4], v[ 9], v[14]); \
|
||||
} while (0)
|
||||
ROUND(0);
|
||||
ROUND(1);
|
||||
ROUND(2);
|
||||
ROUND(3);
|
||||
ROUND(4);
|
||||
ROUND(5);
|
||||
ROUND(6);
|
||||
ROUND(7);
|
||||
ROUND(8);
|
||||
ROUND(9);
|
||||
|
||||
#undef G
|
||||
#undef ROUND
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
ctx->h[i] ^= v[i] ^ v[i + 8];
|
||||
|
||||
data += BLAKE2S_BLOCK_SIZE;
|
||||
--nblocks;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void blake2s_set_lastblock(struct blake2s_ctx *ctx)
|
||||
{
|
||||
ctx->f[0] = -1;
|
||||
}
|
||||
|
||||
void blake2s_update(struct blake2s_ctx *ctx, const u8 *in, size_t inlen)
|
||||
{
|
||||
const size_t fill = BLAKE2S_BLOCK_SIZE - ctx->buflen;
|
||||
|
||||
if (unlikely(!inlen))
|
||||
return;
|
||||
if (inlen > fill) {
|
||||
memcpy(ctx->buf + ctx->buflen, in, fill);
|
||||
blake2s_compress(ctx, ctx->buf, 1, BLAKE2S_BLOCK_SIZE);
|
||||
ctx->buflen = 0;
|
||||
in += fill;
|
||||
inlen -= fill;
|
||||
}
|
||||
if (inlen > BLAKE2S_BLOCK_SIZE) {
|
||||
const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
|
||||
|
||||
blake2s_compress(ctx, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
|
||||
in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
|
||||
inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
|
||||
}
|
||||
memcpy(ctx->buf + ctx->buflen, in, inlen);
|
||||
ctx->buflen += inlen;
|
||||
}
|
||||
|
||||
void blake2s_final(struct blake2s_ctx *ctx, u8 *out)
|
||||
{
|
||||
blake2s_set_lastblock(ctx);
|
||||
memset(ctx->buf + ctx->buflen, 0,
|
||||
BLAKE2S_BLOCK_SIZE - ctx->buflen); /* Padding */
|
||||
blake2s_compress(ctx, ctx->buf, 1, ctx->buflen);
|
||||
cpu_to_le32_array(ctx->h, ARRAY_SIZE(ctx->h));
|
||||
memcpy(out, ctx->h, ctx->outlen);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
73
tools/perf/util/blake2s.h
Normal file
73
tools/perf/util/blake2s.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
/*
|
||||
* Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_BLAKE2S_H
|
||||
#define _CRYPTO_BLAKE2S_H
|
||||
|
||||
#include <string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define BLAKE2S_BLOCK_SIZE 64
|
||||
|
||||
struct blake2s_ctx {
|
||||
u32 h[8];
|
||||
u32 t[2];
|
||||
u32 f[2];
|
||||
u8 buf[BLAKE2S_BLOCK_SIZE];
|
||||
unsigned int buflen;
|
||||
unsigned int outlen;
|
||||
};
|
||||
|
||||
enum blake2s_iv {
|
||||
BLAKE2S_IV0 = 0x6A09E667UL,
|
||||
BLAKE2S_IV1 = 0xBB67AE85UL,
|
||||
BLAKE2S_IV2 = 0x3C6EF372UL,
|
||||
BLAKE2S_IV3 = 0xA54FF53AUL,
|
||||
BLAKE2S_IV4 = 0x510E527FUL,
|
||||
BLAKE2S_IV5 = 0x9B05688CUL,
|
||||
BLAKE2S_IV6 = 0x1F83D9ABUL,
|
||||
BLAKE2S_IV7 = 0x5BE0CD19UL,
|
||||
};
|
||||
|
||||
static inline void __blake2s_init(struct blake2s_ctx *ctx, size_t outlen,
|
||||
const void *key, size_t keylen)
|
||||
{
|
||||
ctx->h[0] = BLAKE2S_IV0 ^ (0x01010000 | keylen << 8 | outlen);
|
||||
ctx->h[1] = BLAKE2S_IV1;
|
||||
ctx->h[2] = BLAKE2S_IV2;
|
||||
ctx->h[3] = BLAKE2S_IV3;
|
||||
ctx->h[4] = BLAKE2S_IV4;
|
||||
ctx->h[5] = BLAKE2S_IV5;
|
||||
ctx->h[6] = BLAKE2S_IV6;
|
||||
ctx->h[7] = BLAKE2S_IV7;
|
||||
ctx->t[0] = 0;
|
||||
ctx->t[1] = 0;
|
||||
ctx->f[0] = 0;
|
||||
ctx->f[1] = 0;
|
||||
ctx->buflen = 0;
|
||||
ctx->outlen = outlen;
|
||||
if (keylen) {
|
||||
memcpy(ctx->buf, key, keylen);
|
||||
memset(&ctx->buf[keylen], 0, BLAKE2S_BLOCK_SIZE - keylen);
|
||||
ctx->buflen = BLAKE2S_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void blake2s_init(struct blake2s_ctx *ctx, size_t outlen)
|
||||
{
|
||||
__blake2s_init(ctx, outlen, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void blake2s_init_key(struct blake2s_ctx *ctx, size_t outlen,
|
||||
const void *key, size_t keylen)
|
||||
{
|
||||
__blake2s_init(ctx, outlen, key, keylen);
|
||||
}
|
||||
|
||||
void blake2s_update(struct blake2s_ctx *ctx, const u8 *in, size_t inlen);
|
||||
|
||||
void blake2s_final(struct blake2s_ctx *ctx, u8 *out);
|
||||
|
||||
#endif /* _CRYPTO_BLAKE2S_H */
|
||||
Reference in New Issue
Block a user