TARFS 0.1.5
Read-only TAR filesystem for ESP32
Loading...
Searching...
No Matches
hash.c
Go to the documentation of this file.
1/*
2 * TARFS - Immutable (read-only) filesystem for embedded systems.
3 *
4 * Copyright (c) 2026 Viacheslav Logunov
5 * SPDX-License-Identifier: MMIT
6 *
7 * Author:
8 * Viacheslav Logunov <vvb333007@gmail.com>
9 *
10 * Project:
11 * https://github.com/vvb333007/tarfs
12 */
13
14
24
25#include <stdint.h>
26#include <stddef.h>
27
28#include "config.h"
29#include "hash.h"
30
31
32#define HASH32_PRIME (uint32_t)(16777619u) /* Special prime number */
33
40#define HASH32_PSTEP(hash_, pb_) do { \
41 (hash_) ^= *(const uint8_t *)(pb_++); \
42 (hash_) *= HASH32_PRIME; \
43} while(0)
44
49#define HASH32_CSTEP(hash_, b_) do { \
50 (hash_) ^= (uint8_t)(b_); \
51 (hash_) *= HASH32_PRIME; \
52} while( 0 )
53
54
55// !! WARNING This macro contains a `return` statement !!
56//
57#define HASH32_RETURN_IF_DONE do { if (--len == 0) return hash; } while(0)
58
59
60
61
79uint32_t hash32(uint32_t prev_hash, const uint8_t *data, size_t len) {
80
81 const uint32_t *wdata; /* Pointer to an aligned 32-bit accessible portion of the data */
82 size_t nwords; /* Number of 32-bit chunks */
83 uint32_t hash; /* Resulting hash */
84 uintptr_t addr;
85
86 /* Empty input does not change our hash value */
87 if (len == 0)
88 return prev_hash;
89
90 hash = prev_hash;
91 addr = (uintptr_t )data;
92
93 if (addr & 1) {
94 HASH32_PSTEP(hash, data); // advance data pointer
96 }
97
98 if (addr & 2) {
99
100 HASH32_PSTEP(hash, data); // advance data pointer
102
103 HASH32_PSTEP(hash, data); // advance data pointer
105 }
106
107 /* At this point we still have data to hash and our data address is 4 bytes aligned
108 * Unrolled version which accesses memory once, reading 4 bytes. Original version does byte-by-byte accesses
109 *
110 */
111 wdata = (const uint32_t *)data; /* do we break aliasing rules here? gcc is quiet */
112 nwords = len >> 2; /* number of 32 bit words to hash */
113
114 len &= 3; /* len now indicates trailing bytes count [0..3] */
115
116 while (nwords > 0) {
117
118 uint32_t v = *wdata++;
119
120#if CONFIG_TARFS_BIG_ENDIAN
121 HASH32_CSTEP(hash, v >> 24); // advance data pointer
122 HASH32_CSTEP(hash, v >> 16);
123 HASH32_CSTEP(hash, v >> 8);
124 HASH32_CSTEP(hash, v);
125#else
126 HASH32_CSTEP(hash, v); // advance data pointer
127 HASH32_CSTEP(hash, v >> 8);
128 HASH32_CSTEP(hash, v >> 16);
129 HASH32_CSTEP(hash, v >> 24);
130#endif
131
132 nwords--;
133 }
134
135 /* There may be 1..3 bytes left after fast-path block. Use the same idea
136 * as used in source address alignment procedure, but inverse it
137 *
138 */
139 data = (const uint8_t *)wdata;
140
141 if (len & 2) {
142 HASH32_PSTEP(hash, data); // advance data pointer
143 HASH32_PSTEP(hash, data);
144 }
145
146 if (len & 1) {
147 HASH32_PSTEP(hash, data); // advance data pointer
148 }
149
150 return hash;
151}
152
153
154
155
163uint64_t hash64(uint64_t prev_crc, void const *buffer0, size_t buf_len) {
164
165 uint64_t crc = prev_crc;
166 uint8_t const *buffer = buffer0;
167
168 while (buf_len--) {
169
170 crc ^= (uint64_t)*buffer++ << 56;
171
172 for (int i = 0; i < 8; i++) {
173 if (crc & 0x8000000000000000ULL)
174 crc = (crc << 1) ^ 0x42F0E1EBA9EA3693ULL;
175 else
176 crc <<= 1;
177 }
178 }
179
180 return crc;
181}
#define HASH32_CSTEP(hash_, b_)
Same as the above but second arg is the value, not pointer.
Definition hash.c:49
uint64_t hash64(uint64_t prev_crc, void const *buffer0, size_t buf_len)
CRC-64/ECMA-182 algoritm.
Definition hash.c:163
#define HASH32_RETURN_IF_DONE
Definition hash.c:57
#define HASH32_PSTEP(hash_, pb_)
Process one byte from pointer (pointer is incremented).
Definition hash.c:40
uint32_t hash32(uint32_t prev_hash, const uint8_t *data, size_t len)
Compute FNV-1a hash over a byte buffer.
Definition hash.c:79