// Copyright (c) 2014-2018 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Boolberry developers // Copyright (c) 2017-2025 Lethean (https://lt.hn) // // Licensed under the European Union Public Licence (EUPL) version 1.2. // You may obtain a copy of the licence at: // // https://joinup.ec.europa.eu/software/page/eupl/licence-eupl // // The EUPL is a copyleft licence that is compatible with the MIT/X11 // licence used by the original projects; the MIT terms are therefore // considered “grandfathered” under the EUPL for this code. // // SPDX‑License‑Identifier: EUPL-1.2 // /* chacha-ref.c version 20080118 D. J. Bernstein Public domain. */ #include "ecrypt-sync.h" #define ROTATE(v,c) (ROTL32(v,c)) #define XOR(v,w) ((v) ^ (w)) #define PLUS(v,w) (U32V((v) + (w))) #define PLUSONE(v) (PLUS((v),1)) #define QUARTERROUND(a,b,c,d) \ x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); static void salsa20_wordtobyte(u8 output[64], const u32 input[16]) { u32 x[16]; int i; for (i = 0; i < 16; ++i) x[i] = input[i]; for (i = 8; i > 0; i -= 2) { QUARTERROUND(0, 4, 8, 12) QUARTERROUND(1, 5, 9, 13) QUARTERROUND(2, 6, 10, 14) QUARTERROUND(3, 7, 11, 15) QUARTERROUND(0, 5, 10, 15) QUARTERROUND(1, 6, 11, 12) QUARTERROUND(2, 7, 8, 13) QUARTERROUND(3, 4, 9, 14) } for (i = 0; i < 16; ++i) x[i] = PLUS(x[i], input[i]); for (i = 0; i < 16; ++i) U32TO8_LITTLE(output + 4 * i, x[i]); } void ECRYPT_init(void) { return; } static const char sigma[16] = "expand 32-byte k"; static const char tau[16] = "expand 16-byte k"; void ECRYPT_keysetup(ECRYPT_ctx *x, const u8 *k, u32 kbits, u32 ivbits) { const char *constants; x->input[4] = U8TO32_LITTLE(k + 0); x->input[5] = U8TO32_LITTLE(k + 4); x->input[6] = U8TO32_LITTLE(k + 8); x->input[7] = U8TO32_LITTLE(k + 12); if (kbits == 256) { /* recommended */ k += 16; constants = sigma; } else { /* kbits == 128 */ constants = tau; } x->input[8] = U8TO32_LITTLE(k + 0); x->input[9] = U8TO32_LITTLE(k + 4); x->input[10] = U8TO32_LITTLE(k + 8); x->input[11] = U8TO32_LITTLE(k + 12); x->input[0] = U8TO32_LITTLE(constants + 0); x->input[1] = U8TO32_LITTLE(constants + 4); x->input[2] = U8TO32_LITTLE(constants + 8); x->input[3] = U8TO32_LITTLE(constants + 12); } void ECRYPT_ivsetup(ECRYPT_ctx *x, const u8 *iv) { x->input[12] = 0; x->input[13] = 0; x->input[14] = U8TO32_LITTLE(iv + 0); x->input[15] = U8TO32_LITTLE(iv + 4); } void ECRYPT_encrypt_bytes(ECRYPT_ctx *x, const u8 *m, u8 *c, u32 bytes) { u8 output[64]; int i; if (!bytes) return; for (;;) { salsa20_wordtobyte(output, x->input); x->input[12] = PLUSONE(x->input[12]); if (!x->input[12]) { x->input[13] = PLUSONE(x->input[13]); /* stopping at 2^70 bytes per nonce is user's responsibility */ } if (bytes <= 64) { for (i = 0; i < bytes; ++i) c[i] = m[i] ^ output[i]; return; } for (i = 0; i < 64; ++i) c[i] = m[i] ^ output[i]; bytes -= 64; c += 64; m += 64; } } void ECRYPT_decrypt_bytes(ECRYPT_ctx *x, const u8 *c, u8 *m, u32 bytes) { ECRYPT_encrypt_bytes(x, c, m, bytes); } void ECRYPT_keystream_bytes(ECRYPT_ctx *x, u8 *stream, u32 bytes) { u32 i; for (i = 0; i < bytes; ++i) stream[i] = 0; ECRYPT_encrypt_bytes(x, stream, stream, bytes); }