Skip to content

Commit 13eeedb

Browse files
bk2204gitster
authored andcommitted
Add a base implementation of SHA-256 support
SHA-1 is weak and we need to transition to a new hash function. For some time, we have referred to this new function as NewHash. Recently, we decided to pick SHA-256 as NewHash. The reasons behind the choice of SHA-256 are outlined in the thread starting at [1] and in the commit history for the hash function transition document. Add a basic implementation of SHA-256 based off libtomcrypt, which is in the public domain. Optimize it and restructure it to meet our coding standards. Pull in the update and final functions from the SHA-1 block implementation, as we know these function correctly with all compilers. This implementation is slower than SHA-1, but more performant implementations will be introduced in future commits. Wire up SHA-256 in the list of hash algorithms, and add a test that the algorithm works correctly. Note that with this patch, it is still not possible to switch to using SHA-256 in Git. Additional patches are needed to prepare the code to handle a larger hash algorithm and further test fixes are needed. [1] https://public-inbox.org/git/20180609224913.GC38834@genre.crustytoothpaste.net/ Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent c166599 commit 13eeedb

File tree

10 files changed

+331
-4
lines changed

10 files changed

+331
-4
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ TEST_BUILTINS_OBJS += test-run-command.o
739739
TEST_BUILTINS_OBJS += test-scrap-cache-tree.o
740740
TEST_BUILTINS_OBJS += test-sha1.o
741741
TEST_BUILTINS_OBJS += test-sha1-array.o
742+
TEST_BUILTINS_OBJS += test-sha256.o
742743
TEST_BUILTINS_OBJS += test-sigchain.o
743744
TEST_BUILTINS_OBJS += test-strcmp-offset.o
744745
TEST_BUILTINS_OBJS += test-string-list.o
@@ -1633,6 +1634,9 @@ endif
16331634
endif
16341635
endif
16351636

1637+
LIB_OBJS += sha256/block/sha256.o
1638+
BASIC_CFLAGS += -DSHA256_BLK
1639+
16361640
ifdef SHA1_MAX_BLOCK_SIZE
16371641
LIB_OBJS += compat/sha1-chunked.o
16381642
BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"

cache.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,17 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
4848
/* The block size of SHA-1. */
4949
#define GIT_SHA1_BLKSZ 64
5050

51+
/* The length in bytes and in hex digits of an object name (SHA-256 value). */
52+
#define GIT_SHA256_RAWSZ 32
53+
#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
54+
/* The block size of SHA-256. */
55+
#define GIT_SHA256_BLKSZ 64
56+
5157
/* The length in byte and in hex digits of the largest possible hash value. */
52-
#define GIT_MAX_RAWSZ GIT_SHA1_RAWSZ
53-
#define GIT_MAX_HEXSZ GIT_SHA1_HEXSZ
58+
#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
59+
#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
5460
/* The largest possible block size for any supported hash. */
55-
#define GIT_MAX_BLKSZ GIT_SHA1_BLKSZ
61+
#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
5662

