\section{SHA-256} SHA-256 is part of the SHA-2 family of cryptographic hash functions, designed by the NSA and first published by NIST in 2001. It produces a 256-bit digest from a message of arbitrary length, processing data in 512-bit blocks. Unlike MD5, SHA-256 has no known practical collision attacks and remains widely used in security-critical applications such as TLS certificates and Bitcoin's proof-of-work. \vspace{1em} SHA-256 maintains a state of eight 32-bit words, initialized to fixed constants derived from the square roots of the first eight prime numbers. Each 512-bit block is processed in 64 rounds. Each round applies a compression step involving two non-linear functions, a message schedule word, and a precomputed constant derived from the cube roots of the first 64 prime numbers. \vspace{1em} The padding scheme is identical to MD5: a single \texttt{1} bit is appended, followed by \texttt{0} bits until the message length is congruent to 448 bits modulo 512, and the original length in bits is appended as a 64-bit integer. The difference is that SHA-256 encodes this length in big-endian order. \vspace{1em} Each round uses two non-linear functions applied to the state words: \begin{align*} \text{Ch}(E, F, G) &= (E \land F) \oplus (\lnot E \land G) \\ \text{Maj}(A, B, C) &= (A \land B) \oplus (A \land C) \oplus (B \land C) \end{align*} \noindent and two rotation-based functions applied to the state words $A$ and $E$: \begin{align*} \Sigma_0(A) &= (A \ggg 2) \oplus (A \ggg 13) \oplus (A \ggg 22) \\ \Sigma_1(E) &= (E \ggg 6) \oplus (E \ggg 11) \oplus (E \ggg 25) \end{align*} \noindent where $\ggg$ denotes a right rotation. \vspace{1em} At each round $i$ (with $0 \leq i < 64$), the state is updated as follows: \begin{align*} T_1 &= H + \Sigma_1(E) + \text{Ch}(E, F, G) + K[i] + W[i] \\ T_2 &= \Sigma_0(A) + \text{Maj}(A, B, C) \\ H &\leftarrow G, \quad G \leftarrow F, \quad F \leftarrow E, \quad E \leftarrow D + T_1 \\ D &\leftarrow C, \quad C \leftarrow B, \quad B \leftarrow A, \quad A \leftarrow T_1 + T_2 \end{align*} \noindent where $K[i]$ is a precomputed constant and $W[i]$ is a word from the message schedule. \vspace{1em} \begin{align*} \forall i \in \mathbb{N},\ 0 \leq i < 64,\quad K[i] = \left\lfloor 2^{32} \times \left(\sqrt[3]{p_{i+1}} \bmod 1\right) \right\rfloor \end{align*} \noindent where $p_{i+1}$ is the $(i+1)$-th prime number and $\bmod 1$ denotes the fractional part. \vspace{1em} The message schedule extends the 16 words of the current block into 64 words using two additional rotation-based functions: \begin{align*} \sigma_0(x) &= (x \ggg 7) \oplus (x \ggg 18) \oplus (x \gg 3) \\ \sigma_1(x) &= (x \ggg 17) \oplus (x \ggg 19) \oplus (x \gg 10) \end{align*} \noindent where $\gg$ denotes a logical right shift, and $M[i]$ denotes the $i$-th 32-bit word of the current 512-bit block. The schedule is then defined as: \begin{align*} W[i] = \begin{cases} M[i] & i \in \mathbb{N},\ 0 \leq i < 16 \\ \sigma_1(W[i-2]) + W[i-7] + \sigma_0(W[i-15]) + W[i-16] & i \in \mathbb{N},\ 16 \leq i < 64 \end{cases} \end{align*} \vspace{1em} The state is initialized to fixed constants derived from the square roots of the first eight prime numbers: \begin{align*} \forall (X,p)\in\{(A,2),(B,3),(C,5),(D,7),(E,11),(F,13),(G,17),(H,19)\}, X \leftarrow \left\lfloor \{\sqrt{p}\}\;2^{32}\right\rfloor \end{align*} \begin{align*} A &= \texttt{0x6a09e667}, \quad B = \texttt{0xbb67ae85}, \quad C = \texttt{0x3c6ef372}, \quad D = \texttt{0xa54ff53a} \\ E &= \texttt{0x510e527f}, \quad F = \texttt{0x9b05688c}, \quad G = \texttt{0x1f83d9ab}, \quad H = \texttt{0x5be0cd19} \end{align*} After each block is processed, the compressed state is added word-by-word to the state before compression: \begin{align*} \forall X \in \{A, B, C, D, E, F, G ,H\}, \quad X \leftarrow X + X_0 \end{align*} \noindent where $X_0$ denote the state at the beginning of the block. After all blocks have been processed, the eight state words are serialized in big-endian order to produce the 256-bit digest.