8#include <botan/internal/chacha.h>
9#include <botan/exceptn.h>
10#include <botan/internal/loadstor.h>
11#include <botan/internal/rotate.h>
12#include <botan/internal/cpuid.h>
13#include <botan/internal/fmt.h>
19inline void chacha_quarter_round(uint32_t& a,
24 a += b; d ^= a; d = rotl<16>(d);
25 c += d; b ^= c; b = rotl<12>(b);
26 a += b; d ^= a; d = rotl< 8>(d);
27 c += d; b ^= c; b = rotl< 7>(b);
33void hchacha(uint32_t output[8],
const uint32_t input[16],
size_t rounds)
37 uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
38 x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
39 x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
40 x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
42 for(
size_t i = 0; i != rounds / 2; ++i)
44 chacha_quarter_round(x00, x04, x08, x12);
45 chacha_quarter_round(x01, x05, x09, x13);
46 chacha_quarter_round(x02, x06, x10, x14);
47 chacha_quarter_round(x03, x07, x11, x15);
49 chacha_quarter_round(x00, x05, x10, x15);
50 chacha_quarter_round(x01, x06, x11, x12);
51 chacha_quarter_round(x02, x07, x08, x13);
52 chacha_quarter_round(x03, x04, x09, x14);
70 "ChaCha only supports 8, 12 or 20 rounds");
73size_t ChaCha::parallelism()
75#if defined(BOTAN_HAS_CHACHA_AVX2)
85#if defined(BOTAN_HAS_CHACHA_AVX2)
92#if defined(BOTAN_HAS_CHACHA_SIMD32)
102void ChaCha::chacha(uint8_t output[],
103 size_t output_blocks,
104 uint32_t state[16],
size_t rounds)
108#if defined(BOTAN_HAS_CHACHA_AVX2)
109 if(CPUID::has_avx2())
111 while(output_blocks >= 8)
113 ChaCha::chacha_avx2_x8(output, state, rounds);
120#if defined(BOTAN_HAS_CHACHA_SIMD32)
123 while(output_blocks >= 4)
125 ChaCha::chacha_simd32_x4(output, state, rounds);
133 for(
size_t i = 0; i != output_blocks; ++i)
135 uint32_t x00 = state[ 0], x01 = state[ 1], x02 = state[ 2], x03 = state[ 3],
136 x04 = state[ 4], x05 = state[ 5], x06 = state[ 6], x07 = state[ 7],
137 x08 = state[ 8], x09 = state[ 9], x10 = state[10], x11 = state[11],
138 x12 = state[12], x13 = state[13], x14 = state[14], x15 = state[15];
140 for(
size_t r = 0; r != rounds / 2; ++r)
142 chacha_quarter_round(x00, x04, x08, x12);
143 chacha_quarter_round(x01, x05, x09, x13);
144 chacha_quarter_round(x02, x06, x10, x14);
145 chacha_quarter_round(x03, x07, x11, x15);
147 chacha_quarter_round(x00, x05, x10, x15);
148 chacha_quarter_round(x01, x06, x11, x12);
149 chacha_quarter_round(x02, x07, x08, x13);
150 chacha_quarter_round(x03, x04, x09, x14);
170 store_le(x00, output + 64 * i + 4 * 0);
171 store_le(x01, output + 64 * i + 4 * 1);
172 store_le(x02, output + 64 * i + 4 * 2);
173 store_le(x03, output + 64 * i + 4 * 3);
174 store_le(x04, output + 64 * i + 4 * 4);
175 store_le(x05, output + 64 * i + 4 * 5);
176 store_le(x06, output + 64 * i + 4 * 6);
177 store_le(x07, output + 64 * i + 4 * 7);
178 store_le(x08, output + 64 * i + 4 * 8);
179 store_le(x09, output + 64 * i + 4 * 9);
180 store_le(x10, output + 64 * i + 4 * 10);
181 store_le(x11, output + 64 * i + 4 * 11);
182 store_le(x12, output + 64 * i + 4 * 12);
183 store_le(x13, output + 64 * i + 4 * 13);
184 store_le(x14, output + 64 * i + 4 * 14);
185 store_le(x15, output + 64 * i + 4 * 15);
188 state[13] += (state[12] == 0);
195void ChaCha::cipher_bytes(
const uint8_t in[], uint8_t out[],
size_t length)
199 while(length >= m_buffer.size() - m_position)
201 const size_t available = m_buffer.size() - m_position;
203 xor_buf(out, in, &m_buffer[m_position], available);
204 chacha(m_buffer.data(), m_buffer.size() / 64,
205 m_state.data(), m_rounds);
213 xor_buf(out, in, &m_buffer[m_position], length);
215 m_position += length;
218void ChaCha::generate_keystream(uint8_t out[],
size_t length)
222 while(length >= m_buffer.size() - m_position)
224 const size_t available = m_buffer.size() - m_position;
228 copy_mem(out, &m_buffer[m_position], available);
229 chacha(m_buffer.data(), m_buffer.size() / 64,
230 m_state.data(), m_rounds);
237 copy_mem(out, &m_buffer[m_position], length);
239 m_position += length;
242void ChaCha::initialize_state()
244 static const uint32_t TAU[] =
245 { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };
247 static const uint32_t SIGMA[] =
248 { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
250 m_state[4] = m_key[0];
251 m_state[5] = m_key[1];
252 m_state[6] = m_key[2];
253 m_state[7] = m_key[3];
255 if(m_key.size() == 4)
262 m_state[8] = m_key[0];
263 m_state[9] = m_key[1];
264 m_state[10] = m_key[2];
265 m_state[11] = m_key[3];
269 m_state[0] = SIGMA[0];
270 m_state[1] = SIGMA[1];
271 m_state[2] = SIGMA[2];
272 m_state[3] = SIGMA[3];
274 m_state[8] = m_key[4];
275 m_state[9] = m_key[5];
276 m_state[10] = m_key[6];
277 m_state[11] = m_key[7];
290 return !m_state.empty();
301void ChaCha::key_schedule(
const uint8_t key[],
size_t length)
303 m_key.resize(length / 4);
308 const size_t chacha_block = 64;
309 m_buffer.resize(parallelism() * chacha_block);
326 return std::make_unique<ChaCha>(m_rounds);
331 return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24);
334void ChaCha::set_iv_bytes(
const uint8_t iv[],
size_t length)
354 else if(length == 12)
360 else if(length == 24)
367 secure_vector<uint32_t> hc(8);
368 hchacha(hc.data(), m_state.data(), m_rounds);
384 chacha(m_buffer.data(), m_buffer.size() / 64,
385 m_state.data(), m_rounds);
399 return fmt(
"ChaCha({})", m_rounds);
407 const uint64_t counter = offset / 64;
416 chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
417 m_position = offset % 64;
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
static bool has_simd_32()
std::string name() const override
size_t buffer_size() const override
std::unique_ptr< StreamCipher > new_object() const 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
bool has_keying_material() const override
void seek(uint64_t offset) override
void set_iv(const uint8_t iv[], size_t iv_len)
void assert_key_material_set() const
constexpr uint32_t load_le< uint32_t >(const uint8_t in[], size_t off)
constexpr void store_le(uint16_t in, uint8_t out[2])
void zap(std::vector< T, Alloc > &vec)
std::string fmt(std::string_view format, const T &... args)
constexpr void copy_mem(T *out, const T *in, size_t n)
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)