chacha20Block function

Uint8List chacha20Block(
  1. Uint8List key32,
  2. int counter,
  3. Uint8List nonce12
)

Generates one 64-byte ChaCha20 keystream block for the given 32-byte key32, 32-bit block counter and 12-byte nonce12.

Implementation

Uint8List chacha20Block(Uint8List key32, int counter, Uint8List nonce12) {
  if (key32.length != 32) {
    throw ArgumentError('key must be 32 bytes');
  }
  if (nonce12.length != 12) {
    throw ArgumentError('nonce must be 12 bytes');
  }

  final state = Uint32List(16);
  // Constants: "expand 32-byte k"
  state[0] = 0x61707865;
  state[1] = 0x3320646e;
  state[2] = 0x79622d32;
  state[3] = 0x6b206574;
  // Key
  for (var i = 0; i < 8; i++) {
    state[4 + i] = _le32(key32, i * 4);
  }
  // Counter
  state[12] = counter & _mask32;
  // Nonce
  state[13] = _le32(nonce12, 0);
  state[14] = _le32(nonce12, 4);
  state[15] = _le32(nonce12, 8);

  final working = Uint32List.fromList(state);
  for (var i = 0; i < 10; i++) {
    // Column rounds
    _quarterRound(working, 0, 4, 8, 12);
    _quarterRound(working, 1, 5, 9, 13);
    _quarterRound(working, 2, 6, 10, 14);
    _quarterRound(working, 3, 7, 11, 15);
    // Diagonal rounds
    _quarterRound(working, 0, 5, 10, 15);
    _quarterRound(working, 1, 6, 11, 12);
    _quarterRound(working, 2, 7, 8, 13);
    _quarterRound(working, 3, 4, 9, 14);
  }

  final out = Uint8List(64);
  for (var i = 0; i < 16; i++) {
    final word = (working[i] + state[i]) & _mask32;
    out[i * 4] = word & 0xff;
    out[i * 4 + 1] = (word >> 8) & 0xff;
    out[i * 4 + 2] = (word >> 16) & 0xff;
    out[i * 4 + 3] = (word >> 24) & 0xff;
  }
  return out;
}