sha256 function
Calcula o digest SHA-256 de data e retorna 32 bytes.
final digest = sha256(utf8.encode('hello'));
// digest.length == 32
Implementation
Uint8List sha256(List<int> data) {
// --- 1. Pré-processamento: padding ---
// Comprimento original em bits
final bitLength = data.length * 8;
// Cria lista mutável e adiciona bit '1' (0x80)
final padded = [...data, 0x80];
// Padding com zeros até comprimento ≡ 448 mod 512 bits (56 mod 64 bytes)
while (padded.length % 64 != 56) {
padded.add(0x00);
}
// Comprimento original como uint64 big-endian (8 bytes)
for (int i = 7; i >= 0; i--) {
padded.add((bitLength >> (i * 8)) & 0xff);
}
// --- 2. Inicializa o estado do hash ---
final h = List<int>.from(_h0);
// --- 3. Processa cada bloco de 512 bits (64 bytes) ---
final numBlocks = padded.length ~/ 64;
final w = List<int>.filled(64, 0);
for (int blockIdx = 0; blockIdx < numBlocks; blockIdx++) {
final offset = blockIdx * 64;
// Prepara o message schedule (64 palavras de 32 bits)
for (int i = 0; i < 16; i++) {
w[i] = ((padded[offset + i * 4] & 0xff) << 24) |
((padded[offset + i * 4 + 1] & 0xff) << 16) |
((padded[offset + i * 4 + 2] & 0xff) << 8) |
(padded[offset + i * 4 + 3] & 0xff);
}
for (int i = 16; i < 64; i++) {
final s0 = _rotr32(w[i - 15], 7) ^
_rotr32(w[i - 15], 18) ^
(w[i - 15] >>> 3);
final s1 = _rotr32(w[i - 2], 17) ^
_rotr32(w[i - 2], 19) ^
(w[i - 2] >>> 10);
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffff;
}
// Inicializa variáveis de trabalho com o hash atual
int a = h[0],
b = h[1],
c = h[2],
d = h[3],
e = h[4],
f = h[5],
g = h[6],
hh = h[7];
// 64 rounds de compressão
for (int i = 0; i < 64; i++) {
final s1 = _rotr32(e, 6) ^ _rotr32(e, 11) ^ _rotr32(e, 25);
final ch = (e & f) ^ (~e & g) & 0xffffffff;
final temp1 = (hh + s1 + ch + _k[i] + w[i]) & 0xffffffff;
final s0 = _rotr32(a, 2) ^ _rotr32(a, 13) ^ _rotr32(a, 22);
final maj = (a & b) ^ (a & c) ^ (b & c);
final temp2 = (s0 + maj) & 0xffffffff;
hh = g;
g = f;
f = e;
e = (d + temp1) & 0xffffffff;
d = c;
c = b;
b = a;
a = (temp1 + temp2) & 0xffffffff;
}
// Soma o bloco comprimido ao hash corrente
h[0] = (h[0] + a) & 0xffffffff;
h[1] = (h[1] + b) & 0xffffffff;
h[2] = (h[2] + c) & 0xffffffff;
h[3] = (h[3] + d) & 0xffffffff;
h[4] = (h[4] + e) & 0xffffffff;
h[5] = (h[5] + f) & 0xffffffff;
h[6] = (h[6] + g) & 0xffffffff;
h[7] = (h[7] + hh) & 0xffffffff;
}
// --- 4. Serializa digest em big-endian ---
final digest = Uint8List(32);
final view = ByteData.sublistView(digest);
for (int i = 0; i < 8; i++) {
view.setUint32(i * 4, h[i], Endian.big);
}
return digest;
}