function sha256(str) {
// Convert string to utf-8 byte array
const utf8 = unescape(encodeURIComponent(str));
const bytes = [...utf8].map(c => c.charCodeAt(0));
// Initial Hash Values
const h = [
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19
];
// Constants
const k = [
0x428a2f98,
0x71374491,
0xb5c0fbcf,
0xe9b5dba5,
0x3956c25b,
0x59f111f1,
0x923f82a4,
0xab1c5ed5,
0xd807aa98,
0x12835b01,
0x243185be,
0x550c7dc3,
0x72be5d74,
0x80deb1fe,
0x9bdc06a7,
0xc19bf174,
0xe49b69c1,
0xefbe4786,
0x0fc19dc6,
0x240ca1cc,
0x2de92c6f,
0x4a7484aa,
0x5cb0a9dc,
0x76f988da,
0x983e5152,
0xa831c66d,
0xb00327c8,
0xbf597fc7,
0xc6e00bf3,
0xd5a79147,
0x06ca6351,
0x14292967,
0x27b70a85,
0x2e1b2138,
0x4d2c6dfc,
0x53380d13,
0x650a7354,
0x766a0abb,
0x81c2c92e,
0x92722c85,
0xa2bfe8a1,
0xa81a664b,
0xc24b8b70,
0xc76c51a3,
0xd192e819,
0xd6990624,
0xf40e3585,
0x106aa070,
0x19a4c116,
0x1e376c08,
0x2748774c,
0x34b0bcb5,
0x391c0cb3,
0x4ed8aa4a,
0x5b9cca4f,
0x682e6ff3,
0x748f82ee,
0x78a5636f,
0x84c87814,
0x8cc70208,
0x90befffa,
0xa4506ceb,
0xbef9a3f7,
0xc67178f2
];
// Pre-processing
bytes.push(0x80); // Add bit "1" to end of message
while ((bytes.length * 8) % 512 !== 448) {
bytes.push(0x00); // Add zeros until length is divisible by 512
}
const msgLenBits = str.length * 8;
const lenBytes = [
(msgLenBits >>> 56) & 0xff,
(msgLenBits >>> 48) & 0xff,
(msgLenBits >>> 40) & 0xff,
(msgLenBits >>> 32) & 0xff,
(msgLenBits >>> 24) & 0xff,
(msgLenBits >>> 16) & 0xff,
(msgLenBits >>> 8) & 0xff,
msgLenBits & 0xff
];
bytes.push(...lenBytes);
// Chunkify
const chunks = [];
for (let i = 0; i < bytes.length; i += 64) {
chunks.push(bytes.slice(i, i + 64));
}
// Process each chunk
for (let i = 0; i < chunks.length; i++) {
const w = new Array(64).fill(0);
for (let j = 0; j < 16; j++) {
w[j] =
(chunks[i][j * 4] << 24) |
(chunks[i][j * 4 + 1] << 16) |
(chunks[i][j * 4 + 2] << 8) |
chunks[i][j * 4 + 3];
}
for (let j = 16; j < 64; j++) {
const s0 =
(w[j - 15] >>> 7) ^
(w[j - 15] >>> 18) ^
(w[j - 15] >>> 3);
const s1 =
(w[j - 2] >>> 17) ^
(w[j - 2] >>> 19) ^
(w[j - 2] >>> 10);
w[j] = (w[j - 16] + s0 + w[j - 7] + s1) & 0xffffffff;
}
let [a, b, c, d, e, f, g, h] = h;
for (let j = 0; j < 64; j++) {
const S1 = (e >>> 6) ^ (e >>> 11) ^ (e >>> 25);
const ch = (e & f) ^ (~e & g);
const temp1 = (h + S1 + ch + k[j] + w[j]) & 0xffffffff;
const S0 = (a >>> 2) ^ (a >>> 13) ^ (a >>> 22);
const maj = (a & b) ^ (a & c) ^ (b & c);
const temp2 = (S0 + maj) & 0xffffffff;
h = g;
g = f;
f = e;
e = (d + temp1) & 0xffffffff;
d = c;
c = b;
b = a;
a = (temp1 + temp2) & 0xffffffff;
}
h = (h + h0) & 0xffffffff;
g = (g + g0) & 0xffffffff;
f = (f + f0) & 0xffffffff;
e = (e + e0) & 0xffffffff;
d = (d + d0) & 0xffffffff;
c = (c + c0) & 0xffffffff;
b = (b + b0) & 0xffffffff;
a = (a + a0) & 0xffffffff;
}
// Concatenate hash values
const hash = new Uint32Array([a, b, c, d, e, f, g, h]).reduce(
(acc, val) => {
let str = val.toString(16);
str = "0".repeat(8 - str.length) + str;
return `${acc}${str}`;
},
""
);
return hash;
}