Skip to content

MrMsnawi/SHA-256

Repository files navigation

sha256

A from-scratch implementation of the SHA-256 hash function in C++, written directly against the NIST FIPS 180-4 specification. No external crypto libraries — just the algorithm as defined in the standard.

The implementation is header-only: drop sha256.hpp into your project and you're done.

Features

  • Single-header, zero-dependency (standard library only)
  • Faithful to FIPS 180-4: message padding, schedule expansion, and the 64-round compression function
  • Validated against the official NIST test vectors
  • A small CLI for hashing files, plus a test runner

Requirements

  • A C++17 compiler (the Makefile uses g++)
  • make

Build

make          # build the CLI -> ./sha256
make test     # build the test runner -> ./test
make clean    # remove built binaries
make re       # clean + rebuild the CLI

The build uses -std=c++17 -Wall -Wextra.

Usage

Command line

The CLI reads a file and prints its digest alongside the filename, in the same <hash> <file> style as sha256sum:

$ ./sha256 main.cpp
3a1f...c9e2  main.cpp

It exits with a non-zero status and an error message if no file is given or the file can't be opened.

As a library

Include the header and call the static hash function with the data you want to digest. It returns the digest as a 64-character lowercase hex string:

#include "sha256.hpp"
#include <iostream>

int main() {
    std::cout << sha256::hash("abc") << "\n";
    // ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
}

Testing

test.cpp checks the implementation against NIST test vectors (the empty string, "abc", the 448-bit two-block message, and the pangram with and without a trailing period). Build and run it:

make test
./test

Each case reports [PASS] or [FAIL], followed by a summary. The runner exits 0 only if every vector passes.

Project structure

sha256/
├── sha256.hpp    			# the implementation (header-only)
├── main.cpp      			# CLI: hash a file
├── test.cpp      			# NIST test vectors
├── Makefile      			# build targets
├── knowledge.md  			# study notes on the algorithm
├── NIST.FIPS.180-4.pdf		# the standard
├── README.md
└── LICENSE

How it works

SHA-256 processes the message in 512-bit blocks and produces a 256-bit digest. The implementation follows the spec stage by stage:

  1. Padding — append a 1 bit, then 0 bits, then the original message length as a 64-bit big-endian integer, so the total is a multiple of 512 bits.
  2. Parsing — split the padded message into 512-bit blocks, each read as sixteen 32-bit big-endian words.
  3. Message schedule — expand the 16 words of each block into 64 using the lower sigma functions.
  4. Compression — run 64 rounds over the eight working variables with the round constants K, the Ch/Maj functions, and the upper sigma functions.
  5. Digest — add each block's result back into the running hash state, then emit the eight words as hex.

See knowledge.md for fuller notes on the bitwise operations, the logical functions, and why the design choices (e.g. the length field, SHR vs. ROTR) matter.

License

Released under the MIT License. See LICENSE for details.

About

A from-scratch implementation of SHA-256 in C++, based on NIST FIPS 180-4.

Topics

Resources

License

Stars

6 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors