Skip to content

Instantly share code, notes, and snippets.

@RagePit
Last active December 1, 2023 14:39
Show Gist options
  • Save RagePit/02cfa6568d8bf0a4933cd7f3ec42d948 to your computer and use it in GitHub Desktop.
Save RagePit/02cfa6568d8bf0a4933cd7f3ec42d948 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
/// @author @rage_pit
/// @notice Not written to be particularly readable
library SHA256 {
/**
Taken from:
https://eips.ethereum.org/assets/eip-2680/sha256-384-512.pdf
https://gist.github.com/hak8or/8794351
https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
Thanks to https://sha256algorithm.com/
*/
uint constant H_OFFSET = 0;
uint constant K_OFFSET = 32;
uint constant BLOCK_OFFSET = 288;
// NOT AUDITED FOR PRODUCTION
function hash(bytes memory _input) internal pure returns(bytes32 output) {
bytes memory input = _input;
assembly {
let len := mload(input)
let dataPtr := add(input, 0x20)
// pad message with 0b1
mstore(add(len, dataPtr), shl(248, 0x80))
// pad with zeros to nearest multiple of 64 bytes
let pad := mod(len, 64)
let k := add(len, sub(56, pad))
switch lt(pad, 56)
case 0 { k := add(k, 64) }
//zero out to end of padding
calldatacopy(add(dataPtr, add(len, 1)), calldatasize(), k)
// end padding with message length
mstore(add(k, dataPtr), shl(192, mul(8, len)))
// number of rounds
let N := add(div(k, 64), 1)
// pointer to the end of the padded message
let START := add(dataPtr, mul(N, 64))
// To avoid stack-too-deep we store the intermidiate hashes, and constant K values in memory
// Copied from SHA256 spec
mstore(add(START, H_OFFSET), 0x6a09e667bb67ae853c6ef372a54ff53a510e527f9b05688c1f83d9ab5be0cd19)
mstore(add(START, add(K_OFFSET, 0)), 0x428a2f9871374491b5c0fbcfe9b5dba53956c25b59f111f1923f82a4ab1c5ed5)
mstore(add(START, add(K_OFFSET, 32)), 0xd807aa9812835b01243185be550c7dc372be5d7480deb1fe9bdc06a7c19bf174)
mstore(add(START, add(K_OFFSET, 64)), 0xe49b69c1efbe47860fc19dc6240ca1cc2de92c6f4a7484aa5cb0a9dc76f988da)
mstore(add(START, add(K_OFFSET, 96)), 0x983e5152a831c66db00327c8bf597fc7c6e00bf3d5a7914706ca635114292967)
mstore(add(START, add(K_OFFSET, 128)), 0x27b70a852e1b21384d2c6dfc53380d13650a7354766a0abb81c2c92e92722c85)
mstore(add(START, add(K_OFFSET, 160)), 0xa2bfe8a1a81a664bc24b8b70c76c51a3d192e819d6990624f40e3585106aa070)
mstore(add(START, add(K_OFFSET, 192)), 0x19a4c1161e376c082748774c34b0bcb5391c0cb34ed8aa4a5b9cca4f682e6ff3)
mstore(add(START, add(K_OFFSET, 224)), 0x748f82ee78a5636f84c878148cc7020890befffaa4506cebbef9a3f7c67178f2)
function H(start, i) -> a { a := shr(224, mload(add(start, add(H_OFFSET, mul(4, i))))) }
function setH(start, i, n) {
let off := add(start, add(H_OFFSET, mul(4, i)))
mstore(off, or(shl(224, n), and(mload(off), 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff)))
}
function K(start, i) -> a { a := shr(224, mload(add(start, add(K_OFFSET, mul(4, i))))) }
function W(blockPtr, i) -> a { a := mload(add(blockPtr, mul(i, 32))) }
function setW(blockPtr, i, word) { mstore(add(blockPtr, mul(i, 32)), word) }
function ROTRIGHT(word, bits) -> a { a := or(shr(bits, word), shl(sub(32, bits), word)) }
function SSIG0(x) -> a { a := xor(xor(ROTRIGHT(x,7), ROTRIGHT(x,18)), shr(3, x)) }
function SSIG1(x) -> a { a := xor(xor(ROTRIGHT(x,17), ROTRIGHT(x,19)), shr(10, x)) }
function EP0(x) -> a { a := and(xor(xor(ROTRIGHT(x,2), ROTRIGHT(x,13)), ROTRIGHT(x,22)), 0xffffffff) }
function EP1(x) -> a { a := and(xor(xor(ROTRIGHT(x,6), ROTRIGHT(x,11)), ROTRIGHT(x,25)), 0xffffffff) }
function CH(x, y, z) -> a { a := xor(and(x, y), and(and(not(x), 0xffffffff), z)) }
function MAJ(x, y, z) -> a { a := xor(xor(and(x, y), and(x, z)), and(y, z)) }
for {let i := 0} lt(i, N) {i := add(i, 1)} {
let B := add(START, BLOCK_OFFSET)
// Preparing the message schedule
for {let t := 0} lt(t, 16) {t := add(t, 1)} {
let word := shr(224, mload(add(dataPtr, add(mul(t, 4), mul(i, 64)))))
setW(B, t, word)
}
for {let t := 16} lt(t, 64) {t := add(t, 1)} {
let w := add(add(add(
SSIG1(W(B, sub(t,2))),
W(B, sub(t,7))),
SSIG0(W(B, sub(t,15)))),
W(B, sub(t,16)))
setW(B, t, and(w, 0xffffffff))
}
// Init
let a := H(START, 0)
let b := H(START, 1)
let c := H(START, 2)
let d := H(START, 3)
let e := H(START, 4)
let f := H(START, 5)
let g := H(START, 6)
let h := H(START, 7)
for {let t := 0} lt(t, 64) {t := add(t, 1)} {
let temp1 := add(h, add(EP1(e), add(CH(e,f,g), add(K(START,t), W(B,t)))))
let temp2 := add(EP0(a), MAJ(a,b,c))
h := g
g := f
f := e
e := and(add(d, temp1), 0xffffffff)
d := c
c := b
b := a
a := and(add(temp1, temp2), 0xffffffff)
}
setH(START, 0, and(add(a, H(START, 0)), 0xffffffff))
setH(START, 1, and(add(b, H(START, 1)), 0xffffffff))
setH(START, 2, and(add(c, H(START, 2)), 0xffffffff))
setH(START, 3, and(add(d, H(START, 3)), 0xffffffff))
setH(START, 4, and(add(e, H(START, 4)), 0xffffffff))
setH(START, 5, and(add(f, H(START, 5)), 0xffffffff))
setH(START, 6, and(add(g, H(START, 6)), 0xffffffff))
setH(START, 7, and(add(h, H(START, 7)), 0xffffffff))
}
output := mload(add(START, H_OFFSET))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment