8#include <botan/chacha.h>
9#include <botan/exceptn.h>
10#include <botan/loadstor.h>
11#include <botan/rotate.h>
12#include <botan/cpuid.h>
18#define CHACHA_QUARTER_ROUND(a, b, c, d) \
20 a += b; d ^= a; d = rotl<16>(d); \
21 c += d; b ^= c; b = rotl<12>(b); \
22 a += b; d ^= a; d = rotl<8>(d); \
23 c += d; b ^= c; b = rotl<7>(b); \
29void hchacha(uint32_t output[8],
const uint32_t input[16],
size_t rounds)
33 uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
34 x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
35 x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
36 x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
38 for(
size_t i = 0; i != rounds / 2; ++i)
66 "ChaCha only supports 8, 12 or 20 rounds");
71#if defined(BOTAN_HAS_CHACHA_AVX2)
78#if defined(BOTAN_HAS_CHACHA_SIMD32)
89void ChaCha::chacha_x8(uint8_t output[64*8], uint32_t input[16],
size_t rounds)
93#if defined(BOTAN_HAS_CHACHA_AVX2)
96 return ChaCha::chacha_avx2_x8(output, input, rounds);
100#if defined(BOTAN_HAS_CHACHA_SIMD32)
103 ChaCha::chacha_simd32_x4(output, input, rounds);
104 ChaCha::chacha_simd32_x4(output + 4*64, input, rounds);
110 for(
size_t i = 0; i != 8; ++i)
112 uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
113 x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
114 x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
115 x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
117 for(
size_t r = 0; r != rounds / 2; ++r)
147 store_le(x00, output + 64 * i + 4 * 0);
148 store_le(x01, output + 64 * i + 4 * 1);
149 store_le(x02, output + 64 * i + 4 * 2);
150 store_le(x03, output + 64 * i + 4 * 3);
151 store_le(x04, output + 64 * i + 4 * 4);
152 store_le(x05, output + 64 * i + 4 * 5);
153 store_le(x06, output + 64 * i + 4 * 6);
154 store_le(x07, output + 64 * i + 4 * 7);
155 store_le(x08, output + 64 * i + 4 * 8);
156 store_le(x09, output + 64 * i + 4 * 9);
157 store_le(x10, output + 64 * i + 4 * 10);
158 store_le(x11, output + 64 * i + 4 * 11);
159 store_le(x12, output + 64 * i + 4 * 12);
160 store_le(x13, output + 64 * i + 4 * 13);
161 store_le(x14, output + 64 * i + 4 * 14);
162 store_le(x15, output + 64 * i + 4 * 15);
165 input[13] += (input[12] == 0);
169#undef CHACHA_QUARTER_ROUND
178 while(length >= m_buffer.size() - m_position)
180 const size_t available = m_buffer.size() - m_position;
182 xor_buf(out, in, &m_buffer[m_position], available);
183 chacha_x8(m_buffer.data(), m_state.data(), m_rounds);
191 xor_buf(out, in, &m_buffer[m_position], length);
193 m_position += length;
200 while(length >= m_buffer.size() - m_position)
202 const size_t available = m_buffer.size() - m_position;
204 copy_mem(out, &m_buffer[m_position], available);
205 chacha_x8(m_buffer.data(), m_state.data(), m_rounds);
212 copy_mem(out, &m_buffer[m_position], length);
214 m_position += length;
217void ChaCha::initialize_state()
219 static const uint32_t TAU[] =
220 { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };
222 static const uint32_t SIGMA[] =
223 { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
225 m_state[4] = m_key[0];
226 m_state[5] = m_key[1];
227 m_state[6] = m_key[2];
228 m_state[7] = m_key[3];
230 if(m_key.size() == 4)
237 m_state[8] = m_key[0];
238 m_state[9] = m_key[1];
239 m_state[10] = m_key[2];
240 m_state[11] = m_key[3];
244 m_state[0] = SIGMA[0];
245 m_state[1] = SIGMA[1];
246 m_state[2] = SIGMA[2];
247 m_state[3] = SIGMA[3];
249 m_state[8] = m_key[4];
250 m_state[9] = m_key[5];
251 m_state[10] = m_key[6];
252 m_state[11] = m_key[7];
266void ChaCha::key_schedule(
const uint8_t key[],
size_t length)
268 m_key.resize(length / 4);
273 const size_t chacha_parallelism = 8;
274 const size_t chacha_block = 64;
275 m_buffer.resize(chacha_parallelism * chacha_block);
292 return new ChaCha(m_rounds);
297 return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24);
320 else if(length == 12)
326 else if(length == 24)
334 hchacha(hc.data(), m_state.data(), m_rounds);
350 chacha_x8(m_buffer.data(), m_state.data(), m_rounds);
364 return "ChaCha(" + std::to_string(m_rounds) +
")";
372 const uint64_t counter = offset / 64;
381 chacha_x8(m_buffer.data(), m_state.data(), m_rounds);
382 m_position = offset % 64;
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
#define CHACHA_QUARTER_ROUND(a, b, c, d)
static bool has_simd_32()
StreamCipher * clone() const override
std::string name() const override
void cipher(const uint8_t in[], uint8_t out[], size_t length) override
void set_iv(const uint8_t iv[], size_t iv_len) override
Key_Length_Specification key_spec() const override
bool valid_iv_length(size_t iv_len) const override
size_t default_iv_length() const override
std::string provider() const override
void seek(uint64_t offset) override
void write_keystream(uint8_t out[], size_t len) override
void verify_key_set(bool cond) const
void zap(std::vector< T, Alloc > &vec)
uint32_t load_le< uint32_t >(const uint8_t in[], size_t off)
void copy_mem(T *out, const T *in, size_t n)
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
void store_le(uint16_t in, uint8_t out[2])
std::vector< T, secure_allocator< T > > secure_vector