PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
checksum.c
Go to the documentation of this file.
1/**
2 * @file checksum.c
3 * @brief Dependency-free SHA-256 implementation used for small persistent metadata.
4 */
5
6#include "checksum.h"
7
8#include <stdio.h>
9
10#define ROTATE_RIGHT(value, bits) (((value) >> (bits)) | ((value) << (32u - (bits))))
11
12static const uint32_t kRoundConstants[64] = {
13 0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, 0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
14 0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u, 0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
15 0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu, 0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
16 0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u, 0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
17 0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u, 0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
18 0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u, 0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
19 0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u, 0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
20 0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u, 0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u
21};
22
23/** @brief Transform one complete 64-byte SHA-256 block. */
24static void PicurvSHA256Transform(PicurvSHA256Context *context, const unsigned char block[64])
25{
26 uint32_t words[64];
27 uint32_t a, b, c, d, e, f, g, h;
28
29 for (size_t index = 0; index < 16; ++index) {
30 const size_t offset = 4 * index;
31 words[index] = ((uint32_t)block[offset] << 24) |
32 ((uint32_t)block[offset + 1] << 16) |
33 ((uint32_t)block[offset + 2] << 8) |
34 (uint32_t)block[offset + 3];
35 }
36 for (size_t index = 16; index < 64; ++index) {
37 const uint32_t s0 = ROTATE_RIGHT(words[index - 15], 7) ^ ROTATE_RIGHT(words[index - 15], 18) ^ (words[index - 15] >> 3);
38 const uint32_t s1 = ROTATE_RIGHT(words[index - 2], 17) ^ ROTATE_RIGHT(words[index - 2], 19) ^ (words[index - 2] >> 10);
39 words[index] = words[index - 16] + s0 + words[index - 7] + s1;
40 }
41
42 a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3];
43 e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7];
44
45 for (size_t index = 0; index < 64; ++index) {
46 const uint32_t sum1 = ROTATE_RIGHT(e, 6) ^ ROTATE_RIGHT(e, 11) ^ ROTATE_RIGHT(e, 25);
47 const uint32_t choose = (e & f) ^ ((~e) & g);
48 const uint32_t temp1 = h + sum1 + choose + kRoundConstants[index] + words[index];
49 const uint32_t sum0 = ROTATE_RIGHT(a, 2) ^ ROTATE_RIGHT(a, 13) ^ ROTATE_RIGHT(a, 22);
50 const uint32_t majority = (a & b) ^ (a & c) ^ (b & c);
51 const uint32_t temp2 = sum0 + majority;
52
53 h = g; g = f; f = e; e = d + temp1;
54 d = c; c = b; b = a; a = temp1 + temp2;
55 }
56
57 context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d;
58 context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h;
59}
60
61/** @brief Implementation of \ref PicurvSHA256Init(). */
63{
64 if (!context) return;
65 context->state[0] = 0x6a09e667u; context->state[1] = 0xbb67ae85u;
66 context->state[2] = 0x3c6ef372u; context->state[3] = 0xa54ff53au;
67 context->state[4] = 0x510e527fu; context->state[5] = 0x9b05688cu;
68 context->state[6] = 0x1f83d9abu; context->state[7] = 0x5be0cd19u;
69 context->bit_count = 0;
70 context->buffer_size = 0;
71}
72
73/** @brief Implementation of \ref PicurvSHA256Update(). */
74void PicurvSHA256Update(PicurvSHA256Context *context, const void *data, size_t length)
75{
76 const unsigned char *bytes = (const unsigned char *)data;
77
78 if (!context || (!bytes && length > 0)) return;
79 context->bit_count += (uint64_t)length * 8u;
80
81 while (length > 0) {
82 const size_t room = 64 - context->buffer_size;
83 const size_t take = length < room ? length : room;
84 for (size_t index = 0; index < take; ++index) {
85 context->buffer[context->buffer_size + index] = bytes[index];
86 }
87 context->buffer_size += take;
88 bytes += take;
89 length -= take;
90 if (context->buffer_size == 64) {
91 PicurvSHA256Transform(context, context->buffer);
92 context->buffer_size = 0;
93 }
94 }
95}
96
97/** @brief Implementation of \ref PicurvSHA256FinalHex(). */
98void PicurvSHA256FinalHex(PicurvSHA256Context *context, char digest_hex[65])
99{
100 static const char hex[] = "0123456789abcdef";
101 unsigned char digest[32];
102 const uint64_t message_bits = context ? context->bit_count : 0;
103 unsigned char padding[128] = {0x80};
104 size_t padding_length;
105
106 if (!context || !digest_hex) return;
107 padding_length = context->buffer_size < 56 ? 56 - context->buffer_size : 120 - context->buffer_size;
108 PicurvSHA256Update(context, padding, padding_length);
109 context->bit_count = message_bits;
110
111 for (size_t index = 0; index < 8; ++index) {
112 context->buffer[56 + index] = (unsigned char)(message_bits >> (56 - 8 * index));
113 }
114 PicurvSHA256Transform(context, context->buffer);
115
116 for (size_t index = 0; index < 8; ++index) {
117 digest[4 * index] = (unsigned char)(context->state[index] >> 24);
118 digest[4 * index + 1] = (unsigned char)(context->state[index] >> 16);
119 digest[4 * index + 2] = (unsigned char)(context->state[index] >> 8);
120 digest[4 * index + 3] = (unsigned char)context->state[index];
121 }
122 for (size_t index = 0; index < sizeof(digest); ++index) {
123 digest_hex[2 * index] = hex[digest[index] >> 4];
124 digest_hex[2 * index + 1] = hex[digest[index] & 0x0f];
125 }
126 digest_hex[64] = '\0';
127}
128
129/** @brief Implementation of \ref PicurvSHA256File(). */
130PetscErrorCode PicurvSHA256File(const char *path, char digest_hex[65])
131{
132 FILE *file = NULL;
133 unsigned char buffer[8192];
134 PicurvSHA256Context context;
135
136 PetscFunctionBeginUser;
137 PetscCheck(path != NULL && digest_hex != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
138 "SHA-256 file path and digest output are required.");
139 file = fopen(path, "rb");
140 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
141 "Unable to open '%s' while computing SHA-256.", path);
142
143 PicurvSHA256Init(&context);
144 while (!feof(file)) {
145 const size_t count = fread(buffer, 1, sizeof(buffer), file);
146 if (count > 0) PicurvSHA256Update(&context, buffer, count);
147 PetscCheck(!ferror(file), PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
148 "Unable to read '%s' while computing SHA-256.", path);
149 }
150 PetscCheck(fclose(file) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
151 "Unable to close '%s' after computing SHA-256.", path);
152 PicurvSHA256FinalHex(&context, digest_hex);
153 PetscFunctionReturn(0);
154}
155
156#undef ROTATE_RIGHT
PetscErrorCode PicurvSHA256File(const char *path, char digest_hex[65])
Implementation of PicurvSHA256File().
Definition checksum.c:130
void PicurvSHA256Init(PicurvSHA256Context *context)
Implementation of PicurvSHA256Init().
Definition checksum.c:62
void PicurvSHA256Update(PicurvSHA256Context *context, const void *data, size_t length)
Implementation of PicurvSHA256Update().
Definition checksum.c:74
static void PicurvSHA256Transform(PicurvSHA256Context *context, const unsigned char block[64])
Transform one complete 64-byte SHA-256 block.
Definition checksum.c:24
void PicurvSHA256FinalHex(PicurvSHA256Context *context, char digest_hex[65])
Implementation of PicurvSHA256FinalHex().
Definition checksum.c:98
#define ROTATE_RIGHT(value, bits)
Definition checksum.c:10
static const uint32_t kRoundConstants[64]
Definition checksum.c:12
Small dependency-free SHA-256 utility for persistent metadata identity.
uint32_t state[8]
Definition checksum.h:15
unsigned char buffer[64]
Definition checksum.h:17
uint64_t bit_count
Definition checksum.h:16
Incremental SHA-256 state.
Definition checksum.h:14