1From 4f6c794c471789bed5e078bb0330ff08bb5936ac Mon Sep 17 00:00:00 2001
2From: Michael Forney <mforney@mforney.org>
3Date: Fri, 15 May 2026 02:59:18 -0700
4Subject: [PATCH] Add br_sha512_256
5
6---
7 inc/bearssl_hash.h | 132 +++++++++++++++++++++++++++++++++++++++++----
8 src/hash/sha2big.c | 42 +++++++++++++++
9 2 files changed, 164 insertions(+), 10 deletions(-)
10
11diff --git a/inc/bearssl_hash.h b/inc/bearssl_hash.h
12index ca4fa26..769e7ac 100644
13--- a/inc/bearssl_hash.h
14+++ b/inc/bearssl_hash.h
15@@ -156,15 +156,16 @@ extern "C" {
16 *
17 * Implemented hash functions are:
18 *
19- * | Function | Name | Output length | State length |
20- * | :-------- | :------ | :-----------: | :----------: |
21- * | MD5 | md5 | 16 | 16 |
22- * | SHA-1 | sha1 | 20 | 20 |
23- * | SHA-224 | sha224 | 28 | 32 |
24- * | SHA-256 | sha256 | 32 | 32 |
25- * | SHA-384 | sha384 | 48 | 64 |
26- * | SHA-512 | sha512 | 64 | 64 |
27- * | MD5+SHA-1 | md5sha1 | 36 | 36 |
28+ * | Function | Name | Output length | State length |
29+ * | :---------- | :--------- | :-----------: | :----------: |
30+ * | MD5 | md5 | 16 | 16 |
31+ * | SHA-1 | sha1 | 20 | 20 |
32+ * | SHA-224 | sha224 | 28 | 32 |
33+ * | SHA-256 | sha256 | 32 | 32 |
34+ * | SHA-384 | sha384 | 48 | 64 |
35+ * | SHA-512 | sha512 | 64 | 64 |
36+ * | SHA-512/256 | sha512_256 | 32 | 64 |
37+ * | MD5+SHA-1 | md5sha1 | 36 | 36 |
38 *
39 * (MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the
40 * same input; in the implementation, the internal data buffer is
41@@ -359,7 +360,7 @@ struct br_hash_class_ {
42 * -- First field is called 'vtable' and is a pointer to a
43 * const-qualified br_hash_class instance (pointer is set by init()).
44 * -- SHA-224 and SHA-256 contexts are identical.
45- * -- SHA-384 and SHA-512 contexts are identical.
46+ * -- SHA-384, SHA-512, and SHA-512/256 contexts are identical.
47 *
48 * Thus, contexts can be moved and cloned to capture the hash function
49 * current state; and there is no need for any explicit "release" function.
50@@ -961,6 +962,117 @@ void br_sha512_set_state(br_sha512_context *ctx,
51 #define br_sha512_set_state br_sha384_set_state
52 #endif
53
54+/**
55+ * \brief Symbolic identifier for SHA-512/256.
56+ *
57+ * SHA-512/256 is the truncation of SHA-512 to 32 bytes with a
58+ * special IV. It is not one of the functions identified in TLS,
59+ * so we give it a symbolic identifier of value 0.
60+ */
61+#define br_sha512_256_ID 0
62+
63+/**
64+ * \brief SHA-512 output size (in bytes).
65+ */
66+#define br_sha512_256_SIZE 32
67+
68+/**
69+ * \brief Constant vtable for SHA-512/256.
70+ */
71+extern const br_hash_class br_sha512_256_vtable;
72+
73+#ifdef BR_DOXYGEN_IGNORE
74+/**
75+ * \brief SHA-512/256 context.
76+ *
77+ * First field is a pointer to the vtable; it is set by the initialisation
78+ * function. Other fields are not supposed to be accessed by user code.
79+ */
80+typedef struct {
81+ /**
82+ * \brief Pointer to vtable for this context.
83+ */
84+ const br_hash_class *vtable;
85+} br_sha512_256_context;
86+#else
87+typedef br_sha384_context br_sha512_256_context;
88+#endif
89+
90+/**
91+ * \brief SHA-512/256 context initialisation.
92+ *
93+ * This function initialises or resets a context for a new SHA-512/256
94+ * computation. It also sets the vtable pointer.
95+ *
96+ * \param ctx pointer to the context structure.
97+ */
98+void br_sha512_256_init(br_sha512_256_context *ctx);
99+
100+#ifdef BR_DOXYGEN_IGNORE
101+/**
102+ * \brief Inject some data bytes in a running SHA-512/256 computation.
103+ *
104+ * The provided context is updated with some data bytes. If the number
105+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
106+ * and may be `NULL`, and this function does nothing.
107+ *
108+ * \param ctx pointer to the context structure.
109+ * \param data pointer to the injected data.
110+ * \param len injected data length (in bytes).
111+ */
112+void br_sha512_256_update(br_sha512_256_context *ctx, const void *data, size_t len);
113+#else
114+#define br_sha512_256_update br_sha384_update
115+#endif
116+
117+/**
118+ * \brief Compute SHA-512/256 output.
119+ *
120+ * The SHA-512/256 output for the concatenation of all bytes injected
121+ * in the provided context since the last initialisation or reset
122+ * call, is computed and written in the buffer pointed to by `out`.
123+ * The context itself is not modified, so extra bytes may be injected
124+ * afterwards to continue that computation.
125+ *
126+ * \param ctx pointer to the context structure.
127+ * \param out destination buffer for the hash output.
128+ */
129+void br_sha512_256_out(const br_sha512_256_context *ctx, void *out);
130+
131+#ifdef BR_DOXYGEN_IGNORE
132+/**
133+ * \brief Save SHA-512/256 running state.
134+ *
135+ * The running state for SHA-512/256 (output of the last internal
136+ * block processing) is written in the buffer pointed to by `out`.
137+ * The number of bytes injected since the last initialisation or
138+ * reset call is returned. The context is not modified.
139+ *
140+ * \param ctx pointer to the context structure.
141+ * \param out destination buffer for the running state.
142+ * \return the injected total byte length.
143+ */
144+uint64_t br_sha512_256_state(const br_sha512_256_context *ctx, void *out);
145+#else
146+#define br_sha512_256_state br_sha384_state
147+#endif
148+
149+#ifdef BR_DOXYGEN_IGNORE
150+/**
151+ * \brief Restore SHA-512/256 running state.
152+ *
153+ * The running state for SHA-512/256 is set to the provided values.
154+ *
155+ * \param ctx pointer to the context structure.
156+ * \param stb source buffer for the running state.
157+ * \param count the injected total byte length.
158+ */
159+void br_sha512_256_set_state(br_sha512_256_context *ctx,
160+ const void *stb, uint64_t count);
161+#else
162+#define br_sha512_256_set_state br_sha384_set_state
163+#endif
164+
165 /*
166 * "md5sha1" is a special hash function that computes both MD5 and SHA-1
167 * on the same input, and produces a 36-byte output (MD5 and SHA-1
168diff --git a/src/hash/sha2big.c b/src/hash/sha2big.c
169index 5be92ed..a8b930c 100644
170--- a/src/hash/sha2big.c
171+++ b/src/hash/sha2big.c
172@@ -48,6 +48,13 @@ static const uint64_t IV512[8] = {
173 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
174 };
175
176+static const uint64_t IV512_256[8] = {
177+ 0x22312194FC2BF72C, 0x9F555FA3C84C64C2,
178+ 0x2393B86B6F53B151, 0x963877195940EABD,
179+ 0x96283EE2A88EFFE3, 0xBE5E1E2553863992,
180+ 0x2B0199FC2C85B8AA, 0x0EB72DDC81C52CA2
181+};
182+
183 static const uint64_t K[80] = {
184 0x428A2F98D728AE22, 0x7137449123EF65CD,
185 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
186@@ -246,6 +253,22 @@ br_sha512_out(const br_sha512_context *cc, void *dst)
187 sha2big_out(cc, dst, 8);
188 }
189
190+/* see bearssl.h */
191+void
192+br_sha512_256_init(br_sha512_context *cc)
193+{
194+ cc->vtable = &br_sha512_256_vtable;
195+ memcpy(cc->val, IV512_256, sizeof IV512_256);
196+ cc->count = 0;
197+}
198+
199+/* see bearssl.h */
200+void
201+br_sha512_256_out(const br_sha512_context *cc, void *dst)
202+{
203+ sha2big_out(cc, dst, 4);
204+}
205+
206 /* see bearssl.h */
207 const br_hash_class br_sha384_vtable = {
208 sizeof(br_sha384_context),
209@@ -283,3 +306,22 @@ const br_hash_class br_sha512_vtable = {
210 (void (*)(const br_hash_class **, const void *, uint64_t))
211 &br_sha512_set_state
212 };
213+
214+/* see bearssl.h */
215+const br_hash_class br_sha512_256_vtable = {
216+ sizeof(br_sha512_256_context),
217+ BR_HASHDESC_ID(br_sha512_ID)
218+ | BR_HASHDESC_OUT(32)
219+ | BR_HASHDESC_STATE(64)
220+ | BR_HASHDESC_LBLEN(7)
221+ | BR_HASHDESC_MD_PADDING
222+ | BR_HASHDESC_MD_PADDING_BE
223+ | BR_HASHDESC_MD_PADDING_128,
224+ (void (*)(const br_hash_class **))&br_sha512_256_init,
225+ (void (*)(const br_hash_class **, const void *, size_t))
226+ &br_sha512_256_update,
227+ (void (*)(const br_hash_class *const *, void *))&br_sha512_256_out,
228+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha512_256_state,
229+ (void (*)(const br_hash_class **, const void *, uint64_t))
230+ &br_sha512_256_set_state
231+};
232--
2332.54.0
234