5763
struct object_id {
5864
unsigned char hash[GIT_MAX_RAWSZ];

hash.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "block-sha1/sha1.h"
1616
#endif
1717

18+
#include "sha256/block/sha256.h"
19+
1820
#ifndef platform_SHA_CTX
1921
/*
2022
* platform's underlying implementation of SHA-1; could be OpenSSL,
@@ -34,6 +36,18 @@
3436
#define git_SHA1_Update platform_SHA1_Update
3537
#define git_SHA1_Final platform_SHA1_Final
3638

39+
#ifndef platform_SHA256_CTX
40+
#define platform_SHA256_CTX SHA256_CTX
41+
#define platform_SHA256_Init SHA256_Init
42+
#define platform_SHA256_Update SHA256_Update
43+
#define platform_SHA256_Final SHA256_Final
44+
#endif
45+
46+
#define git_SHA256_CTX platform_SHA256_CTX
47+
#define git_SHA256_Init platform_SHA256_Init
48+
#define git_SHA256_Update platform_SHA256_Update
49+
#define git_SHA256_Final platform_SHA256_Final
50+
3751
#ifdef SHA1_MAX_BLOCK_SIZE
3852
#include "compat/sha1-chunked.h"
3953
#undef git_SHA1_Update
@@ -52,12 +66,15 @@
5266
#define GIT_HASH_UNKNOWN 0
5367
/* SHA-1 */
5468
#define GIT_HASH_SHA1 1
69+
/* SHA-256 */
70+
#define GIT_HASH_SHA256 2
5571
/* Number of algorithms supported (including unknown). */
56-
#define GIT_HASH_NALGOS (GIT_HASH_SHA1 + 1)
72+
#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
5773

5874
/* A suitably aligned type for stack allocations of hash contexts. */
5975
union git_hash_ctx {
6076
git_SHA_CTX sha1;
77+
git_SHA256_CTX sha256;
6178
};
6279
typedef union git_hash_ctx git_hash_ctx;
6380

sha1-file.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,20 @@
4040
#define EMPTY_TREE_SHA1_BIN_LITERAL \
4141
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
4242
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
43+
#define EMPTY_TREE_SHA256_BIN_LITERAL \
44+
"\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1" \
45+
"\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5" \
46+
"\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc" \
47+
"\x53\x21"
4348

4449
#define EMPTY_BLOB_SHA1_BIN_LITERAL \
4550
"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
4651
"\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
52+
#define EMPTY_BLOB_SHA256_BIN_LITERAL \
53+
"\x47\x3a\x0f\x4c\x3b\xe8\xa9\x36\x81\xa2" \
54+
"\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43" \
55+
"\x6f\xe1\x41\xf7\x74\x91\x20\xa3\x03\x72" \
56+
"\x18\x13"
4757

4858
const unsigned char null_sha1[GIT_MAX_RAWSZ];
4959
const struct object_id null_oid;
@@ -53,6 +63,12 @@ static const struct object_id empty_tree_oid = {
5363
static const struct object_id empty_blob_oid = {
5464
EMPTY_BLOB_SHA1_BIN_LITERAL
5565
};
66+
static const struct object_id empty_tree_oid_sha256 = {
67+
EMPTY_TREE_SHA256_BIN_LITERAL
68+
};
69+
static const struct object_id empty_blob_oid_sha256 = {
70+
EMPTY_BLOB_SHA256_BIN_LITERAL
71+
};
5672

5773
static void git_hash_sha1_init(git_hash_ctx *ctx)
5874
{
@@ -69,6 +85,22 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
6985
git_SHA1_Final(hash, &ctx->sha1);
7086
}
7187

88+
89+
static void git_hash_sha256_init(git_hash_ctx *ctx)
90+
{
91+
git_SHA256_Init(&ctx->sha256);
92+
}
93+
94+
static void git_hash_sha256_update(git_hash_ctx *ctx, const void *data, size_t len)
95+
{
96+
git_SHA256_Update(&ctx->sha256, data, len);
97+
}
98+
99+
static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
100+
{
101+
git_SHA256_Final(hash, &ctx->sha256);
102+
}
103+
72104
static void git_hash_unknown_init(git_hash_ctx *ctx)
73105
{
74106
BUG("trying to init unknown hash");
@@ -110,6 +142,19 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
110142
&empty_tree_oid,
111143
&empty_blob_oid,
112144
},
145+
{
146+
"sha256",
147+
/* "s256", big-endian */
148+
0x73323536,
149+
GIT_SHA256_RAWSZ,
150+
GIT_SHA256_HEXSZ,
151+
GIT_SHA256_BLKSZ,
152+
git_hash_sha256_init,
153+
git_hash_sha256_update,
154+
git_hash_sha256_final,
155+
&empty_tree_oid_sha256,
156+
&empty_blob_oid_sha256,
157+
}
113158
};
114159

115160
const char *empty_tree_oid_hex(void)

sha256/block/sha256.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
#include "git-compat-util.h"
2+
#include "./sha256.h"
3+
4+
#undef RND
5+
#undef BLKSIZE
6+
7+
#define BLKSIZE blk_SHA256_BLKSIZE
8+
9+
void blk_SHA256_Init(blk_SHA256_CTX *ctx)
10+
{
11+
ctx->offset = 0;
12+
ctx->size = 0;
13+
ctx->state[0] = 0x6a09e667ul;
14+
ctx->state[1] = 0xbb67ae85ul;
15+
ctx->state[2] = 0x3c6ef372ul;
16+
ctx->state[3] = 0xa54ff53aul;
17+
ctx->state[4] = 0x510e527ful;
18+
ctx->state[5] = 0x9b05688cul;
19+
ctx->state[6] = 0x1f83d9abul;
20+
ctx->state[7] = 0x5be0cd19ul;
21+
}
22+
23+
static inline uint32_t ror(uint32_t x, unsigned n)
24+
{
25+
return (x >> n) | (x << (32 - n));
26+
}
27+
28+
static inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z)
29+
{
30+
return z ^ (x & (y ^ z));
31+
}
32+
33+
static inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
34+
{
35+
return ((x | y) & z) | (x & y);
36+
}
37+
38+
static inline uint32_t sigma0(uint32_t x)
39+
{
40+
return ror(x, 2) ^ ror(x, 13) ^ ror(x, 22);
41+
}
42+
43+
static inline uint32_t sigma1(uint32_t x)
44+
{
45+
return ror(x, 6) ^ ror(x, 11) ^ ror(x, 25);
46+
}
47+
48+
static inline uint32_t gamma0(uint32_t x)
49+
{
50+
return ror(x, 7) ^ ror(x, 18) ^ (x >> 3);
51+
}
52+
53+
static inline uint32_t gamma1(uint32_t x)
54+
{
55+
return ror(x, 17) ^ ror(x, 19) ^ (x >> 10);
56+
}
57+
58+
static void blk_SHA256_Transform(blk_SHA256_CTX *ctx, const unsigned char *buf)
59+
{
60+
61+
uint32_t S[8], W[64], t0, t1;
62+
int i;
63+
64+
/* copy state into S */
65+
for (i = 0; i < 8; i++)
66+
S[i] = ctx->state[i];
67+
68+
/* copy the state into 512-bits into W[0..15] */
69+
for (i = 0; i < 16; i++, buf += sizeof(uint32_t))
70+
W[i] = get_be32(buf);
71+
72+
/* fill W[16..63] */
73+
for (i = 16; i < 64; i++)
74+
W[i] = gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16];
75+
76+
#define RND(a,b,c,d,e,f,g,h,i,ki) \
77+
t0 = h + sigma1(e) + ch(e, f, g) + ki + W[i]; \
78+
t1 = sigma0(a) + maj(a, b, c); \
79+
d += t0; \
80+
h = t0 + t1;
81+
82+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
83+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
84+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
85+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
86+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
87+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
88+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
89+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
90+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
91+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
92+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
93+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
94+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
95+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
96+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
97+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
98+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
99+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
100+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
101+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
102+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
103+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
104+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
105+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
106+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
107+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
108+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
109+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
110+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
111+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
112+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
113+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
114+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
115+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
116+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
117+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
118+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
119+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
120+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
121+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
122+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
123+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
124+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
125+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
126+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
127+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
128+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
129+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
130+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
131+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
132+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
133+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
134+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
135+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
136+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
137+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
138+
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
139+
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
140+
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
141+
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
142+
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
143+
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
144+
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
145+
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
146+
147+
for (i = 0; i < 8; i++)
148+
ctx->state[i] += S[i];
149+
}
150+
151+
void blk_SHA256_Update(blk_SHA256_CTX *ctx, const void *data, size_t len)
152+
{
153+
unsigned int len_buf = ctx->size & 63;
154+
155+
ctx->size += len;
156+
157+
/* Read the data into buf and process blocks as they get full */
158+
if (len_buf) {
159+
unsigned int left = 64 - len_buf;
160+
if (len < left)
161+
left = len;
162+
memcpy(len_buf + ctx->buf, data, left);
163+
len_buf = (len_buf + left) & 63;
164+
len -= left;
165+
data = ((const char *)data + left);
166+
if (len_buf)
167+
return;
168+
blk_SHA256_Transform(ctx, ctx->buf);
169+
}
170+
while (len >= 64) {
171+
blk_SHA256_Transform(ctx, data);
172+
data = ((const char *)data + 64);
173+
len -= 64;
174+
}
175+
if (len)
176+
memcpy(ctx->buf, data, len);
177+
}
178+
179+
void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx)
180+
{
181+
static const unsigned char pad[64] = { 0x80 };
182+
unsigned int padlen[2];
183+
int i;
184+
185+
/* Pad with a binary 1 (ie 0x80), then zeroes, then length */
186+
padlen[0] = htonl((uint32_t)(ctx->size >> 29));
187+
padlen[1] = htonl((uint32_t)(ctx->size << 3));
188+
189+
i = ctx->size & 63;
190+
blk_SHA256_Update(ctx, pad, 1 + (63 & (55 - i)));
191+
blk_SHA256_Update(ctx, padlen, 8);
192+
193+
/* copy output */
194+
for (i = 0; i < 8; i++, digest += sizeof(uint32_t))
195+
put_be32(digest, ctx->state[i]);
196+
}

