0% found this document useful (0 votes)
16 views

256-Hash Function

Hash functions
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views

256-Hash Function

Hash functions
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

Step-by-Step Breakdown of the Code

This code consists of several hash functions, including a simple one (djb2), a slightly more
complex one (FNV-1a), and the cryptographically secure SHA-256 implementation. I'll go
through each section in detail:

1. djb2_hash Function

This is a simple hash function developed by Daniel J. Bernstein. The purpose of this function
is to take a string and return a 32-bit hash.

c
Copy code
unsigned long djb2_hash(const unsigned char *str) {
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}

• Initial value (5381): The hash variable starts with a constant seed value of 5381,
which is empirically chosen for its performance and distribution characteristics.
• Loop through each character (while ((c = *str++)): The string is processed
character by character, updating the hash.
• Hash computation (hash * 33 + c): The hash is updated by multiplying it by 33
and adding the current character (c). The bit-shifting (hash << 5) is a faster way of
doing multiplication by 32.

2. fnv1a_hash Function

FNV-1a is a non-cryptographic hash function that processes arbitrary data, such as byte
arrays. It uses a combination of XOR and multiplication for good distribution.

c
Copy code
#define FNV_PRIME 0x100000001b3
#define FNV_OFFSET 0xcbf29ce484222325

uint64_t fnv1a_hash(const unsigned char *data, size_t len) {


uint64_t hash = FNV_OFFSET;
for (size_t i = 0; i < len; i++) {
hash ^= data[i]; // XOR with the current byte
hash *= FNV_PRIME; // Multiply by a large prime number
}
return hash;
}

• FNV_OFFSET: A large constant that serves as the initial hash value.


• FNV_PRIME: A prime number used in the multiplication step to ensure a good
distribution of the hash values.
• XOR with each byte: The current byte is XOR'd into the hash value (hash ^=
data[i]), mixing the input into the hash.
• Multiply by prime: After each XOR, the hash is multiplied by a prime to further
randomize the bits.

3. SHA-256 Implementation

This section implements the cryptographic hash function SHA-256. It is more complex and
follows the official specification with careful bitwise operations to achieve security.

a. Constants and Macros

SHA-256 relies heavily on bitwise operations and logical functions. These macros simplify
the implementation:

c
Copy code
#define ROTRIGHT(word,bits) (((word) >> (bits)) | ((word) << (32-(bits))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))

• ROTRIGHT: Performs a circular right bit-shift.


• CH and MAJ: Logical functions specific to SHA-256 for mixing bits of input.
• EP0, EP1, SIG0, and SIG1: Functions for rotating and shifting bits, as specified in the
SHA-256 algorithm.

b. SHA256_CTX Structure

This structure maintains the state of the SHA-256 computation across different stages:

c
Copy code
typedef struct {
uint8_t data[64]; // Data buffer (512 bits)
uint32_t datalen; // Length of the current data
uint64_t bitlen; // Total number of bits processed
uint32_t state[8]; // Intermediate hash value (256 bits)
} SHA256_CTX;

• data: A buffer to hold blocks of 512 bits (64 bytes) for processing.
• datalen: Keeps track of how much data is currently in the buffer.
• bitlen: A counter for the total number of bits processed so far.
• state: An array of 8 integers (each 32 bits) that holds the current intermediate hash
value.

c. sha256_transform Function
This function processes a 512-bit chunk of data (64 bytes) and updates the hash state:

c
Copy code
void sha256_transform(SHA256_CTX *ctx, const uint8_t data[]) {
// ... (complex operations on the state)
}

• Input scheduling: First, the input is expanded from 16 32-bit words to 64 words
using the SIG0 and SIG1 functions.
• Main loop: The core of the function is a loop that processes each of the 64 rounds of
the SHA-256 algorithm. In each round, the state is updated using logical functions
like CH, MAJ, EP0, and EP1.
• Final state update: After processing the block, the state is updated by adding the
values computed in the loop to the current state.

d. sha256_init Function

This initializes the SHA-256 context with predefined initial hash values:

c
Copy code
void sha256_init(SHA256_CTX *ctx) {
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}

• These constants are defined in the SHA-256 standard as the initial hash values.

e. sha256_update Function

This processes the input data in chunks of 512 bits (64 bytes). If the data buffer is full, the
function calls sha256_transform to process it.

c
Copy code
void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len) {
// Handles filling the buffer and calling sha256_transform when full
}

f. sha256_final Function

This function pads the final block of data and processes any remaining bytes to finalize the
hash.

c
Copy code
void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) {
// Padding and final transformation
}

• Padding: Ensures the data is padded to the correct length according to SHA-256
specifications, adding a 1 bit followed by enough zeros to fill out the block.
• Final hash value: The final 256-bit hash is written to the hash[] array.

4. main Function

This demonstrates the usage of the three hash functions:

c
Copy code
int main() {
const char *input = "Hello, PhD candidate!";

// djb2 hash
printf("djb2 hash: %lu\n", djb2_hash((const unsigned char *)input));

// FNV-1a hash
printf("FNV-1a hash: %llu\n", fnv1a_hash((const unsigned char *)input,
strlen(input)));

// SHA-256 hash
SHA256_CTX ctx;
uint8_t hash[SHA256_BLOCK_SIZE];
sha256_init(&ctx);
sha256_update(&ctx, (const uint8_t *)input, strlen(input));
sha256_final(&ctx, hash);

printf("SHA-256 hash: ");


for (int i = 0; i < SHA256_BLOCK_SIZE; i++) {
printf("%02x", hash[i]);
}
printf("\n");

return 0;
}

• Input: The string "Hello, PhD candidate!" is hashed using each function.
• djb2: Simple, fast hash function.
• FNV-1a: Slightly more complex but still non-cryptographic.
• SHA-256: Secure, cryptographic hash function providing a 256-bit result.

Conclusion

This code provides an excellent demonstration of different types of hash functions, from
simple to cryptographically secure. Each function has its purpose, and the SHA-256
implementation illustrates a complete cryptographic hash function designed for security.

You might also like