diff --git a/CMakeLists.txt b/CMakeLists.txt
index 306ff5fa9d897c87af75919f5f92a489459821e3..e5cb645ee2df0d8096cd5aa3b86192ae7d318e3a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,6 +105,7 @@ set( AKRYPT_SOURCES
    source/ak_blom.c
    source/ak_kdf.c
    source/ak_encrypt.c
+   source/ak_belt_hash.c
 )
 
 # -------------------------------------------------------------------------------------------------- #
@@ -353,6 +354,7 @@ set ( ARITHMETIC_TESTS_LIST
       hash02
       kuznechik01
       mac-offset
+      belt-hash
     )
 
 if( AK_TESTS_GMP )
diff --git a/examples/tests/test-belt-hash.c b/examples/tests/test-belt-hash.c
new file mode 100644
index 0000000000000000000000000000000000000000..75fdc1dc5b9dd0097922f32d4e41b6909d223524
--- /dev/null
+++ b/examples/tests/test-belt-hash.c
@@ -0,0 +1,178 @@
+#include <libakrypt.h>
+#include <string.h>
+
+//подстановка битов
+#define H16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)\
+  0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h,\
+  0x##i, 0x##j, 0x##k, 0x##l, 0x##m, 0x##n, 0x##o, 0x##p
+
+int main() {
+  ak_uint8 X1[13] = { 
+    0xB1, 0x94, 0xBA, 0xC8, 0x0A, 0x08, 0xF5, 0x3B,
+    0x36, 0x6D, 0x00, 0x8E, 0x58
+  };
+  const ak_uint8 Y1[32] = {
+    H16(AB,EF,97,25,D4,C5,A8,35,97,A3,67,D1,44,94,CC,25),
+    H16(42,F2,0F,65,9D,DF,EC,C9,61,A3,EC,55,0C,BA,8C,75)
+  };
+  ak_uint8 X2[32] = { 
+    H16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4),
+    H16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D)
+  };
+  const ak_uint8 Y2[32] = {
+    H16(74,9E,4C,36,53,AE,CE,5E,48,DB,47,61,22,77,42,EB),
+    H16(6D,BE,13,F4,A8,0F,7B,EF,F1,A9,CF,8D,10,EE,77,86)
+  };
+  ak_uint8 X3[48] = { 
+    H16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4),
+    H16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D),
+    H16(5B,E3,D6,12,17,B9,61,81,FE,67,86,AD,71,6B,89,0B)
+  };
+  const ak_uint8 Y3[32] = {
+    H16(9D,02,EE,44,6F,B6,A2,9F,E5,C9,82,D4,B1,3A,F9,D3),
+    H16(E9,08,61,BC,4C,EF,27,CF,30,6B,FB,0B,17,4A,15,4A)
+  };
+
+  ak_uint8 success = 0;
+  ak_uint8 A[32] = {0};
+  struct hash ctx;
+
+  if (ak_libakrypt_create(NULL) != ak_true) {
+    ak_libakrypt_destroy();
+    return EXIT_FAILURE;
+  }
+
+  printf("--------------------Testing belt-hash----------------------\n"
+    "               -----------Test 1------------\n"
+    "Input:\n"
+    " > X1 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x\n"
+    "Expected output:\n"
+    " > Y1 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+    X1[0] , X1[1] , X1[2] , X1[3] , X1[4] , X1[5] , X1[6] , X1[7] ,
+    X1[8] , X1[9] , X1[10], X1[11], X1[12],
+    Y1[0] , Y1[1] , Y1[2] , Y1[3] , Y1[4] , Y1[5] , Y1[6] , Y1[7] ,
+    Y1[8] , Y1[9] , Y1[10], Y1[11], Y1[12], Y1[13], Y1[14], Y1[15],
+    Y1[16], Y1[17], Y1[18], Y1[19], Y1[20], Y1[21], Y1[22], Y1[23],
+    Y1[24], Y1[25], Y1[26], Y1[27], Y1[28], Y1[29], Y1[30], Y1[31]);
+
+  ak_hash_create_belt_hash( &ctx );
+  ak_hash_ptr( &ctx, X1, 13, A, 32 );
+  ak_hash_destroy( &ctx );
+
+  printf("Output:\n"
+    " > Y1 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+    A[0] , A[1] , A[2] , A[3] , A[4] , A[5] , A[6] , A[7] ,
+    A[8] , A[9] , A[10], A[11], A[12], A[13], A[14], A[15],
+    A[16], A[17], A[18], A[19], A[20], A[21], A[22], A[23],
+    A[24], A[25], A[26], A[27], A[28], A[29], A[30], A[31]);
+  
+  if(strncmp( (const char*)A, (const char*)Y1, 32) == 0) {
+    printf("Test 1 was successful\n\n");
+    success += 1;
+  }
+  else {
+    printf("Test 1 failed\n\n");
+  }
+
+  printf("               -----------Test 2------------\n"
+    "Input:\n"
+    " > X2 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "Expected output:\n"
+    " > Y2 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+    X2[0] , X2[1] , X2[2] , X2[3] , X2[4] , X2[5] , X2[6] , X2[7] ,
+    X2[8] , X2[9] , X2[10], X2[11], X2[12], X2[13], X2[14], X2[15],
+    X2[16], X2[17], X2[18], X2[19], X2[20], X2[21], X2[22], X2[23],
+    X2[24], X2[25], X2[26], X2[27], X2[28], X2[29], X2[30], X2[31],
+    Y2[0] , Y2[1] , Y2[2] , Y2[3] , Y2[4] , Y2[5] , Y2[6] , Y2[7] ,
+    Y2[8] , Y2[9] , Y2[10], Y2[11], Y2[12], Y2[13], Y2[14], Y2[15],
+    Y2[16], Y2[17], Y2[18], Y2[19], Y2[20], Y2[21], Y2[22], Y2[23],
+    Y2[24], Y2[25], Y2[26], Y2[27], Y2[28], Y2[29], Y2[30], Y2[31]);
+
+  ak_hash_create_belt_hash( &ctx );
+  ak_hash_ptr( &ctx, X2, 32, A, 32 );
+  ak_hash_destroy( &ctx );
+
+  printf("Output:\n"
+    " > Y2 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+    A[0] , A[1] , A[2] , A[3] , A[4] , A[5] , A[6] , A[7] ,
+    A[8] , A[9] , A[10], A[11], A[12], A[13], A[14], A[15],
+    A[16], A[17], A[18], A[19], A[20], A[21], A[22], A[23],
+    A[24], A[25], A[26], A[27], A[28], A[29], A[30], A[31]);
+  
+  if(strncmp((const char*)A, (const char*)Y2, 32) == 0) {
+    printf("Test 2 was successful\n\n");
+    success += 2;
+  }
+  else {
+    printf("Test 2 failed\n\n");
+  }
+
+  printf("               -----------Test 3------------\n"
+    "Input:\n"
+    " > X3 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "Expected output:\n"
+    " > Y3 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+    X3[0] , X3[1] , X3[2] , X3[3] , X3[4] , X3[5] , X3[6] , X3[7] ,
+    X3[8] , X3[9] , X3[10], X3[11], X3[12], X3[13], X3[14], X3[15],
+    X3[16], X3[17], X3[18], X3[19], X3[20], X3[21], X3[22], X3[23],
+    X3[24], X3[25], X3[26], X3[27], X3[28], X3[29], X3[30], X3[31],
+    X3[32], X3[33], X3[34], X3[35], X3[36], X3[37], X3[38], X3[39],
+    X3[40], X3[41], X3[42], X3[43], X3[44], X3[45], X3[46], X3[47],
+    Y3[0] , Y3[1] , Y3[2] , Y3[3] , Y3[4] , Y3[5] , Y3[6] , Y3[7] ,
+    Y3[8] , Y3[9] , Y3[10], Y3[11], Y3[12], Y3[13], Y3[14], Y3[15],
+    Y3[16], Y3[17], Y3[18], Y3[19], Y3[20], Y3[21], Y3[22], Y3[23],
+    Y3[24], Y3[25], Y3[26], Y3[27], Y3[28], Y3[29], Y3[30], Y3[31]);
+
+  ak_hash_create_belt_hash( &ctx );
+  ak_hash_ptr( &ctx, X3, 48, A, 32 );
+  ak_hash_destroy( &ctx );
+
+  ak_libakrypt_destroy();
+
+  printf("Output:\n"
+    " > Y3 = %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n"
+    "        %02x%02x%02x%02x %02x%02x%02x%02x "
+            "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+    A[0] , A[1] , A[2] , A[3] , A[4] , A[5] , A[6] , A[7] ,
+    A[8] , A[9] , A[10], A[11], A[12], A[13], A[14], A[15],
+    A[16], A[17], A[18], A[19], A[20], A[21], A[22], A[23],
+    A[24], A[25], A[26], A[27], A[28], A[29], A[30], A[31]);
+  
+  if(strncmp((const char*)A, (const char*)Y3, 32) == 0) {
+    printf("Test 3, was successful\n");
+    success += 4;
+  }
+  else {
+    printf("Test 3 failed\n");
+  }
+
+  if(success == 7) {
+    return EXIT_SUCCESS;
+  }
+  return EXIT_FAILURE;
+}
diff --git a/source/ak_belt_hash.c b/source/ak_belt_hash.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab0b3d3552d99301761f2776ca2dae574aafa0a1
--- /dev/null
+++ b/source/ak_belt_hash.c
@@ -0,0 +1,417 @@
+/* ----------------------------------------------------------------------------------------------- */
+/*                                                                                                 */
+/*  Реализация хэширования сообщения                                                               */
+/*  из Белорусского стандарта СТБ 34.101.31-2020                                                   */
+/*                                                                                                 */
+/* ----------------------------------------------------------------------------------------------- */
+
+#include <libakrypt-internal.h>
+
+//---------------------------------------------------------
+//----------------------belt-block-------------------------
+//---------------------------------------------------------
+
+//подстановка битов
+#define H16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)\
+  0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h,\
+  0x##i, 0x##j, 0x##k, 0x##l, 0x##m, 0x##n, 0x##o, 0x##p
+
+//базовая H
+static const ak_uint8 H[256] = {
+  H16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4),
+  H16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D),
+  H16(5B,E3,D6,12,17,B9,61,81,FE,67,86,AD,71,6B,89,0B),
+  H16(5C,B0,C0,FF,33,C3,56,B8,35,C4,05,AE,D8,E0,7F,99),
+  H16(E1,2B,DC,1A,E2,82,57,EC,70,3F,CC,F0,95,EE,8D,F1),
+  H16(C1,AB,76,38,9F,E6,78,CA,F7,C6,F8,60,D5,BB,9C,4F),
+  H16(F3,3C,65,7B,63,7C,30,6A,DD,4E,A7,79,9E,B2,3D,31),
+  H16(3E,98,B5,6E,27,D3,BC,CF,59,1E,18,1F,4C,5A,B7,93),
+  H16(E9,DE,E7,2C,8F,0C,0F,A6,2D,DB,49,F4,6F,73,96,47),
+  H16(06,07,53,16,ED,24,7A,37,39,CB,A3,83,03,A9,8B,F6),
+  H16(92,BD,9B,1C,E5,D1,41,01,54,45,FB,C9,5E,4D,0E,F2),
+  H16(68,20,80,AA,22,7D,64,2F,26,87,F9,34,90,40,55,11),
+  H16(BE,32,97,13,43,FC,9A,48,A0,2A,88,5F,19,4B,09,A1),
+  H16(7E,CD,A4,D0,15,44,AF,8C,A5,84,50,BF,66,D2,E8,8A),
+  H16(A2,D7,46,52,42,A8,DF,B3,69,74,C5,51,EB,23,29,21),
+  H16(D4,EF,D9,B4,3A,62,28,75,91,14,10,EA,77,6C,DA,1D),
+};
+
+const ak_uint8* beltH()
+{
+  return H;
+}
+
+//rotl
+#define ROTL32(a, r) \
+  ((ak_uint32)0x##a << r | (ak_uint32)0x##a >> (32 - r))
+
+#define ROTL32x16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p, r)\
+  ROTL32(a, r), ROTL32(b, r), ROTL32(c, r), ROTL32(d, r),\
+  ROTL32(e, r), ROTL32(f, r), ROTL32(g, r), ROTL32(h, r),\
+  ROTL32(i, r), ROTL32(j, r), ROTL32(k, r), ROTL32(l, r),\
+  ROTL32(m, r), ROTL32(n, r), ROTL32(o, r), ROTL32(p, r)
+
+//rotl(h)
+static const ak_uint32 H5[256] = {
+  ROTL32x16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4, 5),
+  ROTL32x16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D, 5),
+  ROTL32x16(5B,E3,D6,12,17,B9,61,81,FE,67,86,AD,71,6B,89,0B, 5),
+  ROTL32x16(5C,B0,C0,FF,33,C3,56,B8,35,C4,05,AE,D8,E0,7F,99, 5),
+  ROTL32x16(E1,2B,DC,1A,E2,82,57,EC,70,3F,CC,F0,95,EE,8D,F1, 5),
+  ROTL32x16(C1,AB,76,38,9F,E6,78,CA,F7,C6,F8,60,D5,BB,9C,4F, 5),
+  ROTL32x16(F3,3C,65,7B,63,7C,30,6A,DD,4E,A7,79,9E,B2,3D,31, 5),
+  ROTL32x16(3E,98,B5,6E,27,D3,BC,CF,59,1E,18,1F,4C,5A,B7,93, 5),
+  ROTL32x16(E9,DE,E7,2C,8F,0C,0F,A6,2D,DB,49,F4,6F,73,96,47, 5),
+  ROTL32x16(06,07,53,16,ED,24,7A,37,39,CB,A3,83,03,A9,8B,F6, 5),
+  ROTL32x16(92,BD,9B,1C,E5,D1,41,01,54,45,FB,C9,5E,4D,0E,F2, 5),
+  ROTL32x16(68,20,80,AA,22,7D,64,2F,26,87,F9,34,90,40,55,11, 5),
+  ROTL32x16(BE,32,97,13,43,FC,9A,48,A0,2A,88,5F,19,4B,09,A1, 5),
+  ROTL32x16(7E,CD,A4,D0,15,44,AF,8C,A5,84,50,BF,66,D2,E8,8A, 5),
+  ROTL32x16(A2,D7,46,52,42,A8,DF,B3,69,74,C5,51,EB,23,29,21, 5),
+  ROTL32x16(D4,EF,D9,B4,3A,62,28,75,91,14,10,EA,77,6C,DA,1D, 5),
+};
+
+static const ak_uint32 H13[256] = {
+  ROTL32x16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4, 13),
+  ROTL32x16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D, 13),
+  ROTL32x16(5B,E3,D6,12,17,B9,61,81,FE,67,86,AD,71,6B,89,0B, 13),
+  ROTL32x16(5C,B0,C0,FF,33,C3,56,B8,35,C4,05,AE,D8,E0,7F,99, 13),
+  ROTL32x16(E1,2B,DC,1A,E2,82,57,EC,70,3F,CC,F0,95,EE,8D,F1, 13),
+  ROTL32x16(C1,AB,76,38,9F,E6,78,CA,F7,C6,F8,60,D5,BB,9C,4F, 13),
+  ROTL32x16(F3,3C,65,7B,63,7C,30,6A,DD,4E,A7,79,9E,B2,3D,31, 13),
+  ROTL32x16(3E,98,B5,6E,27,D3,BC,CF,59,1E,18,1F,4C,5A,B7,93, 13),
+  ROTL32x16(E9,DE,E7,2C,8F,0C,0F,A6,2D,DB,49,F4,6F,73,96,47, 13),
+  ROTL32x16(06,07,53,16,ED,24,7A,37,39,CB,A3,83,03,A9,8B,F6, 13),
+  ROTL32x16(92,BD,9B,1C,E5,D1,41,01,54,45,FB,C9,5E,4D,0E,F2, 13),
+  ROTL32x16(68,20,80,AA,22,7D,64,2F,26,87,F9,34,90,40,55,11, 13),
+  ROTL32x16(BE,32,97,13,43,FC,9A,48,A0,2A,88,5F,19,4B,09,A1, 13),
+  ROTL32x16(7E,CD,A4,D0,15,44,AF,8C,A5,84,50,BF,66,D2,E8,8A, 13),
+  ROTL32x16(A2,D7,46,52,42,A8,DF,B3,69,74,C5,51,EB,23,29,21, 13),
+  ROTL32x16(D4,EF,D9,B4,3A,62,28,75,91,14,10,EA,77,6C,DA,1D, 13),
+};
+
+static const ak_uint32 H21[256] = {
+  ROTL32x16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4, 21),
+  ROTL32x16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D, 21),
+  ROTL32x16(5B,E3,D6,12,17,B9,61,81,FE,67,86,AD,71,6B,89,0B, 21),
+  ROTL32x16(5C,B0,C0,FF,33,C3,56,B8,35,C4,05,AE,D8,E0,7F,99, 21),
+  ROTL32x16(E1,2B,DC,1A,E2,82,57,EC,70,3F,CC,F0,95,EE,8D,F1, 21),
+  ROTL32x16(C1,AB,76,38,9F,E6,78,CA,F7,C6,F8,60,D5,BB,9C,4F, 21),
+  ROTL32x16(F3,3C,65,7B,63,7C,30,6A,DD,4E,A7,79,9E,B2,3D,31, 21),
+  ROTL32x16(3E,98,B5,6E,27,D3,BC,CF,59,1E,18,1F,4C,5A,B7,93, 21),
+  ROTL32x16(E9,DE,E7,2C,8F,0C,0F,A6,2D,DB,49,F4,6F,73,96,47, 21),
+  ROTL32x16(06,07,53,16,ED,24,7A,37,39,CB,A3,83,03,A9,8B,F6, 21),
+  ROTL32x16(92,BD,9B,1C,E5,D1,41,01,54,45,FB,C9,5E,4D,0E,F2, 21),
+  ROTL32x16(68,20,80,AA,22,7D,64,2F,26,87,F9,34,90,40,55,11, 21),
+  ROTL32x16(BE,32,97,13,43,FC,9A,48,A0,2A,88,5F,19,4B,09,A1, 21),
+  ROTL32x16(7E,CD,A4,D0,15,44,AF,8C,A5,84,50,BF,66,D2,E8,8A, 21),
+  ROTL32x16(A2,D7,46,52,42,A8,DF,B3,69,74,C5,51,EB,23,29,21, 21),
+  ROTL32x16(D4,EF,D9,B4,3A,62,28,75,91,14,10,EA,77,6C,DA,1D, 21),
+};
+
+static const ak_uint32 H29[256] = {
+  ROTL32x16(B1,94,BA,C8,0A,08,F5,3B,36,6D,00,8E,58,4A,5D,E4, 29),
+  ROTL32x16(85,04,FA,9D,1B,B6,C7,AC,25,2E,72,C2,02,FD,CE,0D, 29),
+  ROTL32x16(5B,E3,D6,12,17,B9,61,81,FE,67,86,AD,71,6B,89,0B, 29),
+  ROTL32x16(5C,B0,C0,FF,33,C3,56,B8,35,C4,05,AE,D8,E0,7F,99, 29),
+  ROTL32x16(E1,2B,DC,1A,E2,82,57,EC,70,3F,CC,F0,95,EE,8D,F1, 29),
+  ROTL32x16(C1,AB,76,38,9F,E6,78,CA,F7,C6,F8,60,D5,BB,9C,4F, 29),
+  ROTL32x16(F3,3C,65,7B,63,7C,30,6A,DD,4E,A7,79,9E,B2,3D,31, 29),
+  ROTL32x16(3E,98,B5,6E,27,D3,BC,CF,59,1E,18,1F,4C,5A,B7,93, 29),
+  ROTL32x16(E9,DE,E7,2C,8F,0C,0F,A6,2D,DB,49,F4,6F,73,96,47, 29),
+  ROTL32x16(06,07,53,16,ED,24,7A,37,39,CB,A3,83,03,A9,8B,F6, 29),
+  ROTL32x16(92,BD,9B,1C,E5,D1,41,01,54,45,FB,C9,5E,4D,0E,F2, 29),
+  ROTL32x16(68,20,80,AA,22,7D,64,2F,26,87,F9,34,90,40,55,11, 29),
+  ROTL32x16(BE,32,97,13,43,FC,9A,48,A0,2A,88,5F,19,4B,09,A1, 29),
+  ROTL32x16(7E,CD,A4,D0,15,44,AF,8C,A5,84,50,BF,66,D2,E8,8A, 29),
+  ROTL32x16(A2,D7,46,52,42,A8,DF,B3,69,74,C5,51,EB,23,29,21, 29),
+  ROTL32x16(D4,EF,D9,B4,3A,62,28,75,91,14,10,EA,77,6C,DA,1D, 29),
+};
+
+//gr(x)
+#define G5(x)\
+  H5[(x) & 255] ^ H13[(x) >> 8 & 255] ^ \
+  H21[(x) >> 16 & 255] ^ H29[(x) >> 24]
+
+#define G13(x)\
+  H13[(x) & 255] ^ H21[(x) >> 8 & 255] ^ \
+  H29[(x) >> 16 & 255] ^ H5[(x) >> 24]
+
+#define G21(x)\
+  H21[(x) & 255] ^ H29[(x) >> 8 & 255] ^ \
+  H5[(x) >> 16 & 255] ^ H13[(x) >> 24]
+
+//1 раунд
+#define R(a, b, c, d, K, i, subkey)\
+  *b ^= G5(*a + subkey(K, i, 0));\
+  *c ^= G21(*d + subkey(K, i, 1));\
+  *a -= G13(*b + subkey(K, i, 2));\
+  *c += *b;\
+  *b += G21(*c + subkey(K, i, 3)) ^ i;\
+  *c -= *b;\
+  *d += G13(*c + subkey(K, i, 4));\
+  *b ^= G21(*a + subkey(K, i, 5));\
+  *c ^= G5(*d + subkey(K, i, 6));\
+
+//ключевая развертка
+#define subkey_e(K, i, j) K[(7 * (i) - 7 + (j)) % 8]
+
+//зашифрование с перестановкой через аргументы
+#define E(a, b, c, d, K)\
+  R(a, b, c, d, K, 1, subkey_e);\
+  R(b, d, a, c, K, 2, subkey_e);\
+  R(d, c, b, a, K, 3, subkey_e);\
+  R(c, a, d, b, K, 4, subkey_e);\
+  R(a, b, c, d, K, 5, subkey_e);\
+  R(b, d, a, c, K, 6, subkey_e);\
+  R(d, c, b, a, K, 7, subkey_e);\
+  R(c, a, d, b, K, 8, subkey_e);\
+  *a ^= *b, *b ^= *a, *a ^= *b;\
+  *c ^= *d, *d ^= *c, *c ^= *d;\
+  *b ^= *c, *c ^= *b, *b ^= *c;\
+
+/**
+ * \brief Алгоритм зашифрования belt-block.
+ * \param block [4*32 бит] Указатель на шифруемый блок данных.
+ * \param key [8*32 бит] Указатель на ключ шифрования.
+ */
+void beltBlockEncr2(ak_uint32 block[4], const ak_uint32 key[8]) {
+  E((block + 0), (block + 1), (block + 2), (block + 3), key);
+}
+
+//---------------------------------------------------------
+//--------------------belt-compress------------------------
+//---------------------------------------------------------
+
+#define beltBlockNeg(dest, src)\
+  ((ak_uint32*)(dest))[0] = ~((const ak_uint32*)(src))[0],\
+  ((ak_uint32*)(dest))[1] = ~((const ak_uint32*)(src))[1],\
+  ((ak_uint32*)(dest))[2] = ~((const ak_uint32*)(src))[2],\
+  ((ak_uint32*)(dest))[3] = ~((const ak_uint32*)(src))[3]
+
+#define beltBlockXor(dest, src1, src2)\
+  ((ak_uint32*)(dest))[0] = \
+    ((const ak_uint32*)(src1))[0] ^ ((const ak_uint32*)(src2))[0],\
+  ((ak_uint32*)(dest))[1] = \
+    ((const ak_uint32*)(src1))[1] ^ ((const ak_uint32*)(src2))[1],\
+  ((ak_uint32*)(dest))[2] = \
+    ((const ak_uint32*)(src1))[2] ^ ((const ak_uint32*)(src2))[2],\
+  ((ak_uint32*)(dest))[3] = \
+    ((const ak_uint32*)(src1))[3] ^ ((const ak_uint32*)(src2))[3]
+
+#define beltBlockXor2(dest, src)\
+  ((ak_uint32*)(dest))[0] ^= ((const ak_uint32*)(src))[0],\
+  ((ak_uint32*)(dest))[1] ^= ((const ak_uint32*)(src))[1],\
+  ((ak_uint32*)(dest))[2] ^= ((const ak_uint32*)(src))[2],\
+  ((ak_uint32*)(dest))[3] ^= ((const ak_uint32*)(src))[3]
+
+#define beltBlockCopy(dest, src)\
+  ((ak_uint32*)(dest))[0] = ((const ak_uint32*)(src))[0],\
+  ((ak_uint32*)(dest))[1] = ((const ak_uint32*)(src))[1],\
+  ((ak_uint32*)(dest))[2] = ((const ak_uint32*)(src))[2],\
+  ((ak_uint32*)(dest))[3] = ((const ak_uint32*)(src))[3]
+
+/**
+ * \brief Алгоритм сжатия belt-compress <b>без обработки S</b>.
+ * \param h [8*32 бит] Указатель на выходное значение Y <b>и второй половины входного значения X</b>.
+ * \param X [8*32 бит] Указатель на входное значение первой половины данных X.
+ * \param stack [12*32 бит] Указатель на промежуточный буфер работы функции.
+ */
+void beltCompress(ak_uint32 h[8], const ak_uint32 X[8], void* stack) {
+  // [12]buf = [4]buf0 || [4]buf1 || [4]buf2
+  ak_uint32* buf = (ak_uint32*)stack;
+  // buf0, buf1 <- h0 + h1
+  beltBlockXor(buf, h, h + 4);
+  beltBlockCopy(buf + 4, buf);
+  // buf0 <- beltBlock(buf0, X) + buf1
+  beltBlockEncr2(buf, X);
+  beltBlockXor2(buf, buf + 4);
+  // buf2 <- h0
+  beltBlockCopy(buf + 8, h);
+  // buf1 <- h1 [buf01 == K1]
+  beltBlockCopy(buf + 4, h + 4);
+  // h0 <- beltBlock(X0, buf01) + X0
+  beltBlockCopy(h, X);
+  beltBlockEncr2(h, buf);
+  beltBlockXor2(h, X);
+  // buf1 <- ~buf0 [buf12 == K2]
+  beltBlockNeg(buf + 4, buf);
+  // h1 <- beltBlock(X1, buf12) + X1
+  beltBlockCopy(h + 4, X + 4);
+  beltBlockEncr2(h + 4, buf + 4);
+  beltBlockXor2(h + 4, X + 4);
+}
+
+/**
+ * \brief Алгоритм сжатия belt-compress.
+ * \param s [4*32 бит] Указатель на выходное значение данных S.
+ * \param h [8*32 бит] Указатель на выходное значение Y <b>и второй половины входного значения X</b>.
+ * \param X [8*32 бит] Указатель на входное значение первой половины данных X.
+ * \param stack [12*32 бит] Указатель на промежуточный буфер работы функции.
+ */
+static inline void beltCompress2(ak_uint32 s[4], ak_uint32 h[8],
+                   const ak_uint32 X[8], void* stack) {
+  // [12]buf = [4]buf0 || [4]buf1 || [4]buf2
+  ak_uint32* buf = (ak_uint32*)stack;
+  // buf0, buf1 <- h0 + h1
+  beltBlockXor(buf, h, h + 4);
+  beltBlockCopy(buf + 4, buf);
+  // buf0 <- beltBlock(buf0, X) + buf1
+  beltBlockEncr2(buf, X);
+  beltBlockXor2(buf, buf + 4);
+  // s <- s ^ buf0
+  beltBlockXor2(s, buf);
+  // buf2 <- h0
+  beltBlockCopy(buf + 8, h);
+  // buf1 <- h1 [buf01 == K1]
+  beltBlockCopy(buf + 4, h + 4);
+  // h0 <- beltBlock(X0, buf01) + X0
+  beltBlockCopy(h, X);
+  beltBlockEncr2(h, buf);
+  beltBlockXor2(h, X);
+  // buf1 <- ~buf0 [buf12 == K2]
+  beltBlockNeg(buf + 4, buf);
+  // h1 <- beltBlock(X1, buf12) + X1
+  beltBlockCopy(h + 4, X + 4);
+  beltBlockEncr2(h + 4, buf + 4);
+  beltBlockXor2(h + 4, X + 4);
+}
+
+//---------------------------------------------------------
+//----------------------belt-hash--------------------------
+//---------------------------------------------------------
+
+#define beltBlockSetZero(block)\
+  ((ak_uint32*)(block))[0] = 0,\
+  ((ak_uint32*)(block))[1] = 0,\
+  ((ak_uint32*)(block))[2] = 0,\
+  ((ak_uint32*)(block))[3] = 0
+
+ak_uint32 u32Rev(ak_uint32 w) {
+  return w << 24 | (w & 0xFF00) << 8 | (w >> 8 & 0xFF00) | w >> 24;
+}
+
+#define beltBlockRevU32(block)\
+  ((ak_uint32*)(block))[0] = u32Rev(((ak_uint32*)(block))[0]),\
+  ((ak_uint32*)(block))[1] = u32Rev(((ak_uint32*)(block))[1]),\
+  ((ak_uint32*)(block))[2] = u32Rev(((ak_uint32*)(block))[2]),\
+  ((ak_uint32*)(block))[3] = u32Rev(((ak_uint32*)(block))[3])
+
+static int ak_hash_context_belt_hash_clean( ak_pointer bctx ) {
+  ak_belt_hash cx = ( ak_belt_hash ) bctx;
+  if( cx == NULL ) return ak_error_null_pointer;
+
+  beltBlockSetZero(cx->ls);
+  beltBlockSetZero(cx->ls + 4);
+  memmove(cx->h, beltH(), 32);
+
+  return ak_error_ok;
+}
+
+static int ak_hash_context_belt_hash_update(
+    ak_pointer bctx, const ak_pointer in, const size_t size ) {
+  ak_belt_hash cx = ( ak_belt_hash ) bctx;
+  const ak_uint8* dt = (const ak_uint8*) in;
+  ak_uint64 count;
+  ak_uint64 count_for_r;
+  ak_uint32* carry;
+
+  if( cx == NULL ) return ak_error_message( ak_error_null_pointer, __func__,
+                                               "using null pointer to internal streebog context" );
+  if(( !size ) || ( in == NULL )) return ak_error_ok;
+  if( size & 0x1F ) return ak_error_message( ak_error_wrong_length, __func__,
+                                      "data length is not a multiple of the length of the block" );
+
+  // обновить длину
+  count = size;
+  count_for_r = count << 3;
+  carry = (ak_uint32*) &count_for_r;
+
+  cx->ls[0] = carry[0];
+  cx->ls[1] = carry[1];
+  count_for_r = count >> 61;
+  cx->ls[2] = carry[0];
+  cx->ls[3] = 0;
+  
+
+  while (count >= 32)
+  {
+    beltBlockCopy(cx->block, dt);
+    beltBlockCopy(cx->block + 16, dt + 16);
+#ifndef AK_LITTLE_ENDIAN
+    beltBlockRevU32(st->block);
+    beltBlockRevU32(st->block + 16);
+#endif
+    beltCompress2(cx->ls + 4, cx->h, (ak_uint32*)cx->block, cx->stack);
+    dt += 32;
+    count -= 32;
+  }
+
+  return ak_error_ok;
+}
+
+static int ak_hash_context_belt_hash_finalize( ak_pointer bctx,
+  const ak_pointer in, const size_t size, ak_pointer out,
+  const size_t out_size )
+{
+  ak_belt_hash cx = ( ak_belt_hash ) bctx;
+  struct belt_hash bx[1]; //здесь должна изменяться копия контекста, а не оригинал
+  ak_uint32 carry;
+
+  if( cx == NULL ) return ak_error_message( ak_error_null_pointer, __func__,
+                                               "using null pointer to internal streebog context" );
+  if( out == NULL ) return ak_error_message( ak_error_null_pointer, __func__,
+                                                   "using null pointer to externl result buffer" );
+  if( size >= 32 ) return ak_error_message( ak_error_wrong_length, __func__,
+                                                                       "input length is too huge" );
+  
+  memcpy( bx, cx, sizeof( struct belt_hash ));
+
+  if(size) {
+    // обновить длину
+    carry = (ak_uint32) size << 3;
+    carry = (bx->ls[0] += carry) < carry;
+    carry = (bx->ls[1] += carry) < carry;
+    carry = (bx->ls[2] += carry) < carry;
+    bx->ls[3] += carry;
+
+    //отработать последний блок
+    memset(bx->block, 0, 32);
+    if (in != NULL) {
+      memcpy(bx->block, in, size);
+    }
+#ifndef AK_LITTLE_ENDIAN
+    beltBlockRevU32(bx->block);
+    beltBlockRevU32(bx->block + 16);
+#endif
+    beltCompress2(bx->ls + 4, bx->h, (ak_uint32*)bx->block, bx->stack);
+  }
+  beltCompress(bx->h, bx->ls, bx->stack);
+
+  memcpy(out, bx->h, ak_min(32, out_size));
+
+  return ak_error_ok;
+}
+
+/**
+ * \brief Инициализация контекста функции бесключевого хеширования СТБ 34.101.31-2020 (belt-hash).
+ * \param hctx Контекст функции хеширования, который будет заполнен
+ * \return Функция возвращает код ошибки или \ref ak_error_ok (в случае успеха)
+ */
+int ak_hash_create_belt_hash( ak_hash hctx )
+{
+  int error = ak_error_ok;
+
+  if( hctx == NULL ) return ak_error_message( ak_error_null_pointer, __func__,
+                                                            "using null pointer to hash context" );
+  if(( hctx->oid = ak_oid_find_by_name( "belt-hash" )) == NULL )
+    return ak_error_message( ak_error_wrong_oid, __func__,
+                                           "incorrect internal search of belt-hash identifier" );
+  if(( error = ak_mac_create( &hctx->mctx, 32, &hctx->data.bctx,
+                                             ak_hash_context_belt_hash_clean,
+                                             ak_hash_context_belt_hash_update,
+                                             ak_hash_context_belt_hash_finalize )) != ak_error_ok )
+    return ak_error_message( error, __func__, "incorrect initialization of internal mac context" );
+
+  return ak_hash_context_belt_hash_clean( &hctx->data.bctx );
+}
diff --git a/source/ak_hash.c b/source/ak_hash.c
index efec30498afbf1a2368892719e5841614acb4bb6..4d0bf56f79f7386b225d0a045cc8d4cfa19f8f69 100644
--- a/source/ak_hash.c
+++ b/source/ak_hash.c
@@ -1512,7 +1512,7 @@
   if( hctx == NULL ) return ak_error_message( ak_error_null_pointer, __func__,
                                                        "destroying null pointer to hash context" );
   hctx->oid = NULL;
