hash: add a function to finalize object IDs

To avoid the penalty of having to branch in hash comparison functions, we'll want to always compare the full hash member in a struct object_id, which will require that SHA-1 object IDs be zero-padded. To do so, add a function which finalizes a hash context and writes it into an object ID that performs this padding. Move the definition of struct object_id and the constant definitions higher up so we they are available for us to use. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Apr 26, 2021 at 01:02 UTC ab795f0d77aec52496557eb69a5fc9e4f60ea1fd
2 files changed +52 -23
hash.h
+27 -23
@@ -95,6 +95,29 @@ static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *s
95 /* Number of algorithms supported (including unknown). */
96 #define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
97
98 +/* The length in bytes and in hex digits of an object name (SHA-1 value). */
99 +#define GIT_SHA1_RAWSZ 20
100 +#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
101 +/* The block size of SHA-1. */
102 +#define GIT_SHA1_BLKSZ 64
103 +
104 +/* The length in bytes and in hex digits of an object name (SHA-256 value). */
105 +#define GIT_SHA256_RAWSZ 32
106 +#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
107 +/* The block size of SHA-256. */
108 +#define GIT_SHA256_BLKSZ 64
109 +
110 +/* The length in byte and in hex digits of the largest possible hash value. */
111 +#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
112 +#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
113 +/* The largest possible block size for any supported hash. */
114 +#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
115 +
116 +struct object_id {
117 + unsigned char hash[GIT_MAX_RAWSZ];
118 + int algo;
119 +};
120 +
121 /* A suitably aligned type for stack allocations of hash contexts. */
122 union git_hash_ctx {
123 git_SHA_CTX sha1;
@@ -106,6 +129,7 @@ typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
129 typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
130 typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
131 typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
132 +typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
133
134 struct git_hash_algo {
135 /*
@@ -138,6 +162,9 @@ struct git_hash_algo {
162 /* The hash finalization function. */
163 git_hash_final_fn final_fn;
164
165 + /* The hash finalization function for object IDs. */
166 + git_hash_final_oid_fn final_oid_fn;
167 +
168 /* The OID of the empty tree. */
169 const struct object_id *empty_tree;
170
@@ -161,29 +188,6 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
188 return p - hash_algos;
189 }
190
164 -/* The length in bytes and in hex digits of an object name (SHA-1 value). */
165 -#define GIT_SHA1_RAWSZ 20
166 -#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
167 -/* The block size of SHA-1. */
168 -#define GIT_SHA1_BLKSZ 64
169 -
170 -/* The length in bytes and in hex digits of an object name (SHA-256 value). */
171 -#define GIT_SHA256_RAWSZ 32
172 -#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
173 -/* The block size of SHA-256. */
174 -#define GIT_SHA256_BLKSZ 64
175 -
176 -/* The length in byte and in hex digits of the largest possible hash value. */
177 -#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
178 -#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
179 -/* The largest possible block size for any supported hash. */
180 -#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
181 -
182 -struct object_id {
183 - unsigned char hash[GIT_MAX_RAWSZ];
184 - int algo;
185 -};
186 -
191 #define the_hash_algo the_repository->hash_algo
192
193 extern const struct object_id null_oid;
object-file.c
+25
@@ -89,6 +89,12 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
89 git_SHA1_Final(hash, &ctx->sha1);
90 }
91
92 +static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
93 +{
94 + git_SHA1_Final(oid->hash, &ctx->sha1);
95 + memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
96 +}
97 +
98
99 static void git_hash_sha256_init(git_hash_ctx *ctx)
100 {
@@ -110,6 +116,16 @@ static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
116 git_SHA256_Final(hash, &ctx->sha256);
117 }
118
119 +static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
120 +{
121 + git_SHA256_Final(oid->hash, &ctx->sha256);
122 + /*
123 + * This currently does nothing, so the compiler should optimize it out,
124 + * but keep it in case we extend the hash size again.
125 + */
126 + memset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ);
127 +}
128 +
129 static void git_hash_unknown_init(git_hash_ctx *ctx)
130 {
131 BUG("trying to init unknown hash");
@@ -130,6 +146,12 @@ static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)
146 BUG("trying to finalize unknown hash");
147 }
148
149 +static void git_hash_unknown_final_oid(struct object_id *oid, git_hash_ctx *ctx)
150 +{
151 + BUG("trying to finalize unknown hash");
152 +}
153 +
154 +
155 const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
156 {
157 NULL,
@@ -141,6 +163,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
163 git_hash_unknown_clone,
164 git_hash_unknown_update,
165 git_hash_unknown_final,
166 + git_hash_unknown_final_oid,
167 NULL,
168 NULL,
169 },
@@ -155,6 +178,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
178 git_hash_sha1_clone,
179 git_hash_sha1_update,
180 git_hash_sha1_final,
181 + git_hash_sha1_final_oid,
182 &empty_tree_oid,
183 &empty_blob_oid,
184 },
@@ -169,6 +193,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
193 git_hash_sha256_clone,
194 git_hash_sha256_update,
195 git_hash_sha256_final,
196 + git_hash_sha256_final_oid,
197 &empty_tree_oid_sha256,
198 &empty_blob_oid_sha256,
199 }