sha256/block/sha256.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef SHA256_BLOCK_SHA256_H
2+
#define SHA256_BLOCK_SHA256_H
3+
4+
#define blk_SHA256_BLKSIZE 64
5+
6+
struct blk_SHA256_CTX {
7+
uint32_t state[8];
8+
uint64_t size;
9+
uint32_t offset;
10+
uint8_t buf[blk_SHA256_BLKSIZE];
11+
};
12+
13+
typedef struct blk_SHA256_CTX blk_SHA256_CTX;
14+
15+
void blk_SHA256_Init(blk_SHA256_CTX *ctx);
16+
void blk_SHA256_Update(blk_SHA256_CTX *ctx, const void *data, size_t len);
17+
void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx);
18+
19+
#define platform_SHA256_CTX blk_SHA256_CTX
20+
#define platform_SHA256_Init blk_SHA256_Init
21+
#define platform_SHA256_Update blk_SHA256_Update
22+
#define platform_SHA256_Final blk_SHA256_Final
23+
24+
#endif

t/helper/test-sha256.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "test-tool.h"
2+
#include "cache.h"
3+
4+
int cmd__sha256(int ac, const char **av)
5+
{
6+
return cmd_hash_impl(ac, av, GIT_HASH_SHA256);
7+
}

t/helper/test-tool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static struct test_cmd cmds[] = {
4343
{ "scrap-cache-tree", cmd__scrap_cache_tree },
4444
{ "sha1", cmd__sha1 },
4545
{ "sha1-array", cmd__sha1_array },
46+
{ "sha256", cmd__sha256 },
4647
{ "sigchain", cmd__sigchain },
4748
{ "strcmp-offset", cmd__strcmp_offset },
4849
{ "string-list", cmd__string_list },

0 commit comments

Comments
 (0)