-  memset( &hctx->data.sctx, 0, sizeof( struct streebog ));
+  memset( &hctx->data.sctx, 0, sizeof (&hctx->data) );
   if( ak_mac_destroy( &hctx->mctx ) != ak_error_ok )
     ak_error_message( ak_error_get_value(), __func__,
                                                     "incorrect cleaning of internal mac context" );
diff --git a/source/ak_oid.c b/source/ak_oid.c
index 8cad564c4b4e365b37426fade4b27e59453c7cc2..3040f5e2d6f2d0502705bb205f5ea5e482da2f91 100644
--- a/source/ak_oid.c
+++ b/source/ak_oid.c
@@ -69,6 +69,8 @@
  static const char *asn1_streebog256_i[] = { "1.2.643.7.1.1.2.2", NULL };
  static const char *asn1_streebog512_n[] = { "streebog512", "md_gost12_512", NULL };
  static const char *asn1_streebog512_i[] = { "1.2.643.7.1.1.2.3", NULL };
+ static const char *asn1_belt_hash_n[] = { "belt-hash", NULL };
+ static const char *asn1_belt_hash_i[] = { "1.2.112.0.2.0.34.101.31.81", NULL };
  static const char *asn1_crc64_n[] =       { "crc64", NULL };
  static const char *asn1_crc64_i[] =       { "1.2.643.2.52.1.2.2", NULL };
 
