Skip to content

Commit 8746600

Browse files
Merge #1093: hash: Make code agnostic of endianness
37d3692 tests: Add tests for _read_be32 and _write_be32 (Tim Ruffing) 616b43d util: Remove endianness detection (Tim Ruffing) 8d89b9e hash: Make code agnostic of endianness (Tim Ruffing) Pull request description: Recent compilers compile the two new functions to very efficient code on various platforms. In particular, already GCC >= 5 and clang >= 5 understand do this for the read function, which is the one critical for performance (called 16 times per SHA256 transform). Fixes #1080. ACKs for top commit: sipa: utACK 37d3692 robot-dreams: ACK 37d3692 Tree-SHA512: b03cec67756fb3c94ca8e7e06f974136050efd5065f392dba6eed4d0dbe61dbf93dad054627267225bac1bb302bb025f86588612ef7d4beeb834466686c70b8f
2 parents 912b7cc + 37d3692 commit 8746600

File tree

4 files changed

+55
-59
lines changed

4 files changed

+55
-59
lines changed

src/hash.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
typedef struct {
1414
uint32_t s[8];
15-
uint32_t buf[16]; /* In big endian */
15+
unsigned char buf[64];
1616
uint64_t bytes;
1717
} secp256k1_sha256;
1818

src/hash_impl.h

+24-33
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@
2828
(h) = t1 + t2; \
2929
} while(0)
3030

31-
#if defined(SECP256K1_BIG_ENDIAN)
32-
#define BE32(x) (x)
33-
#elif defined(SECP256K1_LITTLE_ENDIAN)
34-
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
35-
#endif
36-
3731
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
3832
hash->s[0] = 0x6a09e667ul;
3933
hash->s[1] = 0xbb67ae85ul;
@@ -47,26 +41,26 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
4741
}
4842

4943
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
50-
static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
44+
static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
5145
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
5246
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
5347

54-
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));
55-
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
56-
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
57-
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
58-
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
59-
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
60-
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
61-
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
62-
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
63-
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
64-
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
65-
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
66-
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
67-
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
68-
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
69-
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
48+
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0]));
49+
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4]));
50+
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8]));
51+
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12]));
52+
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16]));
53+
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20]));
54+
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24]));
55+
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28]));
56+
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32]));
57+
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36]));
58+
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40]));
59+
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44]));
60+
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48]));
61+
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52]));
62+
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56]));
63+
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60]));
7064

7165
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
7266
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
@@ -136,7 +130,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
136130
while (len >= 64 - bufsize) {
137131
/* Fill the buffer, and process it. */
138132
size_t chunk_len = 64 - bufsize;
139-
memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
133+
memcpy(hash->buf + bufsize, data, chunk_len);
140134
data += chunk_len;
141135
len -= chunk_len;
142136
secp256k1_sha256_transform(hash->s, hash->buf);
@@ -150,20 +144,18 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
150144

151145
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
152146
static const unsigned char pad[64] = {0x80};
153-
uint32_t sizedesc[2];
154-
uint32_t out[8];
155-
int i = 0;
147+
unsigned char sizedesc[8];
148+
int i;
156149
/* The maximum message size of SHA256 is 2^64-1 bits. */
157150
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
158-
sizedesc[0] = BE32(hash->bytes >> 29);
159-
sizedesc[1] = BE32(hash->bytes << 3);
151+
secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
152+
secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
160153
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
161-
secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);
154+
secp256k1_sha256_write(hash, sizedesc, 8);
162155
for (i = 0; i < 8; i++) {
163-
out[i] = BE32(hash->s[i]);
156+
secp256k1_write_be32(&out32[4*i], hash->s[i]);
164157
hash->s[i] = 0;
165158
}
166-
memcpy(out32, (const unsigned char*)out, 32);
167159
}
168160

169161
/* Initializes a sha256 struct and writes the 64 byte string
@@ -287,7 +279,6 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
287279
rng->retry = 0;
288280
}
289281

290-
#undef BE32
291282
#undef Round
292283
#undef sigma1
293284
#undef sigma0

src/tests.c

+14
Original file line numberDiff line numberDiff line change
@@ -6887,6 +6887,19 @@ void run_secp256k1_memczero_test(void) {
68876887
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
68886888
}
68896889

6890+
void run_secp256k1_byteorder_tests(void) {
6891+
const uint32_t x = 0xFF03AB45;
6892+
const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
6893+
unsigned char buf[4];
6894+
uint32_t x_;
6895+
6896+
secp256k1_write_be32(buf, x);
6897+
CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
6898+
6899+
x_ = secp256k1_read_be32(buf);
6900+
CHECK(x == x_);
6901+
}
6902+
68906903
void int_cmov_test(void) {
68916904
int r = INT_MAX;
68926905
int a = 0;
@@ -7161,6 +7174,7 @@ int main(int argc, char **argv) {
71617174

71627175
/* util tests */
71637176
run_secp256k1_memczero_test();
7177+
run_secp256k1_byteorder_tests();
71647178

71657179
run_cmov_tests();
71667180

src/util.h

+16-25
Original file line numberDiff line numberDiff line change
@@ -173,31 +173,6 @@ static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void
173173
# define SECP256K1_GNUC_EXT
174174
#endif
175175

176-
/* If SECP256K1_{LITTLE,BIG}_ENDIAN is not explicitly provided, infer from various other system macros. */
177-
#if !defined(SECP256K1_LITTLE_ENDIAN) && !defined(SECP256K1_BIG_ENDIAN)
178-
/* Inspired by https://github.com/rofl0r/endianness.h/blob/9853923246b065a3b52d2c43835f3819a62c7199/endianness.h#L52L73 */
179-
# if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
180-
defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \
181-
defined(__i486__) || defined(__i586__) || defined(__i686__) || \
182-
defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \
183-
defined(__ARMEL__) || defined(__AARCH64EL__) || \
184-
(defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
185-
(defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \
186-
defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) /* MSVC */
187-
# define SECP256K1_LITTLE_ENDIAN
188-
# endif
189-
# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
190-
defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \
191-
defined(__MICROBLAZEEB__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \
192-
(defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
193-
(defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1)
194-
# define SECP256K1_BIG_ENDIAN
195-
# endif
196-
#endif
197-
#if defined(SECP256K1_LITTLE_ENDIAN) == defined(SECP256K1_BIG_ENDIAN)
198-
# error Please make sure that either SECP256K1_LITTLE_ENDIAN or SECP256K1_BIG_ENDIAN is set, see src/util.h.
199-
#endif
200-
201176
/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */
202177
static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) {
203178
unsigned char *p = (unsigned char *)s;
@@ -338,4 +313,20 @@ static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) {
338313
#endif
339314
}
340315

316+
/* Read a uint32_t in big endian */
317+
SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) {
318+
return (uint32_t)p[0] << 24 |
319+
(uint32_t)p[1] << 16 |
320+
(uint32_t)p[2] << 8 |
321+
(uint32_t)p[3];
322+
}
323+
324+
/* Write a uint32_t in big endian */
325+
SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) {
326+
p[3] = x;
327+
p[2] = x >> 8;
328+
p[1] = x >> 16;
329+
p[0] = x >> 24;
330+
}
331+
341332
#endif /* SECP256K1_UTIL_H */

0 commit comments

Comments
 (0)