diff --git a/Cryptography/Kuznyechik/C++/Description.md b/Cryptography/Kuznyechik/C++/Description.md
new file mode 100644
index 000000000..d137ee078
--- /dev/null
+++ b/Cryptography/Kuznyechik/C++/Description.md
@@ -0,0 +1,9 @@
+# Kuznyechik cipher
+
+Kuznyechik (Russian: Кузнечик, literally "grasshopper") is a symmetric block cipher. It has a block size of 128 bits and key length of 256 bits. It is defined in the National Standard of the Russian Federation GOST R 34.12-2015 in English and also in RFC 7801.
+
+The name of the cipher can be translated from Russian as grasshopper, however, the standard explicitly says that the English name for the cipher is Kuznyechik (/kʊznˈɛtʃɪk/). The designers claim that by naming the cipher Kuznyechik they follow the trend of difficult to pronounce algorithm names set up by Rijndael and Keccak. There is also a rumor that the cipher was named after its creators: A.S.Kuzmin, A.A.Nechaev and Company (Russian: Кузьмин, Нечаев и Компания).
+
+The standard GOST R 34.12-2015 defines the new cipher in addition to the old GOST block cipher (now called Magma) as one and does not declare the old cipher obsolete.
+
+Kuznyechik is based on a substitution-permutation network, though the key schedule employs a Feistel network.
\ No newline at end of file
diff --git a/Cryptography/Kuznyechik/C++/Kuznyechik.cpp b/Cryptography/Kuznyechik/C++/Kuznyechik.cpp
new file mode 100644
index 000000000..a151534b0
--- /dev/null
+++ b/Cryptography/Kuznyechik/C++/Kuznyechik.cpp
@@ -0,0 +1,162 @@
+#include "kuznechik.h"
+#include <cstring>
+
+constexpr unsigned char Kuznechik::Pi[256];
+constexpr unsigned char Kuznechik::revPi[256];
+constexpr unsigned char Kuznechik::koef[16];
+
+uint8_t *Kuznechik::encrypt(const uint8_t *key, const uint8_t *plaintext)
+{
+    expandKey(key, key + BLOCK_SIZE);
+    uint8_t* res = new uint8_t[BLOCK_SIZE];
+    _encrypt(plaintext, res);
+    return res;
+}
+
+uint8_t *Kuznechik::decrypt(const uint8_t *key, const uint8_t *ciphertext)
+{
+    expandKey(key, key + BLOCK_SIZE);
+    uint8_t* res = new uint8_t[BLOCK_SIZE];
+    _decrypt(ciphertext, res);
+    return res;
+}
+
+void Kuznechik::_encrypt(const uint8_t *in, uint8_t *out)
+{
+
+    std::memcpy(out, in, BLOCK_SIZE);
+    for (int i = 0; i < 9; ++i) {
+        transfX(iterKey[i], out, out);
+        transfS(out, out);
+        transfL(out, out);
+    }
+    transfX(out, iterKey[9], out);
+}
+
+void Kuznechik::_decrypt(const uint8_t *in, uint8_t *out)
+{
+    std::memcpy(out, in, BLOCK_SIZE);
+    transfX(out, iterKey[9], out);
+    for (int i = 8; i >= 0; --i) {
+        transfRevL(out, out);
+        transfRevS(out, out);
+        transfX(iterKey[i], out, out);
+    }
+}
+
+void Kuznechik::transfX(const uint8_t *a, const uint8_t *b, uint8_t *c)
+{
+    for (int i = 0; i < BLOCK_SIZE; ++i) c[i] = a[i] ^ b[i];
+}
+
+void Kuznechik::transfS(const uint8_t *in, uint8_t* out)
+{
+    for (int i = 0; i < BLOCK_SIZE; ++i) out[i] = Pi[in[i]];
+}
+
+void Kuznechik::transfRevS(const uint8_t *in, uint8_t *out)
+{
+    for (int i = 0; i < BLOCK_SIZE; ++i) out[i] = revPi[in[i]];
+}
+
+void Kuznechik::transfR(uint8_t *vector)
+{
+        uint8_t a15 = 0;
+        uint8_t temp[16];
+        for (int i = 15; i >= 0; i--)
+        {
+            temp[i - 1] = vector[i];
+            a15 ^= gfMul(vector[i], koef[i]);
+        }
+        temp[15] = a15;
+        memcpy(vector, temp, BLOCK_SIZE);
+}
+
+void Kuznechik::transfRevR(uint8_t *vector)
+{
+
+        uint8_t a0;
+        a0 = vector[15];
+        uint8_t temp[16];
+        for (int i = 0; i < 16; i++)
+        {
+            temp[i] = vector[i - 1];
+            a0 ^= gfMul(temp[i], koef[i]);
+        }
+        temp[0] = a0;
+        memcpy(vector, temp, BLOCK_SIZE);
+}
+
+void Kuznechik::transfL(const uint8_t *in, uint8_t *out)
+{
+    std::memcpy(out, in, BLOCK_SIZE);
+    for (int i = 0; i < 16; ++i) transfR(out);
+}
+
+void Kuznechik::transfRevL(const uint8_t *in, uint8_t *out)
+{
+    std::memcpy(out, in, BLOCK_SIZE);
+    for (int i = 0; i < 16; ++i) transfRevR(out);
+}
+
+void Kuznechik::F(const uint8_t *in1, const uint8_t *in2, uint8_t *out1, uint8_t *out2, const uint8_t *iterConst)
+{
+    uint8_t internal[BLOCK_SIZE];
+    std::memcpy(out2, in1, BLOCK_SIZE);
+    transfX(in1, iterConst, internal);
+    transfS(internal, internal);
+    transfL(internal, internal);
+    transfX(internal, in2, out1);
+}
+
+void Kuznechik::expandKey(const uint8_t *k1, const uint8_t *k2)
+{
+    uint8_t it1[64];
+    uint8_t it2[64];
+    uint8_t it3[64];
+    uint8_t it4[64];
+    getConsts();
+    memcpy(iterKey[0], k1, 64);
+    memcpy(iterKey[1], k2, 64);
+    memcpy(it1, k1, 64);
+    memcpy(it2, k2, 64);
+    for (int i = 0; i < 4; i++)
+        {
+            F(it1, it2, it3, it4, iterConsts[0 + 8 * i]);
+            F(it3, it4, it1, it2, iterConsts[1 + 8 * i]);
+            F(it1, it2, it3, it4, iterConsts[2 + 8 * i]);
+            F(it3, it4, it1, it2, iterConsts[3 + 8 * i]);
+            F(it1, it2, it3, it4, iterConsts[4 + 8 * i]);
+            F(it3, it4, it1, it2, iterConsts[5 + 8 * i]);
+            F(it1, it2, it3, it4, iterConsts[6 + 8 * i]);
+            F(it3, it4, it1, it2, iterConsts[7 + 8 * i]);
+            memcpy(iterKey[2 * i + 2], it1, 64);
+            memcpy(iterKey[2 * i + 3], it2, 64);
+        }
+}
+
+void Kuznechik::getConsts()
+{
+    uint8_t iter_num[32][16];
+    for (int i = 0; i < 32; i++)
+    {
+        std::memset(iter_num[i], 0, BLOCK_SIZE);
+        iter_num[i][0] = i+1;
+    }
+    for (int i = 0; i < 32; i++)
+         transfL(iter_num[i], iterConsts[i]);
+}
+
+uint8_t Kuznechik::gfMul(uint8_t a, uint8_t b)
+{
+    uint8_t res = 0;
+    uint8_t h = 0;
+    for (int i = 0; i < BLOCK_SIZE; ++i) {
+        if (b & 1) res ^= a;
+        h = a & 0b10000000;
+        a <<= 1;
+        if (h) a ^= 0b11000011;
+        b >>= 1;
+    }
+    return res;
+}