This repository contains my work for the Secure Hash Standard (FIPS 180-4) assessment.
All solutions are implemented and explained in the main notebook: problems.ipynb
My aim was to present the notebook in a clear and structured way for someone who is comfortable with Python and basic cryptography, but may not be familiar with the internal workings of SHA-256. Each problem is broken down with explanations, code, and tests so that the full process can be followed without additional context.
- Python 3.8+
- NumPy
- Standard library modules (
hashlib,os, etc.)
-
Clone this repository:
git clone https://github.com/NathanCarr10/Computational-Theory.git cd Computational-Theory -
Install dependencies:
pip install numpy
-
Open and run the notebook:
jupyter notebook problems.ipynb
Or use VS Code with the Jupyter extension and select a Python kernel.
All cells are designed to run sequentially from top to bottom. There are no external data dependencies—all test data is generated within the notebook.
Each code cell is self-contained and includes comments explaining its purpose. Markdown cells provide context and theoretical background.
├── problems.ipynb # Main assessment notebook with full solutions
├── roughwork.ipynb # Scratch/testing notebook (not part of final marking, just my working area)
├── requirements.txt # Allowed packages for the assignment
└── README.md # This file
I implemented the core 32-bit operations used by SHA-256, including Ch, Maj, Σ0, Σ1, σ0 and σ1.
These are all wrapped as np.uint32 to match the behaviour in the Secure Hash Standard.
I also included tests that show the expected bitwise behaviour.
I generated the first 64 prime numbers, took the fractional parts of their cube roots, and extracted the first 32 bits just like FIPS 180-4 describes.
I then verified that my computed constants match the official constants exactly.
I implemented the SHA-256 padding rules, turning any input message into 512-bit blocks.
I tested edge cases (like messages of length 55, 56, and 57 bytes) to make sure the padding matches the standard perfectly.
I built the message schedule (W[0..63]) and the compression function (the 64 rounds), using the functions from earlier problems.
Finally, I wrote sha256_custom(msg) and confirmed that it matches Python’s hashlib.sha256 on a variety of standard test messages.
I used SHA-256 to demonstrate a simple dictionary attack on three given password hashes.
After recovering the passwords, I explained why hashing passwords with just SHA-256 is insecure and discussed better alternatives like PBKDF2, bcrypt, and Argon2, along with salts, peppers, and rate limiting.
- Install the required packages:
pip install -r requirements.txt
Launch Jupyter:
Open problems.ipynb and run the cells in order.
Everything is self-contained, and all tests run automatically.