From c304e13550f0ffadcf9f861f98f963bd00159c26 Mon Sep 17 00:00:00 2001
From: "ivan.fedorov" <ivan.fedorov@demlabs.net>
Date: Thu, 30 Apr 2020 22:30:18 +0300
Subject: [PATCH] salsa implemented

---
 CMakeLists.txt                          |   2 +
 include/dap_enc_key.h                   |   2 +-
 include/dap_enc_salsa2012.h             |  34 +++
 src/dap_enc_key.c                       |  22 +-
 src/dap_enc_salsa2012.c                 | 131 ++++++++++++
 src/ringct20/ringct20_params.c          |   2 +-
 src/salsa2012/common_salsa.h            | 263 ++++++++++++++++++++++++
 src/salsa2012/core_salsa_ref.c          | 116 +++++++++++
 src/salsa2012/crypto_core_salsa2012.h   |  35 ++++
 src/salsa2012/crypto_stream_salsa2012.h |  50 +++++
 src/salsa2012/stream_salsa2012.c        |  26 +++
 src/salsa2012/stream_salsa2012_ref.c    | 124 +++++++++++
 src/salsa2012/utils.h                   |   9 +
 test/crypto/main.c                      |   6 +-
 14 files changed, 815 insertions(+), 7 deletions(-)
 create mode 100644 include/dap_enc_salsa2012.h
 create mode 100644 src/dap_enc_salsa2012.c
 create mode 100644 src/salsa2012/common_salsa.h
 create mode 100644 src/salsa2012/core_salsa_ref.c
 create mode 100644 src/salsa2012/crypto_core_salsa2012.h
 create mode 100644 src/salsa2012/crypto_stream_salsa2012.h
 create mode 100644 src/salsa2012/stream_salsa2012.c
 create mode 100644 src/salsa2012/stream_salsa2012_ref.c
 create mode 100644 src/salsa2012/utils.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index adf7711..9b83fb9 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,6 +32,7 @@ file( GLOB CRYPTO_SRCS
       src/oaes/*.c
       src/blowfish/*.c
       src/GOST/*.c
+      src/salsa2012/*.c
       src/sha3/*.c
       src/msrln/*.c
       src/defeo_scheme/*.c
@@ -49,6 +50,7 @@ file( GLOB CRYPTO_HEADERS
       src/oaes/*.h
       src/blowfish/*.h
       src/GOST/*.h
+      src/salsa2012/*.h
       src/sha3/*.h
       src/msrln/*.h
       src/defeo_scheme/*.h
diff --git a/include/dap_enc_key.h b/include/dap_enc_key.h
index 145fb27..8f05eff 100755
--- a/include/dap_enc_key.h
+++ b/include/dap_enc_key.h
@@ -241,7 +241,7 @@ extern "C" {
 int dap_enc_key_init(void);
 void dap_enc_key_deinit(void);
 
-char *dap_enc_get_type_name(dap_enc_key_type_t key_type);
+const char *dap_enc_get_type_name(dap_enc_key_type_t a_key_type);
 size_t dap_enc_key_get_enc_size(dap_enc_key_t * a_key, const size_t buf_in_size);
 size_t dap_enc_key_get_dec_size(dap_enc_key_t * a_key, const size_t buf_in_size);
 
diff --git a/include/dap_enc_salsa2012.h b/include/dap_enc_salsa2012.h
new file mode 100644
index 0000000..de2e7de
--- /dev/null
+++ b/include/dap_enc_salsa2012.h
@@ -0,0 +1,34 @@
+#ifndef _DAP_ENC_SALSA2012_H_
+#define _DAP_ENC_SALSA2012_H_
+
+#include <stddef.h>
+#include "dap_enc_key.h"
+#include "salsa2012/crypto_stream_salsa2012.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void dap_enc_salsa2012_key_delete(struct dap_enc_key *a_key);
+void dap_enc_salsa2012_key_generate(struct dap_enc_key * a_key, const void *kex_buf,
+        size_t kex_size, const void * seed, size_t seed_size, size_t key_size);
+//------salsa2012---------
+void dap_enc_salsa2012_key_new(struct dap_enc_key * a_key);
+
+size_t dap_enc_salsa2012_calc_decode_size(const size_t size_in);
+size_t dap_enc_salsa2012_calc_encode_size(const size_t size_in);
+
+size_t dap_enc_salsa2012_decrypt(struct dap_enc_key * a_key, const void * a_in, size_t a_in_size, void ** a_out);
+size_t dap_enc_salsa2012_encrypt(struct dap_enc_key * a_key, const void * a_in, size_t a_in_size, void ** a_out);
+
+// Writes result ( out ) in already allocated buffer
+size_t dap_enc_salsa2012_decrypt_fast(struct dap_enc_key * a_key, const void * a_in,
+        size_t a_in_size, void * buf_out, size_t buf_out_size);
+// Writes result ( out ) in already allocated buffer
+size_t dap_enc_salsa2012_encrypt_fast(struct dap_enc_key * a_key, const void * a_in,
+        size_t a_in_size, void * buf_out, size_t buf_out_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/dap_enc_key.c b/src/dap_enc_key.c
index 55258d7..4d0812b 100755
--- a/src/dap_enc_key.c
+++ b/src/dap_enc_key.c
@@ -166,6 +166,22 @@ struct dap_enc_key_callbacks{
         .sign_get = NULL,
         .sign_verify = NULL
     },
+    [DAP_ENC_KEY_TYPE_SALSA2012]={
+        .name = "SALSA2012",
+        .enc = dap_enc_salsa2012_encrypt,
+        .enc_na = dap_enc_salsa2012_encrypt_fast ,
+        .dec = dap_enc_salsa2012_decrypt,
+        .dec_na = dap_enc_salsa2012_decrypt_fast ,
+        .new_callback = dap_enc_salsa2012_key_new,
+        .delete_callback = dap_enc_salsa2012_key_delete,
+        .new_generate_callback = dap_enc_salsa2012_key_generate,
+        .gen_key_public = NULL,
+        .gen_key_public_size = NULL,
+        .enc_out_size = dap_enc_salsa2012_calc_encode_size,
+        .dec_out_size = dap_enc_salsa2012_calc_decode_size,
+        .sign_get = NULL,
+        .sign_verify = NULL
+    },
 
     [DAP_ENC_KEY_TYPE_MSRLN] = {
         .name = "MSRLN",
@@ -750,10 +766,10 @@ size_t dap_enc_key_get_dec_size(dap_enc_key_t * a_key, const size_t buf_in_size)
     return 0;
 }
 
-char *dap_enc_get_type_name(dap_enc_key_type_t key_type)
+const char *dap_enc_get_type_name(dap_enc_key_type_t a_key_type)
 {
-    if(s_callbacks[key_type].name) {
-        return s_callbacks[key_type].name;
+    if(s_callbacks[a_key_type].name) {
+        return s_callbacks[a_key_type].name;
     }
     log_it(L_ERROR, "name not realize for current key type");
     return 0;
diff --git a/src/dap_enc_salsa2012.c b/src/dap_enc_salsa2012.c
new file mode 100644
index 0000000..767f9fb
--- /dev/null
+++ b/src/dap_enc_salsa2012.c
@@ -0,0 +1,131 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "dap_enc_salsa2012.h"
+#include "dap_common.h"
+#include "rand/dap_rand.h"
+#include "sha3/KeccakHash.h"
+
+#define LOG_TAG "dap_enc_salsa2012"
+#define SALSA20_KEY_SIZE 32
+#define SALSA20_NONCE_SIZE 8
+
+void dap_enc_salsa2012_key_generate(struct dap_enc_key * a_key, const void *kex_buf,
+        size_t kex_size, const void * seed, size_t seed_size, size_t key_size)
+{
+    if(key_size < SALSA20_KEY_SIZE)
+    {
+        log_it(L_ERROR, "SALSA20 key cannot be less than 32 bytes.");
+    }
+    a_key->last_used_timestamp = time(NULL);
+
+
+    a_key->priv_key_data_size = SALSA20_KEY_SIZE;
+    a_key->priv_key_data = DAP_NEW_SIZE(uint8_t, key_size);
+
+    Keccak_HashInstance Keccak_ctx;
+    Keccak_HashInitialize(&Keccak_ctx, 1088,  512, SALSA20_KEY_SIZE*8, 0x06);
+    Keccak_HashUpdate(&Keccak_ctx, kex_buf, kex_size*8);
+    if(seed_size)
+        Keccak_HashUpdate(&Keccak_ctx, seed, seed_size*8);
+    Keccak_HashFinal(&Keccak_ctx, a_key->priv_key_data);
+}
+
+void dap_enc_salsa2012_key_delete(struct dap_enc_key *a_key)
+{
+    if(a_key->priv_key_data != NULL)
+    {
+        randombytes(a_key->priv_key_data,a_key->priv_key_data_size);
+        DAP_DELETE(a_key->priv_key_data);
+    }
+    a_key->priv_key_data_size = 0;
+}
+//------SALSA2012-----------
+void dap_enc_salsa2012_key_new(struct dap_enc_key * a_key)
+{
+    a_key->_inheritor = NULL;
+    a_key->_inheritor_size = 0;
+    a_key->type = DAP_ENC_KEY_TYPE_SALSA2012;
+    a_key->enc = dap_enc_salsa2012_encrypt;
+    a_key->dec = dap_enc_salsa2012_decrypt;
+    a_key->enc_na = dap_enc_salsa2012_encrypt_fast;
+    a_key->dec_na = dap_enc_salsa2012_decrypt_fast;
+}
+
+
+size_t dap_enc_salsa2012_decrypt(struct dap_enc_key *a_key, const void * a_in, size_t a_in_size, void ** a_out)
+{
+    size_t a_out_size = a_in_size - SALSA20_NONCE_SIZE;
+    if(a_out_size <= 0) {
+        log_it(L_ERROR, "salsa2012 decryption ct with iv must be more than kBlockLen89 bytes");
+        return 0;
+    }
+    *a_out = DAP_NEW_SIZE(uint8_t, a_in_size - SALSA20_NONCE_SIZE);
+    a_out_size = dap_enc_salsa2012_decrypt_fast(a_key, a_in, a_in_size, *a_out, a_out_size);
+    if(a_out_size == 0)
+        DAP_DEL_Z(*a_out);
+    return a_out_size;
+}
+
+size_t dap_enc_salsa2012_encrypt(struct dap_enc_key * a_key, const void * a_in, size_t a_in_size, void ** a_out)
+{
+    if(a_in_size <= 0) {
+        log_it(L_ERROR, "gost ofb encryption pt cannot be 0 bytes");
+        return 0;
+    }
+    size_t a_out_size = a_in_size + SALSA20_NONCE_SIZE;
+    *a_out = DAP_NEW_SIZE(uint8_t, a_out_size);
+    a_out_size = dap_enc_salsa2012_encrypt_fast(a_key, a_in, a_in_size, *a_out, a_out_size);
+    if(a_out_size == 0)
+        DAP_DEL_Z(*a_out);
+    return a_out_size;
+}
+
+size_t dap_enc_salsa2012_calc_encode_size(const size_t size_in)
+{
+    return size_in + SALSA20_NONCE_SIZE;
+}
+
+size_t dap_enc_salsa2012_calc_decode_size(const size_t size_in)
+{
+    if(size_in <= SALSA20_NONCE_SIZE) {
+        log_it(L_ERROR, "salsa2012 decryption size_in ct with iv must be more than kBlockLen89 bytes");
+        return 0;
+    }
+    return size_in - SALSA20_NONCE_SIZE;
+}
+
+size_t dap_enc_salsa2012_decrypt_fast(struct dap_enc_key *a_key, const void * a_in,
+        size_t a_in_size, void * a_out, size_t buf_out_size) {
+    size_t a_out_size = a_in_size - SALSA20_NONCE_SIZE;
+    if(a_out_size > buf_out_size) {
+        log_it(L_ERROR, "salsa2012 fast_decryption too small buf_out_size");
+        return 0;
+    }
+
+    //memcpy(nonce, a_in, SALSA20_NONCE_SIZE);
+    crypto_stream_salsa2012_xor(a_out, a_in + SALSA20_NONCE_SIZE, a_in_size - SALSA20_NONCE_SIZE, a_in, a_key->priv_key_data);
+    return a_out_size;
+}
+
+size_t dap_enc_salsa2012_encrypt_fast(struct dap_enc_key * a_key, const void * a_in, size_t a_in_size, void * a_out,size_t buf_out_size)
+{
+    size_t a_out_size = a_in_size + SALSA20_NONCE_SIZE;
+    if(a_out_size > buf_out_size) {
+        log_it(L_ERROR, "salsa2012 fast_encryption too small buf_out_size");
+        return 0;
+    }
+
+    if(randombytes(a_out, SALSA20_NONCE_SIZE) == 1)
+    {
+        log_it(L_ERROR, "failed to get SALSA20_NONCE_SIZE bytes nonce");
+        return 0;
+    }
+
+    crypto_stream_salsa2012_xor(a_out + SALSA20_NONCE_SIZE, a_in, a_in_size, a_out, a_key->priv_key_data);
+    return a_out_size;
+ }
+
diff --git a/src/ringct20/ringct20_params.c b/src/ringct20/ringct20_params.c
index c55598f..077221e 100644
--- a/src/ringct20/ringct20_params.c
+++ b/src/ringct20/ringct20_params.c
@@ -74,7 +74,7 @@ uint8_t H_bpoly_MAXSEC[14][NEWHOPE_POLYBYTES] = {
 #elif (NEWHOPE_N == 1024)
 #error "NEWHOPE_N must be either 512 or 1024.. NEWHOPE_N == 1024 not implemented yet"
 #elif
-#error "NEWHOPE_N must be either 512 or 1024..
+#error "NEWHOPE_N must be either 512 or 1024.."
 #endif
 
 bool ringct20_params_init(ringct20_param_t *ringct20_p, DAP_RINGCT20_SIGN_SECURITY kind)//, const int wLen)
diff --git a/src/salsa2012/common_salsa.h b/src/salsa2012/common_salsa.h
new file mode 100644
index 0000000..5f45c9a
--- /dev/null
+++ b/src/salsa2012/common_salsa.h
@@ -0,0 +1,263 @@
+#ifndef common_SALSA_H
+#define common_SALSA_H 1
+
+#if !defined(_MSC_VER) && !defined(DEV_MODE) && 1
+# warning *** This is unstable, untested, development code.
+# warning It might not compile. It might not work as expected.
+# warning It might be totally insecure.
+# warning Do not use this except if you are planning to contribute code.
+# warning Use releases available at https://download.libsodium.org/libsodium/releases/ instead.
+# warning Alternatively, use the "stable" branch in the git repository.
+#endif
+
+#if !defined(_MSC_VER) && (!defined(CONFIGURED) || CONFIGURED != 1)
+# warning *** The library is being compiled using an undocumented method.
+# warning This is not supported. It has not been tested, it might not
+# warning work as expected, and performance is likely to be suboptimal.
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+//#include "private/quirks.h"
+
+#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1])
+
+#ifdef HAVE_TI_MODE
+# if defined(__SIZEOF_INT128__)
+typedef unsigned __int128 uint128_t;
+# else
+typedef unsigned uint128_t __attribute__((mode(TI)));
+# endif
+#endif
+
+#define ROTL32(X, B) rotl32((X), (B))
+static inline uint32_t
+rotl32(const uint32_t x, const int b)
+{
+    return (x << b) | (x >> (32 - b));
+}
+
+#define ROTL64(X, B) rotl64((X), (B))
+static inline uint64_t
+rotl64(const uint64_t x, const int b)
+{
+    return (x << b) | (x >> (64 - b));
+}
+
+#define ROTR32(X, B) rotr32((X), (B))
+static inline uint32_t
+rotr32(const uint32_t x, const int b)
+{
+    return (x >> b) | (x << (32 - b));
+}
+
+#define ROTR64(X, B) rotr64((X), (B))
+static inline uint64_t
+rotr64(const uint64_t x, const int b)
+{
+    return (x >> b) | (x << (64 - b));
+}
+
+#define LOAD64_LE(SRC) load64_le(SRC)
+static inline uint64_t
+load64_le(const uint8_t src[8])
+{
+#ifdef NATIVE_LITTLE_ENDIAN
+    uint64_t w;
+    memcpy(&w, src, sizeof w);
+    return w;
+#else
+    uint64_t w = (uint64_t) src[0];
+    w |= (uint64_t) src[1] <<  8;
+    w |= (uint64_t) src[2] << 16;
+    w |= (uint64_t) src[3] << 24;
+    w |= (uint64_t) src[4] << 32;
+    w |= (uint64_t) src[5] << 40;
+    w |= (uint64_t) src[6] << 48;
+    w |= (uint64_t) src[7] << 56;
+    return w;
+#endif
+}
+
+#define STORE64_LE(DST, W) store64_le((DST), (W))
+static inline void
+store64_le(uint8_t dst[8], uint64_t w)
+{
+#ifdef NATIVE_LITTLE_ENDIAN
+    memcpy(dst, &w, sizeof w);
+#else
+    dst[0] = (uint8_t) w; w >>= 8;
+    dst[1] = (uint8_t) w; w >>= 8;
+    dst[2] = (uint8_t) w; w >>= 8;
+    dst[3] = (uint8_t) w; w >>= 8;
+    dst[4] = (uint8_t) w; w >>= 8;
+    dst[5] = (uint8_t) w; w >>= 8;
+    dst[6] = (uint8_t) w; w >>= 8;
+    dst[7] = (uint8_t) w;
+#endif
+}
+
+#define LOAD32_LE(SRC) load32_le(SRC)
+static inline uint32_t
+load32_le(const uint8_t src[4])
+{
+#ifdef NATIVE_LITTLE_ENDIAN
+    uint32_t w;
+    memcpy(&w, src, sizeof w);
+    return w;
+#else
+    uint32_t w = (uint32_t) src[0];
+    w |= (uint32_t) src[1] <<  8;
+    w |= (uint32_t) src[2] << 16;
+    w |= (uint32_t) src[3] << 24;
+    return w;
+#endif
+}
+
+#define STORE32_LE(DST, W) store32_le((DST), (W))
+static inline void
+store32_le(uint8_t dst[4], uint32_t w)
+{
+#ifdef NATIVE_LITTLE_ENDIAN
+    memcpy(dst, &w, sizeof w);
+#else
+    dst[0] = (uint8_t) w; w >>= 8;
+    dst[1] = (uint8_t) w; w >>= 8;
+    dst[2] = (uint8_t) w; w >>= 8;
+    dst[3] = (uint8_t) w;
+#endif
+}
+
+/* ----- */
+
+#define LOAD64_BE(SRC) load64_be(SRC)
+static inline uint64_t
+load64_be(const uint8_t src[8])
+{
+#ifdef NATIVE_BIG_ENDIAN
+    uint64_t w;
+    memcpy(&w, src, sizeof w);
+    return w;
+#else
+    uint64_t w = (uint64_t) src[7];
+    w |= (uint64_t) src[6] <<  8;
+    w |= (uint64_t) src[5] << 16;
+    w |= (uint64_t) src[4] << 24;
+    w |= (uint64_t) src[3] << 32;
+    w |= (uint64_t) src[2] << 40;
+    w |= (uint64_t) src[1] << 48;
+    w |= (uint64_t) src[0] << 56;
+    return w;
+#endif
+}
+
+#define STORE64_BE(DST, W) store64_be((DST), (W))
+static inline void
+store64_be(uint8_t dst[8], uint64_t w)
+{
+#ifdef NATIVE_BIG_ENDIAN
+    memcpy(dst, &w, sizeof w);
+#else
+    dst[7] = (uint8_t) w; w >>= 8;
+    dst[6] = (uint8_t) w; w >>= 8;
+    dst[5] = (uint8_t) w; w >>= 8;
+    dst[4] = (uint8_t) w; w >>= 8;
+    dst[3] = (uint8_t) w; w >>= 8;
+    dst[2] = (uint8_t) w; w >>= 8;
+    dst[1] = (uint8_t) w; w >>= 8;
+    dst[0] = (uint8_t) w;
+#endif
+}
+
+#define LOAD32_BE(SRC) load32_be(SRC)
+static inline uint32_t
+load32_be(const uint8_t src[4])
+{
+#ifdef NATIVE_BIG_ENDIAN
+    uint32_t w;
+    memcpy(&w, src, sizeof w);
+    return w;
+#else
+    uint32_t w = (uint32_t) src[3];
+    w |= (uint32_t) src[2] <<  8;
+    w |= (uint32_t) src[1] << 16;
+    w |= (uint32_t) src[0] << 24;
+    return w;
+#endif
+}
+
+#define STORE32_BE(DST, W) store32_be((DST), (W))
+static inline void
+store32_be(uint8_t dst[4], uint32_t w)
+{
+#ifdef NATIVE_BIG_ENDIAN
+    memcpy(dst, &w, sizeof w);
+#else
+    dst[3] = (uint8_t) w; w >>= 8;
+    dst[2] = (uint8_t) w; w >>= 8;
+    dst[1] = (uint8_t) w; w >>= 8;
+    dst[0] = (uint8_t) w;
+#endif
+}
+
+#define XOR_BUF(OUT, IN, N) xor_buf((OUT), (IN), (N))
+static inline void
+xor_buf(unsigned char *out, const unsigned char *in, size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        out[i] ^= in[i];
+    }
+}
+
+#if !defined(__clang__) && !defined(__GNUC__)
+# ifdef __attribute__
+#  undef __attribute__
+# endif
+# define __attribute__(a)
+#endif
+
+#ifndef CRYPTO_ALIGN
+# if defined(__INTEL_COMPILER) || defined(_MSC_VER)
+#  define CRYPTO_ALIGN(x) __declspec(align(x))
+# else
+#  define CRYPTO_ALIGN(x) __attribute__ ((aligned(x)))
+# endif
+#endif
+
+#if defined(_MSC_VER) && \
+    (defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86))
+
+# include <intrin.h>
+
+# define HAVE_INTRIN_H    1
+# define HAVE_MMINTRIN_H  1
+# define HAVE_EMMINTRIN_H 1
+# define HAVE_PMMINTRIN_H 1
+# define HAVE_TMMINTRIN_H 1
+# define HAVE_SMMINTRIN_H 1
+# define HAVE_AVXINTRIN_H 1
+# if _MSC_VER >= 1600
+#  define HAVE_WMMINTRIN_H 1
+# endif
+# if _MSC_VER >= 1700 && defined(_M_X64)
+#  define HAVE_AVX2INTRIN_H 1
+# endif
+#elif defined(HAVE_INTRIN_H)
+# include <intrin.h>
+#endif
+
+#ifdef HAVE_LIBCTGRIND
+extern void ct_poison  (const void *, size_t);
+extern void ct_unpoison(const void *, size_t);
+# define POISON(X, L)   ct_poison((X), (L))
+# define UNPOISON(X, L) ct_unpoison((X), (L))
+#else
+# define POISON(X, L)   (void) 0
+# define UNPOISON(X, L) (void) 0
+#endif
+
+#endif
diff --git a/src/salsa2012/core_salsa_ref.c b/src/salsa2012/core_salsa_ref.c
new file mode 100644
index 0000000..0caccc3
--- /dev/null
+++ b/src/salsa2012/core_salsa_ref.c
@@ -0,0 +1,116 @@
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "crypto_core_salsa2012.h"
+#include "common_salsa.h"
+
+/** @brief main salsa code
+ * @param[out] out --
+ * @param[in] rounds main rounds number
+ * @param[in] c constants for x0,5,10,15 refer to NULL, than uses fixed const
+ * @param[in] k 32 bytes key
+ * @param[in] in 16 bytes input generated from nonce and counts
+ */
+static void
+crypto_core_salsa(unsigned char *out, const unsigned char *in,
+                  const unsigned char *k, const unsigned char *c,
+                  const int rounds)
+{
+    uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
+        x15;
+    uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14,
+        j15;
+    int i;
+
+    j0  = x0  = 0x61707865;
+    j5  = x5  = 0x3320646e;
+    j10 = x10 = 0x79622d32;
+    j15 = x15 = 0x6b206574;
+    if (c != NULL) {
+        j0  = x0  = LOAD32_LE(c + 0);
+        j5  = x5  = LOAD32_LE(c + 4);
+        j10 = x10 = LOAD32_LE(c + 8);
+        j15 = x15 = LOAD32_LE(c + 12);
+    }
+    j1  = x1  = LOAD32_LE(k + 0);
+    j2  = x2  = LOAD32_LE(k + 4);
+    j3  = x3  = LOAD32_LE(k + 8);
+    j4  = x4  = LOAD32_LE(k + 12);
+    j11 = x11 = LOAD32_LE(k + 16);
+    j12 = x12 = LOAD32_LE(k + 20);
+    j13 = x13 = LOAD32_LE(k + 24);
+    j14 = x14 = LOAD32_LE(k + 28);
+
+    j6  = x6  = LOAD32_LE(in + 0);
+    j7  = x7  = LOAD32_LE(in + 4);
+    j8  = x8  = LOAD32_LE(in + 8);
+    j9  = x9  = LOAD32_LE(in + 12);
+
+    for (i = 0; i < rounds; i += 2) {
+        x4  ^= ROTL32(x0  + x12, 7);
+        x8  ^= ROTL32(x4  + x0, 9);
+        x12 ^= ROTL32(x8  + x4, 13);
+        x0  ^= ROTL32(x12 + x8, 18);
+        x9  ^= ROTL32(x5  + x1, 7);
+        x13 ^= ROTL32(x9  + x5, 9);
+        x1  ^= ROTL32(x13 + x9, 13);
+        x5  ^= ROTL32(x1  + x13, 18);
+        x14 ^= ROTL32(x10 + x6, 7);
+        x2  ^= ROTL32(x14 + x10, 9);
+        x6  ^= ROTL32(x2  + x14, 13);
+        x10 ^= ROTL32(x6  + x2, 18);
+        x3  ^= ROTL32(x15 + x11, 7);
+        x7  ^= ROTL32(x3  + x15, 9);
+        x11 ^= ROTL32(x7  + x3, 13);
+        x15 ^= ROTL32(x11 + x7, 18);
+        x1  ^= ROTL32(x0  + x3, 7);
+        x2  ^= ROTL32(x1  + x0, 9);
+        x3  ^= ROTL32(x2  + x1, 13);
+        x0  ^= ROTL32(x3  + x2, 18);
+        x6  ^= ROTL32(x5  + x4, 7);
+        x7  ^= ROTL32(x6  + x5, 9);
+        x4  ^= ROTL32(x7  + x6, 13);
+        x5  ^= ROTL32(x4  + x7, 18);
+        x11 ^= ROTL32(x10 + x9, 7);
+        x8  ^= ROTL32(x11 + x10, 9);
+        x9  ^= ROTL32(x8  + x11, 13);
+        x10 ^= ROTL32(x9  + x8, 18);
+        x12 ^= ROTL32(x15 + x14, 7);
+        x13 ^= ROTL32(x12 + x15, 9);
+        x14 ^= ROTL32(x13 + x12, 13);
+        x15 ^= ROTL32(x14 + x13, 18);
+    }
+    STORE32_LE(out + 0,  x0  + j0);
+    STORE32_LE(out + 4,  x1  + j1);
+    STORE32_LE(out + 8,  x2  + j2);
+    STORE32_LE(out + 12, x3  + j3);
+    STORE32_LE(out + 16, x4  + j4);
+    STORE32_LE(out + 20, x5  + j5);
+    STORE32_LE(out + 24, x6  + j6);
+    STORE32_LE(out + 28, x7  + j7);
+    STORE32_LE(out + 32, x8  + j8);
+    STORE32_LE(out + 36, x9  + j9);
+    STORE32_LE(out + 40, x10 + j10);
+    STORE32_LE(out + 44, x11 + j11);
+    STORE32_LE(out + 48, x12 + j12);
+    STORE32_LE(out + 52, x13 + j13);
+    STORE32_LE(out + 56, x14 + j14);
+    STORE32_LE(out + 60, x15 + j15);
+}
+
+int
+crypto_core_salsa20(unsigned char *out, const unsigned char *in,
+                    const unsigned char *k, const unsigned char *c)
+{
+    crypto_core_salsa(out, in, k, c, 20);
+    return 0;
+}
+int
+crypto_core_salsa2012(unsigned char *out, const unsigned char *in,
+                      const unsigned char *k, const unsigned char *c)
+{
+    crypto_core_salsa(out, in, k, c, 12);
+    return 0;
+}
+
diff --git a/src/salsa2012/crypto_core_salsa2012.h b/src/salsa2012/crypto_core_salsa2012.h
new file mode 100644
index 0000000..956024f
--- /dev/null
+++ b/src/salsa2012/crypto_core_salsa2012.h
@@ -0,0 +1,35 @@
+#ifndef crypto_core_salsa2012_H
+#define crypto_core_salsa2012_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define crypto_core_salsa2012_OUTPUTBYTES 64U
+
+size_t crypto_core_salsa2012_outputbytes(void);
+
+#define crypto_core_salsa2012_INPUTBYTES 16U
+
+size_t crypto_core_salsa2012_inputbytes(void);
+
+#define crypto_core_salsa2012_KEYBYTES 32U
+
+size_t crypto_core_salsa2012_keybytes(void);
+
+#define crypto_core_salsa2012_CONSTBYTES 16U
+
+size_t crypto_core_salsa2012_constbytes(void);
+
+
+int crypto_core_salsa2012(unsigned char *out, const unsigned char *in,
+                          const unsigned char *k, const unsigned char *c)
+            __attribute__ ((nonnull(1, 2, 3)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/salsa2012/crypto_stream_salsa2012.h b/src/salsa2012/crypto_stream_salsa2012.h
new file mode 100644
index 0000000..d6cc6e2
--- /dev/null
+++ b/src/salsa2012/crypto_stream_salsa2012.h
@@ -0,0 +1,50 @@
+#ifndef crypto_stream_salsa2012_H
+#define crypto_stream_salsa2012_H
+
+/*
+ *  WARNING: This is just a stream cipher. It is NOT authenticated encryption.
+ *  While it provides some protection against eavesdropping, it does NOT
+ *  provide any security against active attacks.
+ *  Unless you know what you're doing, what you are looking for is probably
+ *  the crypto_box functions.
+ */
+
+#include <stddef.h>
+#include "utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define crypto_stream_salsa2012_KEYBYTES 32U
+
+size_t crypto_stream_salsa2012_keybytes(void);
+
+#define crypto_stream_salsa2012_NONCEBYTES 8U
+
+size_t crypto_stream_salsa2012_noncebytes(void);
+
+#define crypto_stream_salsa2012_MESSAGEBYTES_MAX SODIUM_SIZE_MAX
+
+size_t crypto_stream_salsa2012_messagebytes_max(void);
+
+
+int crypto_stream_salsa2012(unsigned char *c, unsigned long long clen,
+                            const unsigned char *n, const unsigned char *k)
+            __attribute__ ((nonnull));
+
+
+int crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m,
+                                unsigned long long mlen, const unsigned char *n,
+                                const unsigned char *k)
+            __attribute__ ((nonnull));
+
+
+void crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES])
+            __attribute__ ((nonnull));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/salsa2012/stream_salsa2012.c b/src/salsa2012/stream_salsa2012.c
new file mode 100644
index 0000000..be62fe4
--- /dev/null
+++ b/src/salsa2012/stream_salsa2012.c
@@ -0,0 +1,26 @@
+#include "crypto_stream_salsa2012.h"
+#include "rand/dap_rand.h"
+
+size_t
+crypto_stream_salsa2012_keybytes(void)
+{
+    return crypto_stream_salsa2012_KEYBYTES;
+}
+
+size_t
+crypto_stream_salsa2012_noncebytes(void)
+{
+    return crypto_stream_salsa2012_NONCEBYTES;
+}
+
+size_t
+crypto_stream_salsa2012_messagebytes_max(void)
+{
+    return crypto_stream_salsa2012_MESSAGEBYTES_MAX;
+}
+
+void
+crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES])
+{
+    randombytes(k, crypto_stream_salsa2012_KEYBYTES);
+}
diff --git a/src/salsa2012/stream_salsa2012_ref.c b/src/salsa2012/stream_salsa2012_ref.c
new file mode 100644
index 0000000..5937c63
--- /dev/null
+++ b/src/salsa2012/stream_salsa2012_ref.c
@@ -0,0 +1,124 @@
+/*
+version 20140420
+D. J. Bernstein
+Public domain.
+*/
+
+#include <stdint.h>
+
+#include "crypto_core_salsa2012.h"
+#include "crypto_stream_salsa2012.h"
+#include "utils.h"
+
+
+/**
+ * @brief generate gamma bytes
+ * @param gamma bytes array
+ * @param gamma_len
+ * @param n nonce
+ * @param k key
+ * @return
+ */
+
+int
+crypto_stream_salsa2012(unsigned char *gamma, unsigned long long gamma_len,
+                        const unsigned char *n, const unsigned char *k)
+{
+    unsigned char in[16];
+    unsigned char block[64];
+    unsigned char kcopy[32];
+    unsigned int  i;
+    unsigned int  u;
+
+    if (!gamma_len) {
+        return 0;
+    }
+    for (i = 0; i < 32; ++i) {
+        kcopy[i] = k[i];
+    }
+    for (i = 0; i < 8; ++i) {
+        in[i] = n[i];
+    }
+    for (i = 8; i < 16; ++i) {
+        in[i] = 0;
+    }
+    while (gamma_len >= 64) {
+        crypto_core_salsa2012(gamma, in, kcopy, NULL);
+        u = 1;
+        for (i = 8; i < 16; ++i) {
+            u += (unsigned int)in[i];
+            in[i] = u;
+            u >>= 8;
+        }
+        gamma_len -= 64;
+        gamma += 64;
+    }
+    if (gamma_len) {
+        crypto_core_salsa2012(block, in, kcopy, NULL);
+        for (i = 0; i < (unsigned int)gamma_len; ++i) {
+            gamma[i] = block[i];
+        }
+    }
+//    sodium_memzero(block, sizeof block);//TODO
+//    sodium_memzero(kcopy, sizeof kcopy);
+
+    return 0;
+}
+/**
+ * @brief c = m ^ gamma
+ * @param c
+ * @param m
+ * @param mlen
+ * @param n nonce 8 bytes
+ * @param k
+ * @return
+ */
+int
+crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m,
+                            unsigned long long mlen, const unsigned char *n,
+                            const unsigned char *k)
+{
+    unsigned char in[16];
+    unsigned char block[64];
+    unsigned char kcopy[32];
+    unsigned int  i;
+    unsigned int  u;
+
+    if (!mlen) {
+        return 0;
+    }
+    for (i = 0; i < 32; ++i) {
+        kcopy[i] = k[i];
+    }
+    for (i = 0; i < 8; ++i) {
+        in[i] = n[i];
+    }
+    for (i = 8; i < 16; ++i) {
+        in[i] = 0;
+    }
+    while (mlen >= 64) {
+        crypto_core_salsa2012(block, in, kcopy, NULL);
+        for (i = 0; i < 64; ++i) {
+            c[i] = m[i] ^ block[i];
+        }
+        u = 1;
+        for (i = 8; i < 16; ++i) {
+            u += (unsigned int)in[i];
+            in[i] = u;
+            u >>= 8;
+        }
+        mlen -= 64;
+        c += 64;
+        m += 64;
+    }
+    if (mlen) {
+        crypto_core_salsa2012(block, in, kcopy, NULL);
+        for (i = 0; i < (unsigned int)mlen; ++i) {
+            c[i] = m[i] ^ block[i];
+        }
+    }
+//    sodium_memzero(block, sizeof block);//TODO
+//    sodium_memzero(kcopy, sizeof kcopy);
+
+    return 0;
+}
diff --git a/src/salsa2012/utils.h b/src/salsa2012/utils.h
new file mode 100644
index 0000000..d7ce028
--- /dev/null
+++ b/src/salsa2012/utils.h
@@ -0,0 +1,9 @@
+#ifndef sodium_utils_H
+#define sodium_utils_H
+
+#include <stddef.h>
+
+
+#define SODIUM_MIN(A, B) ((A) < (B) ? (A) : (B))
+#define SODIUM_SIZE_MAX SODIUM_MIN(UINT64_MAX, SIZE_MAX)
+#endif
diff --git a/test/crypto/main.c b/test/crypto/main.c
index dc0d542..075dc0a 100755
--- a/test/crypto/main.c
+++ b/test/crypto/main.c
@@ -18,8 +18,10 @@ int main(void)
  // switch off debug info from library
     dap_log_level_set(L_CRITICAL);
 
-    test_encypt_decrypt      (1000, DAP_ENC_KEY_TYPE_GOST_OFB,   32);
-    test_encypt_decrypt_fast (1000, DAP_ENC_KEY_TYPE_GOST_OFB,   32);
+    test_encypt_decrypt      (1000, DAP_ENC_KEY_TYPE_SALSA2012,  32);
+    test_encypt_decrypt_fast (1000, DAP_ENC_KEY_TYPE_SALSA2012,  32);
+    test_encypt_decrypt      (1000, DAP_ENC_KEY_TYPE_GOST_OFB,  32);
+    test_encypt_decrypt_fast (1000, DAP_ENC_KEY_TYPE_GOST_OFB,  32);
     test_encypt_decrypt      (1000, DAP_ENC_KEY_TYPE_KUZN_OFB,  32);
     test_encypt_decrypt_fast (1000, DAP_ENC_KEY_TYPE_KUZN_OFB,  32);
     return 0;
-- 
GitLab