sha256 function

Uint8List sha256(
  1. List<int> data
)

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;
}