@@ -556,6 +558,10 @@ static struct oid libakrypt_oids[] =
   {{ sizeof( struct hash ), ( ak_function_create_object *) ak_hash_create_streebog512,
                               ( ak_function_destroy_object *) ak_hash_destroy, NULL, NULL, NULL },
                               ak_object_undefined, (ak_function_run_object *) ak_hash_ptr, NULL }},
+ { hash_function, algorithm, asn1_belt_hash_i, asn1_belt_hash_n, NULL,
+  {{ sizeof( struct hash ), ( ak_function_create_object *) ak_hash_create_belt_hash,
+                              ( ak_function_destroy_object *) ak_hash_destroy, NULL, NULL, NULL },
+                              ak_object_undefined, (ak_function_run_object *) ak_hash_ptr, NULL }},
 
  { hash_function, algorithm, asn1_crc64_i, asn1_crc64_n, NULL,
   {{ sizeof( struct hash ), ( ak_function_create_object *) ak_hash_create_crc64,
diff --git a/source/libakrypt.h b/source/libakrypt.h
index c03e0c299b8c1a3b61d78fc5b0a583a4a07e3d54..415b12baff60b924e92fda43fdd8bbfd4eb0ed13 100644
--- a/source/libakrypt.h
+++ b/source/libakrypt.h
@@ -911,6 +911,20 @@ extern "C" {
   size_t hsize;
 } *ak_streebog;
 
+/* ----------------------------------------------------------------------------------------------- */
+/*! \brief Структура для хранения внутренних данных функции хеширования семейства belt-hash */
+/* ----------------------------------------------------------------------------------------------- */
+ typedef struct belt_hash {
+  /*! \brief Блок [4]len || [4]s */
+  ak_uint32 ls[8];
+  /*! \brief Временное значение хэш-суммы */
+  ak_uint32 h[8];
+  /*! \brief Блок данных для шифрования */
+  ak_uint8 block[32];
+  /*! \brief Стек для работы beltCompr [12*4 байт] */
+  ak_uint8 stack[12*4];
+} *ak_belt_hash;
+
 /* ----------------------------------------------------------------------------------------------- */
 /*! \brief Контекст бесключевой функции хеширования. */
 /*! \details Класс предоставляет интерфейс для реализации бесключевых функций хеширования, построенных
@@ -934,6 +948,8 @@ extern "C" {
    union {
      /*! \brief Структура алгоритмов семейства Стрибог. */
       struct streebog sctx;
+     /*! \brief Структура алгоритма belt-hash. */
+      struct belt_hash bctx;
      /*! \brief Вектор значений для алгоритмов семейства crc64 */
       ak_uint64 b64;
    } data;
@@ -944,6 +960,8 @@ extern "C" {
  dll_export int ak_hash_create_streebog256( ak_hash );
 /*! \brief Инициализация контекста функции бесключевого хеширования ГОСТ Р 34.11-2012 (Стрибог512). */
  dll_export int ak_hash_create_streebog512( ak_hash );
+/*! \brief Инициализация контекста функции бесключевого хеширования СТБ 34.101.31-2020 (belt-hash). */
+ dll_export int ak_hash_create_belt_hash( ak_hash );
 /*! \brief Инициализация контекста некриптографической функции хеширования crc64. */
  dll_export int ak_hash_create_crc64( ak_hash );
 /*! \brief Инициализация контекста функции бесключевого хеширования по заданному OID алгоритма. */