16#define QUARTERROUND(a,b,c,d) \
17 a += b; d = std::rotl(d ^ a, 16); \
18 c += d; b = std::rotl(b ^ c, 12); \
19 a += b; d = std::rotl(d ^ a, 8); \
20 c += d; b = std::rotl(b ^ c, 7);
22#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
26 assert(key.size() == KEYLEN);
30 input[3] =
ReadLE32(key.data() + 12);
31 input[4] =
ReadLE32(key.data() + 16);
32 input[5] =
ReadLE32(key.data() + 20);
33 input[6] =
ReadLE32(key.data() + 24);
34 input[7] =
ReadLE32(key.data() + 28);
54 input[9] =
nonce.first;
55 input[10] =
nonce.second;
56 input[11] =
nonce.second >> 32;
61 std::byte*
c = output.data();
62 size_t blocks = output.size() / BLOCKLEN;
65 uint32_t x0,
x1,
x2,
x3,
x4,
x5,
x6,
x7,
x8,
x9,
x10,
x11,
x12,
x13,
x14,
x15;
66 uint32_t j4,
j5,
j6,
j7,
j8,
j9,
j10,
j11,
j12,
j13,
j14,
j15;
168 uint32_t x0,
x1,
x2,
x3,
x4,
x5,
x6,
x7,
x8,
x9,
x10,
x11,
x12,
x13,
x14,
x15;
169 uint32_t j4,
j5,
j6,
j7,
j8,
j9,
j10,
j11,
j12,
j13,
j14,
j15;
283 if (out.empty())
return;
285 unsigned reuse = std::min<size_t>(m_bufleft, out.size());
286 std::copy(m_buffer.end() - m_bufleft, m_buffer.end() - m_bufleft +
reuse, out.begin());
288 out = out.subspan(
reuse);
290 if (out.size() >= m_aligned.BLOCKLEN) {
291 size_t blocks = out.size() / m_aligned.BLOCKLEN;
292 m_aligned.Keystream(out.first(
blocks * m_aligned.BLOCKLEN));
293 out = out.subspan(
blocks * m_aligned.BLOCKLEN);
296 m_aligned.Keystream(m_buffer);
297 std::copy(m_buffer.begin(), m_buffer.begin() + out.size(), out.begin());
298 m_bufleft = m_aligned.BLOCKLEN - out.size();
302void ChaCha20::Crypt(std::span<const std::byte> input, std::span<std::byte> output)
noexcept
304 assert(input.size() == output.size());
306 if (!input.size())
return;
308 unsigned reuse = std::min<size_t>(m_bufleft, input.size());
309 for (
unsigned i = 0; i <
reuse; i++) {
310 output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
313 output = output.subspan(
reuse);
314 input = input.subspan(
reuse);
316 if (input.size() >= m_aligned.BLOCKLEN) {
317 size_t blocks = input.size() / m_aligned.BLOCKLEN;
318 m_aligned.Crypt(input.first(
blocks * m_aligned.BLOCKLEN), output.first(
blocks * m_aligned.BLOCKLEN));
319 output = output.subspan(
blocks * m_aligned.BLOCKLEN);
320 input = input.subspan(
blocks * m_aligned.BLOCKLEN);
322 if (!input.empty()) {
323 m_aligned.Keystream(m_buffer);
324 for (
unsigned i = 0; i < input.size(); i++) {
325 output[i] = input[i] ^ m_buffer[i];
327 m_bufleft = m_aligned.BLOCKLEN - input.size();
338 m_aligned.SetKey(key);
346 assert(key.size() == KEYLEN);
351 assert(input.size() == output.size());
354 m_chacha20.Crypt(input, output);
357 if (++m_chunk_counter == m_rekey_interval) {
367 m_chacha20.Seek({0, ++m_rekey_counter}, 0);
void Keystream(std::span< std::byte > out) noexcept
outputs the keystream into out, whose length must be a multiple of BLOCKLEN.
void Crypt(std::span< const std::byte > input, std::span< std::byte > output) noexcept
en/deciphers the message <input> and write the result into <output>
ChaCha20Aligned() noexcept=delete
For safety, disallow initialization without key.
std::pair< uint32_t, uint64_t > Nonce96
Type for 96-bit nonces used by the Set function below.
void Seek(Nonce96 nonce, uint32_t block_counter) noexcept
Set the 96-bit nonce and 32-bit block counter.
void SetKey(std::span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
~ChaCha20Aligned()
Destructor to clean up private memory.
void SetKey(std::span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
std::array< std::byte, ChaCha20Aligned::BLOCKLEN > m_buffer
~ChaCha20()
Destructor to clean up private memory.
void Keystream(std::span< std::byte > out) noexcept
outputs the keystream to out.
void Crypt(std::span< const std::byte > in_bytes, std::span< std::byte > out_bytes) noexcept
en/deciphers the message <in_bytes> and write the result into <out_bytes>
FSChaCha20(const FSChaCha20 &)=delete
void Crypt(std::span< const std::byte > input, std::span< std::byte > output) noexcept
Encrypt or decrypt a chunk.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
#define QUARTERROUND(a, b, c, d)
void WriteLE32(B *ptr, uint32_t x)
uint32_t ReadLE32(const B *ptr)
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.