Test the implementation of a second hash algorithm with "short"
(160-bit) BLAKE2b support. Simply add an additional algorithm to the
codebase without changing the use of any hash function and add a test
helper.
BLAKE2b was chosen simply because it provides a readily accessible hash
algorithm with arbitrary length support. A 160-bit (20-byte) hash was
chosen to allow identification of tests that depend on the hash
algorithm in use while not causing buffer overflows, since parts of the
codebase still assume a 20-byte hash.
This is a preliminary commit for test purposes only and should not be
used in production in any way.
---
Makefile | 3 +++
cache.h | 16 ++++++++++++++
hash.h | 9 +++++++-
sha1_file.c | 33 ++++++++++++++++++++++++++++
t/helper/test-sblake2b.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 116 insertions(+), 1 deletion(-)
create mode 100644 t/helper/test-sblake2b.c
diff --git a/Makefile b/Makefile
index 1a9b23b679..d46247586b 100644
--- a/Makefile
+++ b/Makefile
@@ -677,6 +677,7 @@ TEST_PROGRAMS_NEED_X += test-ref-store
TEST_PROGRAMS_NEED_X += test-regex
TEST_PROGRAMS_NEED_X += test-revision-walking
TEST_PROGRAMS_NEED_X += test-run-command
+TEST_PROGRAMS_NEED_X += test-sblake2b
TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sha1-array
@@ -1539,6 +1540,8 @@ endif
endif
endif
+EXTLIBS += -lb2
+
ifdef SHA1_MAX_BLOCK_SIZE
LIB_OBJS += compat/sha1-chunked.o
BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"
diff --git a/cache.h b/cache.h
index bfde6f757a..638d832350 100644
--- a/cache.h
+++ b/cache.h
@@ -45,6 +45,10 @@ unsigned long git_deflate_bound(git_zstream *, unsigned
long);
#define GIT_SHA1_RAWSZ 20
#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
+/* The length in bytes and in hex digits of an object name (short BLAKE2b
value). */
+#define GIT_SBLAKE2B_RAWSZ 20
+#define GIT_SBLAKE2B_HEXSZ (2 * GIT_SBLAKE2B_RAWSZ)
+
/* The length in byte and in hex digits of the largest possible hash value. */
#define GIT_MAX_RAWSZ GIT_SHA1_RAWSZ
#define GIT_MAX_HEXSZ GIT_SHA1_HEXSZ
@@ -1013,7 +1017,13 @@ static inline void oidclr(struct object_id *oid)
#define EMPTY_TREE_SHA1_BIN_LITERAL \
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
+#define EMPTY_TREE_SBLAKE2B_HEX \
+ "f44422a644bfa5212387098f253a1e89eba94548"
+#define EMPTY_TREE_SBLAKE2B_BIN_LITERAL \
+ "\xf4\x44\x22\xa6\x44\xbf\xa5\x21\x23\x87" \
+ "\x09\x8f\x25\x3a\x1e\x89\xeb\xa9\x45\x48"
extern const struct object_id empty_tree_oid;
+const struct object_id empty_tree_oid_sblake2b;
#define EMPTY_TREE_SHA1_BIN (empty_tree_oid.hash)
#define EMPTY_BLOB_SHA1_HEX \
@@ -1021,7 +1031,13 @@ extern const struct object_id empty_tree_oid;
#define EMPTY_BLOB_SHA1_BIN_LITERAL \
"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
"\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
+#define EMPTY_BLOB_SBLAKE2B_HEX \
+ "a706650a477f63b9b00eba41272bf36ef5a7dfa2"
+#define EMPTY_BLOB_SBLAKE2B_BIN_LITERAL \
+ "\xa7\x06\x65\x0a\x47\x7f\x63\xb9\xb0\x0e" \
+ "\xba\x41\x27\x2b\xf3\x6e\xf5\xa7\xdf\xa2"
extern const struct object_id empty_blob_oid;
+const struct object_id empty_blob_oid_sblake2b;
#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
diff --git a/hash.h b/hash.h
index 365846a6b5..ef510bd51a 100644
--- a/hash.h
+++ b/hash.h
@@ -15,6 +15,8 @@
#include "block-sha1/sha1.h"
#endif
+#include <blake2.h>
+
#ifndef platform_SHA_CTX
/*
* platform's underlying implementation of SHA-1; could be OpenSSL,
@@ -40,6 +42,8 @@
#define git_SHA1_Update git_SHA1_Update_Chunked
#endif
+#define git_BLAKE2B_CTX blake2b_state
+
/*
* Note that these constants are suitable for indexing the hash_algos array and
* comparing against each other, but are otherwise arbitrary, so they should
not
@@ -52,12 +56,15 @@
#define GIT_HASH_UNKNOWN 0
/* SHA-1 */
#define GIT_HASH_SHA1 1
+/* 20-byte BLAKE2b ("short" BLAKE2b) */
+#define GIT_HASH_SBLAKE2 2
/* Number of algorithms supported (including unknown). */
-#define GIT_HASH_NALGOS (GIT_HASH_SHA1 + 1)
+#define GIT_HASH_NALGOS (GIT_HASH_SBLAKE2 + 1)
/* A suitably aligned type for stack allocations of hash contexts. */
union git_hash_ctx {
git_SHA_CTX sha1;
+ git_BLAKE2B_CTX blake2b;
};
typedef union git_hash_ctx git_hash_ctx;
diff --git a/sha1_file.c b/sha1_file.c
index d9e2b1f285..5067b22a30 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -38,6 +38,12 @@ const struct object_id empty_tree_oid = {
const struct object_id empty_blob_oid = {
EMPTY_BLOB_SHA1_BIN_LITERAL
};
+const struct object_id empty_tree_oid_sblake2b = {
+ EMPTY_TREE_SBLAKE2B_BIN_LITERAL
+};
+const struct object_id empty_blob_oid_sblake2b = {
+ EMPTY_BLOB_SBLAKE2B_BIN_LITERAL
+};
static void git_hash_sha1_init(void *ctx)
{
@@ -54,6 +60,21 @@ static void git_hash_sha1_final(unsigned char *hash, void
*ctx)
git_SHA1_Final(hash, (git_SHA_CTX *)ctx);
}
+static void git_hash_sblake2b_init(void *ctx)
+{
+ blake2b_init((git_BLAKE2B_CTX *)ctx, GIT_SBLAKE2B_RAWSZ);
+}
+
+static void git_hash_sblake2b_update(void *ctx, const void *data, size_t len)
+{
+ blake2b_update((git_BLAKE2B_CTX *)ctx, data, len);
+}
+
+static void git_hash_sblake2b_final(unsigned char *hash, void *ctx)
+{
+ blake2b_final((git_BLAKE2B_CTX *)ctx, hash, GIT_SBLAKE2B_RAWSZ);
+}
+
static void git_hash_unknown_init(void *ctx)
{
die("trying to init unknown hash");
@@ -93,6 +114,18 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
&empty_tree_oid,
&empty_blob_oid,
},
+ {
+ "sblake2b",
+ /* "sb2b", big-endian */
+ 0x73623262,
+ GIT_SBLAKE2B_RAWSZ,
+ GIT_SBLAKE2B_HEXSZ,
+ git_hash_sblake2b_init,
+ git_hash_sblake2b_update,
+ git_hash_sblake2b_final,
+ &empty_tree_oid_sblake2b,
+ &empty_blob_oid_sblake2b,
+ }
};
/*
diff --git a/t/helper/test-sblake2b.c b/t/helper/test-sblake2b.c
new file mode 100644
index 0000000000..6623aaa4d5
--- /dev/null
+++ b/t/helper/test-sblake2b.c
@@ -0,0 +1,56 @@
+#include "cache.h"
+
+int cmd_main(int ac, const char **av)
+{
+ git_hash_ctx ctx;
+ unsigned char hash[GIT_MAX_RAWSZ];
+ unsigned bufsz = 8192;
+ int binary = 0;
+ char *buffer;
+
+ if (ac == 2) {
+ if (!strcmp(av[1], "-b"))
+ binary = 1;
+ else
+ bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024;
+ }
+
+ if (!bufsz)
+ bufsz = 8192;
+
+ while ((buffer = malloc(bufsz)) == NULL) {
+ fprintf(stderr, "bufsz %u is too big, halving...\n", bufsz);
+ bufsz /= 2;
+ if (bufsz < 1024)
+ die("OOPS");
+ }
+
+ hash_algos[GIT_HASH_SBLAKE2].init_fn(&ctx);
+
+ while (1) {
+ ssize_t sz, this_sz;
+ char *cp = buffer;
+ unsigned room = bufsz;
+ this_sz = 0;
+ while (room) {
+ sz = xread(0, cp, room);
+ if (sz == 0)
+ break;
+ if (sz < 0)
+ die_errno("test-sha1");
+ this_sz += sz;
+ cp += sz;
+ room -= sz;
+ }
+ if (this_sz == 0)
+ break;
+ hash_algos[GIT_HASH_SBLAKE2].update_fn(&ctx, buffer, this_sz);
+ }
+ hash_algos[GIT_HASH_SBLAKE2].final_fn(hash, &ctx);
+
+ if (binary)
+ fwrite(hash, 1, hash_algos[GIT_HASH_SBLAKE2].rawsz, stdout);
+ else
+ puts(sha1_to_hex(hash));
+ exit(0);
+}