content: package im.actor.crypto.primitives.kuznechik;
  
  import im.actor.crypto.primitives.BlockCipher;
  import im.actor.crypto.primitives.util.Pack;
  
  public class KuznechikFastEngine implements BlockCipher {
  
      private static final byte[] kuz_pi = new byte[]{
              (byte) 0xFC, (byte) 0xEE, (byte) 0xDD, (byte) 0x11, (byte) 0xCF, (byte) 0x6E, (byte) 0x31, (byte) 0x16,    // 00..07
              (byte) 0xFB, (byte) 0xC4, (byte) 0xFA, (byte) 0xDA, (byte) 0x23, (byte) 0xC5, (byte) 0x04, (byte) 0x4D,    // 08..0F
              (byte) 0xE9, (byte) 0x77, (byte) 0xF0, (byte) 0xDB, (byte) 0x93, (byte) 0x2E, (byte) 0x99, (byte) 0xBA,    // 10..17
              (byte) 0x17, (byte) 0x36, (byte) 0xF1, (byte) 0xBB, (byte) 0x14, (byte) 0xCD, (byte) 0x5F, (byte) 0xC1,    // 18..1F
              (byte) 0xF9, (byte) 0x18, (byte) 0x65, (byte) 0x5A, (byte) 0xE2, (byte) 0x5C, (byte) 0xEF, (byte) 0x21,    // 20..27
              (byte) 0x81, (byte) 0x1C, (byte) 0x3C, (byte) 0x42, (byte) 0x8B, (byte) 0x01, (byte) 0x8E, (byte) 0x4F,    // 28..2F
              (byte) 0x05, (byte) 0x84, (byte) 0x02, (byte) 0xAE, (byte) 0xE3, (byte) 0x6A, (byte) 0x8F, (byte) 0xA0,    // 30..37
              (byte) 0x06, (byte) 0x0B, (byte) 0xED, (byte) 0x98, (byte) 0x7F, (byte) 0xD4, (byte) 0xD3, (byte) 0x1F,    // 38..3F
              (byte) 0xEB, (byte) 0x34, (byte) 0x2C, (byte) 0x51, (byte) 0xEA, (byte) 0xC8, (byte) 0x48, (byte) 0xAB,    // 40..47
              (byte) 0xF2, (byte) 0x2A, (byte) 0x68, (byte) 0xA2, (byte) 0xFD, (byte) 0x3A, (byte) 0xCE, (byte) 0xCC,    // 48..4F
              (byte) 0xB5, (byte) 0x70, (byte) 0x0E, (byte) 0x56, (byte) 0x08, (byte) 0x0C, (byte) 0x76, (byte) 0x12,    // 50..57
              (byte) 0xBF, (byte) 0x72, (byte) 0x13, (byte) 0x47, (byte) 0x9C, (byte) 0xB7, (byte) 0x5D, (byte) 0x87,    // 58..5F
              (byte) 0x15, (byte) 0xA1, (byte) 0x96, (byte) 0x29, (byte) 0x10, (byte) 0x7B, (byte) 0x9A, (byte) 0xC7,    // 60..67
              (byte) 0xF3, (byte) 0x91, (byte) 0x78, (byte) 0x6F, (byte) 0x9D, (byte) 0x9E, (byte) 0xB2, (byte) 0xB1,    // 68..6F
              (byte) 0x32, (byte) 0x75, (byte) 0x19, (byte) 0x3D, (byte) 0xFF, (byte) 0x35, (byte) 0x8A, (byte) 0x7E,    // 70..77
              (byte) 0x6D, (byte) 0x54, (byte) 0xC6, (byte) 0x80, (byte) 0xC3, (byte) 0xBD, (byte) 0x0D, (byte) 0x57,    // 78..7F
              (byte) 0xDF, (byte) 0xF5, (byte) 0x24, (byte) 0xA9, (byte) 0x3E, (byte) 0xA8, (byte) 0x43, (byte) 0xC9,    // 80..87
              (byte) 0xD7, (byte) 0x79, (byte) 0xD6, (byte) 0xF6, (byte) 0x7C, (byte) 0x22, (byte) 0xB9, (byte) 0x03,    // 88..8F
              (byte) 0xE0, (byte) 0x0F, (byte) 0xEC, (byte) 0xDE, (byte) 0x7A, (byte) 0x94, (byte) 0xB0, (byte) 0xBC,    // 90..97
              (byte) 0xDC, (byte) 0xE8, (byte) 0x28, (byte) 0x50, (byte) 0x4E, (byte) 0x33, (byte) 0x0A, (byte) 0x4A,    // 98..9F
              (byte) 0xA7, (byte) 0x97, (byte) 0x60, (byte) 0x73, (byte) 0x1E, (byte) 0x00, (byte) 0x62, (byte) 0x44,    // A0..A7
              (byte) 0x1A, (byte) 0xB8, (byte) 0x38, (byte) 0x82, (byte) 0x64, (byte) 0x9F, (byte) 0x26, (byte) 0x41,    // A8..AF
              (byte) 0xAD, (byte) 0x45, (byte) 0x46, (byte) 0x92, (byte) 0x27, (byte) 0x5E, (byte) 0x55, (byte) 0x2F,    // B0..B7
              (byte) 0x8C, (byte) 0xA3, (byte) 0xA5, (byte) 0x7D, (byte) 0x69, (byte) 0xD5, (byte) 0x95, (byte) 0x3B,    // B8..BF
              (byte) 0x07, (byte) 0x58, (byte) 0xB3, (byte) 0x40, (byte) 0x86, (byte) 0xAC, (byte) 0x1D, (byte) 0xF7,    // C0..C7
              (byte) 0x30, (byte) 0x37, (byte) 0x6B, (byte) 0xE4, (byte) 0x88, (byte) 0xD9, (byte) 0xE7, (byte) 0x89,    // C8..CF
              (byte) 0xE1, (byte) 0x1B, (byte) 0x83, (byte) 0x49, (byte) 0x4C, (byte) 0x3F, (byte) 0xF8, (byte) 0xFE,    // D0..D7
              (byte) 0x8D, (byte) 0x53, (byte) 0xAA, (byte) 0x90, (byte) 0xCA, (byte) 0xD8, (byte) 0x85, (byte) 0x61,    // D8..DF
              (byte) 0x20, (byte) 0x71, (byte) 0x67, (byte) 0xA4, (byte) 0x2D, (byte) 0x2B, (byte) 0x09, (byte) 0x5B,    // E0..E7
              (byte) 0xCB, (byte) 0x9B, (byte) 0x25, (byte) 0xD0, (byte) 0xBE, (byte) 0xE5, (byte) 0x6C, (byte) 0x52,    // E8..EF
              (byte) 0x59, (byte) 0xA6, (byte) 0x74, (byte) 0xD2, (byte) 0xE6, (byte) 0xF4, (byte) 0xB4, (byte) 0xC0,    // F0..F7
              (byte) 0xD1, (byte) 0x66, (byte) 0xAF, (byte) 0xC2, (byte) 0x39, (byte) 0x4B, (byte) 0x63, (byte) 0xB6,    // F8..FF
      };
  
      // Inverse S-Box
      private static final byte[] kuz_pi_inv = new byte[]{
              (byte) 0xA5, (byte) 0x2D, (byte) 0x32, (byte) 0x8F, (byte) 0x0E, (byte) 0x30, (byte) 0x38, (byte) 0xC0,    // 00..07
              (byte) 0x54, (byte) 0xE6, (byte) 0x9E, (byte) 0x39, (byte) 0x55, (byte) 0x7E, (byte) 0x52, (byte) 0x91,    // 08..0F
              (byte) 0x64, (byte) 0x03, (byte) 0x57, (byte) 0x5A, (byte) 0x1C, (byte) 0x60, (byte) 0x07, (byte) 0x18,    // 10..17
              (byte) 0x21, (byte) 0x72, (byte) 0xA8, (byte) 0xD1, (byte) 0x29, (byte) 0xC6, (byte) 0xA4, (byte) 0x3F,    // 18..1F
              (byte) 0xE0, (byte) 0x27, (byte) 0x8D, (byte) 0x0C, (byte) 0x82, (byte) 0xEA, (byte) 0xAE, (byte) 0xB4,    // 20..27
              (byte) 0x9A, (byte) 0x63, (byte) 0x49, (byte) 0xE5, (byte) 0x42, (byte) 0xE4, (byte) 0x15, (byte) 0xB7,    // 28..2F
              (byte) 0xC8, (byte) 0x06, (byte) 0x70, (byte) 0x9D, (byte) 0x41, (byte) 0x75, (byte) 0x19, (byte) 0xC9,    // 30..37
              (byte) 0xAA, (byte) 0xFC, (byte) 0x4D, (byte) 0xBF, (byte) 0x2A, (byte) 0x73, (byte) 0x84, (byte) 0xD5,    // 38..3F
              (byte) 0xC3, (byte) 0xAF, (byte) 0x2B, (byte) 0x86, (byte) 0xA7, (byte) 0xB1, (byte) 0xB2, (byte) 0x5B,    // 40..47
              (byte) 0x46, (byte) 0xD3, (byte) 0x9F, (byte) 0xFD, (byte) 0xD4, (byte) 0x0F, (byte) 0x9C, (byte) 0x2F,    // 48..4F
              (byte) 0x9B, (byte) 0x43, (byte) 0xEF, (byte) 0xD9, (byte) 0x79, (byte) 0xB6, (byte) 0x53, (byte) 0x7F,    // 50..57
              (byte) 0xC1, (byte) 0xF0, (byte) 0x23, (byte) 0xE7, (byte) 0x25, (byte) 0x5E, (byte) 0xB5, (byte) 0x1E,    // 58..5F
              (byte) 0xA2, (byte) 0xDF, (byte) 0xA6, (byte) 0xFE, (byte) 0xAC, (byte) 0x22, (byte) 0xF9, (byte) 0xE2,    // 60..67
              (byte) 0x4A, (byte) 0xBC, (byte) 0x35, (byte) 0xCA, (byte) 0xEE, (byte) 0x78, (byte) 0x05, (byte) 0x6B,    // 68..6F
              (byte) 0x51, (byte) 0xE1, (byte) 0x59, (byte) 0xA3, (byte) 0xF2, (byte) 0x71, (byte) 0x56, (byte) 0x11,    // 70..77
              (byte) 0x6A, (byte) 0x89, (byte) 0x94, (byte) 0x65, (byte) 0x8C, (byte) 0xBB, (byte) 0x77, (byte) 0x3C,    // 78..7F
              (byte) 0x7B, (byte) 0x28, (byte) 0xAB, (byte) 0xD2, (byte) 0x31, (byte) 0xDE, (byte) 0xC4, (byte) 0x5F,    // 80..87
              (byte) 0xCC, (byte) 0xCF, (byte) 0x76, (byte) 0x2C, (byte) 0xB8, (byte) 0xD8, (byte) 0x2E, (byte) 0x36,    // 88..8F
              (byte) 0xDB, (byte) 0x69, (byte) 0xB3, (byte) 0x14, (byte) 0x95, (byte) 0xBE, (byte) 0x62, (byte) 0xA1,    // 90..97
              (byte) 0x3B, (byte) 0x16, (byte) 0x66, (byte) 0xE9, (byte) 0x5C, (byte) 0x6C, (byte) 0x6D, (byte) 0xAD,    // 98..9F
              (byte) 0x37, (byte) 0x61, (byte) 0x4B, (byte) 0xB9, (byte) 0xE3, (byte) 0xBA, (byte) 0xF1, (byte) 0xA0,    // A0..A7
              (byte) 0x85, (byte) 0x83, (byte) 0xDA, (byte) 0x47, (byte) 0xC5, (byte) 0xB0, (byte) 0x33, (byte) 0xFA,    // A8..AF
              (byte) 0x96, (byte) 0x6F, (byte) 0x6E, (byte) 0xC2, (byte) 0xF6, (byte) 0x50, (byte) 0xFF, (byte) 0x5D,    // B0..B7
              (byte) 0xA9, (byte) 0x8E, (byte) 0x17, (byte) 0x1B, (byte) 0x97, (byte) 0x7D, (byte) 0xEC, (byte) 0x58,    // B8..BF
              (byte) 0xF7, (byte) 0x1F, (byte) 0xFB, (byte) 0x7C, (byte) 0x09, (byte) 0x0D, (byte) 0x7A, (byte) 0x67,    // C0..C7
              (byte) 0x45, (byte) 0x87, (byte) 0xDC, (byte) 0xE8, (byte) 0x4F, (byte) 0x1D, (byte) 0x4E, (byte) 0x04,    // C8..CF
              (byte) 0xEB, (byte) 0xF8, (byte) 0xF3, (byte) 0x3E, (byte) 0x3D, (byte) 0xBD, (byte) 0x8A, (byte) 0x88,    // D0..D7
              (byte) 0xDD, (byte) 0xCD, (byte) 0x0B, (byte) 0x13, (byte) 0x98, (byte) 0x02, (byte) 0x93, (byte) 0x80,    // D8..DF
              (byte) 0x90, (byte) 0xD0, (byte) 0x24, (byte) 0x34, (byte) 0xCB, (byte) 0xED, (byte) 0xF4, (byte) 0xCE,    // E0..E7
              (byte) 0x99, (byte) 0x10, (byte) 0x44, (byte) 0x40, (byte) 0x92, (byte) 0x3A, (byte) 0x01, (byte) 0x26,    // E8..EF
              (byte) 0x12, (byte) 0x1A, (byte) 0x48, (byte) 0x68, (byte) 0xF5, (byte) 0x81, (byte) 0x8B, (byte) 0xC7,    // F0..F7
              (byte) 0xD6, (byte) 0x20, (byte) 0x0A, (byte) 0x08, (byte) 0x00, (byte) 0x4C, (byte) 0xD7, (byte) 0x74        // F8..FF
      };
  
      // Linear vector from sect 5.1.2
      private static final byte[] kuz_lvec = new byte[]{
              (byte) 0x94, (byte) 0x20, (byte) 0x85, (byte) 0x10, (byte) 0xC2, (byte) 0xC0, (byte) 0x01, (byte) 0xFB,
              (byte) 0x01, (byte) 0xC0, (byte) 0xC2, (byte) 0x10, (byte) 0x85, (byte) 0x20, (byte) 0x94, (byte) 0x01
      };
  
      // Generated with http://www.cs.utsa.edu/~wagner/laws/FFM.html
      private static final byte[] gf256_E = new byte[]{
              (byte) 0x01, (byte) 0x03, (byte) 0x05, (byte) 0x0f, (byte) 0x11, (byte) 0x33, (byte) 0x55, (byte) 0xff, (byte) 0xc2, (byte) 0x85, (byte) 0x4c, (byte) 0xd4, (byte) 0xbf, (byte) 0x02, (byte) 0x06, (byte) 0x0a,
              (byte) 0x1e, (byte) 0x22, (byte) 0x66, (byte) 0xaa, (byte) 0x3d, (byte) 0x47, (byte) 0xc9, (byte) 0x98, (byte) 0x6b, (byte) 0xbd, (byte) 0x04, (byte) 0x0c, (byte) 0x14, (byte) 0x3c, (byte) 0x44, (byte) 0xcc,
              (byte) 0x97, (byte) 0x7a, (byte) 0x8e, (byte) 0x51, (byte) 0xf3, (byte) 0xd6, (byte) 0xb9, (byte) 0x08, (byte) 0x18, (byte) 0x28, (byte) 0x78, (byte) 0x88, (byte) 0x5b, (byte) 0xed, (byte) 0xf4, (byte) 0xdf,
              (byte) 0xa2, (byte) 0x25, (byte) 0x6f, (byte) 0xb1, (byte) 0x10, (byte) 0x30, (byte) 0x50, (byte) 0xf0, (byte) 0xd3, (byte) 0xb6, (byte) 0x19, (byte) 0x2b, (byte) 0x7d, (byte) 0x87, (byte) 0x4a, (byte) 0xde,
              (byte) 0xa1, (byte) 0x20, (byte) 0x60, (byte) 0xa0, (byte) 0x23, (byte) 0x65, (byte) 0xaf, (byte) 0x32, (byte) 0x56, (byte) 0xfa, (byte) 0xcd, (byte) 0x94, (byte) 0x7f, (byte) 0x81, (byte) 0x40, (byte) 0xc0,
              (byte) 0x83, (byte) 0x46, (byte) 0xca, (byte) 0x9d, (byte) 0x64, (byte) 0xac, (byte) 0x37, (byte) 0x59, (byte) 0xeb, (byte) 0xfe, (byte) 0xc1, (byte) 0x80, (byte) 0x43, (byte) 0xc5, (byte) 0x8c, (byte) 0x57,
              (byte) 0xf9, (byte) 0xc8, (byte) 0x9b, (byte) 0x6e, (byte) 0xb2, (byte) 0x15, (byte) 0x3f, (byte) 0x41, (byte) 0xc3, (byte) 0x86, (byte) 0x49, (byte) 0xdb, (byte) 0xae, (byte) 0x31, (byte) 0x53, (byte) 0xf5,
              (byte) 0xdc, (byte) 0xa7, (byte) 0x2a, (byte) 0x7e, (byte) 0x82, (byte) 0x45, (byte) 0xcf, (byte) 0x92, (byte) 0x75, (byte) 0x9f, (byte) 0x62, (byte) 0xa6, (byte) 0x29, (byte) 0x7b, (byte) 0x8d, (byte) 0x54,
              (byte) 0xfc, (byte) 0xc7, (byte) 0x8a, (byte) 0x5d, (byte) 0xe7, (byte) 0xea, (byte) 0xfd, (byte) 0xc4, (byte) 0x8f, (byte) 0x52, (byte) 0xf6, (byte) 0xd9, (byte) 0xa8, (byte) 0x3b, (byte) 0x4d, (byte) 0xd7,
              (byte) 0xba, (byte) 0x0d, (byte) 0x17, (byte) 0x39, (byte) 0x4b, (byte) 0xdd, (byte) 0xa4, (byte) 0x2f, (byte) 0x71, (byte) 0x93, (byte) 0x76, (byte) 0x9a, (byte) 0x6d, (byte) 0xb7, (byte) 0x1a, (byte) 0x2e,
              (byte) 0x72, (byte) 0x96, (byte) 0x79, (byte) 0x8b, (byte) 0x5e, (byte) 0xe2, (byte) 0xe5, (byte) 0xec, (byte) 0xf7, (byte) 0xda, (byte) 0xad, (byte) 0x34, (byte) 0x5c, (byte) 0xe4, (byte) 0xef, (byte) 0xf2,
              (byte) 0xd5, (byte) 0xbc, (byte) 0x07, (byte) 0x09, (byte) 0x1b, (byte) 0x2d, (byte) 0x77, (byte) 0x99, (byte) 0x68, (byte) 0xb8, (byte) 0x0b, (byte) 0x1d, (byte) 0x27, (byte) 0x69, (byte) 0xbb, (byte) 0x0e,
              (byte) 0x12, (byte) 0x36, (byte) 0x5a, (byte) 0xee, (byte) 0xf1, (byte) 0xd0, (byte) 0xb3, (byte) 0x16, (byte) 0x3a, (byte) 0x4e, (byte) 0xd2, (byte) 0xb5, (byte) 0x1c, (byte) 0x24, (byte) 0x6c, (byte) 0xb4,
              (byte) 0x1f, (byte) 0x21, (byte) 0x63, (byte) 0xa5, (byte) 0x2c, (byte) 0x74, (byte) 0x9c, (byte) 0x67, (byte) 0xa9, (byte) 0x38, (byte) 0x48, (byte) 0xd8, (byte) 0xab, (byte) 0x3e, (byte) 0x42, (byte) 0xc6,
              (byte) 0x89, (byte) 0x58, (byte) 0xe8, (byte) 0xfb, (byte) 0xce, (byte) 0x91, (byte) 0x70, (byte) 0x90, (byte) 0x73, (byte) 0x95, (byte) 0x7c, (byte) 0x84, (byte) 0x4f, (byte) 0xd1, (byte) 0xb0, (byte) 0x13,
              (byte) 0x35, (byte) 0x5f, (byte) 0xe1, (byte) 0xe0, (byte) 0xe3, (byte) 0xe6, (byte) 0xe9, (byte) 0xf8, (byte) 0xcb, (byte) 0x9e, (byte) 0x61, (byte) 0xa3, (byte) 0x26, (byte) 0x6a, (byte) 0xbe, (byte) 0x01,
      };
  
      // Generated with http://www.cs.utsa.edu/~wagner/laws/FFM.html
      private static final byte[] gf256_L = new byte[]{
              (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x01, (byte) 0x1a, (byte) 0x02, (byte) 0x0e, (byte) 0xb2, (byte) 0x27, (byte) 0xb3, (byte) 0x0f, (byte) 0xba, (byte) 0x1b, (byte) 0x91, (byte) 0xbf, (byte) 0x03,
              (byte) 0x34, (byte) 0x04, (byte) 0xc0, (byte) 0xef, (byte) 0x1c, (byte) 0x65, (byte) 0xc7, (byte) 0x92, (byte) 0x28, (byte) 0x3a, (byte) 0x9e, (byte) 0xb4, (byte) 0xcc, (byte) 0xbb, (byte) 0x10, (byte) 0xd0,
              (byte) 0x41, (byte) 0xd1, (byte) 0x11, (byte) 0x44, (byte) 0xcd, (byte) 0x31, (byte) 0xfc, (byte) 0xbc, (byte) 0x29, (byte) 0x7c, (byte) 0x72, (byte) 0x3b, (byte) 0xd4, (byte) 0xb5, (byte) 0x9f, (byte) 0x97,
              (byte) 0x35, (byte) 0x6d, (byte) 0x47, (byte) 0x05, (byte) 0xab, (byte) 0xf0, (byte) 0xc1, (byte) 0x56, (byte) 0xd9, (byte) 0x93, (byte) 0xc8, (byte) 0x8d, (byte) 0x1d, (byte) 0x14, (byte) 0xdd, (byte) 0x66,
              (byte) 0x4e, (byte) 0x67, (byte) 0xde, (byte) 0x5c, (byte) 0x1e, (byte) 0x75, (byte) 0x51, (byte) 0x15, (byte) 0xda, (byte) 0x6a, (byte) 0x3e, (byte) 0x94, (byte) 0x0a, (byte) 0x8e, (byte) 0xc9, (byte) 0xec,
              (byte) 0x36, (byte) 0x23, (byte) 0x89, (byte) 0x6e, (byte) 0x7f, (byte) 0x06, (byte) 0x48, (byte) 0x5f, (byte) 0xe1, (byte) 0x57, (byte) 0xc2, (byte) 0x2c, (byte) 0xac, (byte) 0x83, (byte) 0xa4, (byte) 0xf1,
              (byte) 0x42, (byte) 0xfa, (byte) 0x7a, (byte) 0xd2, (byte) 0x54, (byte) 0x45, (byte) 0x12, (byte) 0xd7, (byte) 0xb8, (byte) 0xbd, (byte) 0xfd, (byte) 0x18, (byte) 0xce, (byte) 0x9c, (byte) 0x63, (byte) 0x32,
              (byte) 0xe6, (byte) 0x98, (byte) 0xa0, (byte) 0xe8, (byte) 0xd5, (byte) 0x78, (byte) 0x9a, (byte) 0xb6, (byte) 0x2a, (byte) 0xa2, (byte) 0x21, (byte) 0x7d, (byte) 0xea, (byte) 0x3c, (byte) 0x73, (byte) 0x4c,
              (byte) 0x5b, (byte) 0x4d, (byte) 0x74, (byte) 0x50, (byte) 0xeb, (byte) 0x09, (byte) 0x69, (byte) 0x3d, (byte) 0x2b, (byte) 0xe0, (byte) 0x82, (byte) 0xa3, (byte) 0x5e, (byte) 0x7e, (byte) 0x22, (byte) 0x88,
              (byte) 0xe7, (byte) 0xe5, (byte) 0x77, (byte) 0x99, (byte) 0x4b, (byte) 0xe9, (byte) 0xa1, (byte) 0x20, (byte) 0x17, (byte) 0xb7, (byte) 0x9b, (byte) 0x62, (byte) 0xd6, (byte) 0x53, (byte) 0xf9, (byte) 0x79,
              (byte) 0x43, (byte) 0x40, (byte) 0x30, (byte) 0xfb, (byte) 0x96, (byte) 0xd3, (byte) 0x7b, (byte) 0x71, (byte) 0x8c, (byte) 0xd8, (byte) 0x13, (byte) 0xdc, (byte) 0x55, (byte) 0xaa, (byte) 0x6c, (byte) 0x46,
              (byte) 0xee, (byte) 0x33, (byte) 0x64, (byte) 0xc6, (byte) 0xcf, (byte) 0xcb, (byte) 0x39, (byte) 0x9d, (byte) 0xb9, (byte) 0x26, (byte) 0x90, (byte) 0xbe, (byte) 0xb1, (byte) 0x19, (byte) 0xfe, (byte) 0x0c,
              (byte) 0x4f, (byte) 0x5a, (byte) 0x08, (byte) 0x68, (byte) 0x87, (byte) 0x5d, (byte) 0xdf, (byte) 0x81, (byte) 0x61, (byte) 0x16, (byte) 0x52, (byte) 0xf8, (byte) 0x1f, (byte) 0x4a, (byte) 0xe4, (byte) 0x76,
              (byte) 0xc5, (byte) 0xed, (byte) 0xca, (byte) 0x38, (byte) 0x0b, (byte) 0xb0, (byte) 0x25, (byte) 0x8f, (byte) 0xdb, (byte) 0x8b, (byte) 0xa9, (byte) 0x6b, (byte) 0x70, (byte) 0x95, (byte) 0x3f, (byte) 0x2f,
              (byte) 0xf3, (byte) 0xf2, (byte) 0xa5, (byte) 0xf4, (byte) 0xad, (byte) 0xa6, (byte) 0xf5, (byte) 0x84, (byte) 0xe2, (byte) 0xf6, (byte) 0x85, (byte) 0x58, (byte) 0xa7, (byte) 0x2d, (byte) 0xc3, (byte) 0xae,
              (byte) 0x37, (byte) 0xc4, (byte) 0xaf, (byte) 0x24, (byte) 0x2e, (byte) 0x6f, (byte) 0x8a, (byte) 0xa8, (byte) 0xf7, (byte) 0x60, (byte) 0x49, (byte) 0xe3, (byte) 0x80, (byte) 0x86, (byte) 0x59, (byte) 0x07,
      };
  
      private static final int[] gf256res;
      private static final int[] gf256resInv;
  
      static {
          gf256res = new int[16 * 256 * 4];
          gf256resInv = new int[16 * 256 * 4];
  
          byte[] tmp = new byte[16];
          for (int index = 0; index < 16; index++) {
              for (int i = 0; i < 256; i++) {
                  for (int l = 0; l < 16; l++) {
                      tmp[l] = 0;
                  }
                  tmp[index] = (byte) i;
                  kuz_l(tmp);
                  Pack.bigEndianToInt(tmp, 0, gf256res, (index + (16 * i)) * 4, 4);
  
                  for (int l = 0; l < 16; l++) {
                      tmp[l] = 0;
                  }
                  tmp[index] = (byte) i;
                  kuz_l_inv(tmp);
                  Pack.bigEndianToInt(tmp, 0, gf256resInv, (index + (16 * i)) * 4, 4);
              }
          }
      }
  
  
      static void kuz_l_fast(int[] w) {
          int a0 = 0, a1 = 0, a2 = 0, a3 = 0;
          for (int ind = 0; ind < 16; ind++) {
              int dataByte = (ind + ((w[ind / 4] >> (3 - ind % 4) * 8) & 0xFF) * 16) * 4;
  
              a0 = a0 ^ gf256res[dataByte + 0];
              a1 = a1 ^ gf256res[dataByte + 1];
              a2 = a2 ^ gf256res[dataByte + 2];
              a3 = a3 ^ gf256res[dataByte + 3];
          }
          w[0] = a0;
          w[1] = a1;
          w[2] = a2;
          w[3] = a3;
      }
  
      static void kuz_l(byte[] w) {
          for (int j = 0; j < 16; j++) {
              byte x = w[15];
              w[15] = w[14];
              x ^= kuz_mul_gf256_fast(w[14], kuz_lvec[14]);
              w[14] = w[13];
              x ^= kuz_mul_gf256_fast(w[13], kuz_lvec[13]);
              w[13] = w[12];
              x ^= kuz_mul_gf256_fast(w[12], kuz_lvec[12]);
              w[12] = w[11];
              x ^= kuz_mul_gf256_fast(w[11], kuz_lvec[11]);
              w[11] = w[10];
              x ^= kuz_mul_gf256_fast(w[10], kuz_lvec[10]);
              w[10] = w[9];
              x ^= kuz_mul_gf256_fast(w[9], kuz_lvec[9]);
              w[9] = w[8];
              x ^= kuz_mul_gf256_fast(w[8], kuz_lvec[8]);
              w[8] = w[7];
              x ^= kuz_mul_gf256_fast(w[7], kuz_lvec[7]);
              w[7] = w[6];
              x ^= kuz_mul_gf256_fast(w[6], kuz_lvec[6]);
              w[6] = w[5];
              x ^= kuz_mul_gf256_fast(w[5], kuz_lvec[5]);
              w[5] = w[4];
              x ^= kuz_mul_gf256_fast(w[4], kuz_lvec[4]);
              w[4] = w[3];
              x ^= kuz_mul_gf256_fast(w[3], kuz_lvec[3]);
              w[3] = w[2];
              x ^= kuz_mul_gf256_fast(w[2], kuz_lvec[2]);
              w[2] = w[1];
              x ^= kuz_mul_gf256_fast(w[1], kuz_lvec[1]);
              w[1] = w[0];
              x ^= kuz_mul_gf256_fast(w[0], kuz_lvec[0]);
              w[0] = x;
          }
      }
  
      static void kuz_l_inv(byte[] w) {
          for (int j = 0; j < 16; j++) {
              byte x = w[0];
              for (int i = 0; i < 15; i++) {
                  w[i] = w[i + 1];
                  x ^= kuz_mul_gf256_fast(w[i], kuz_lvec[i]);
              }
              w[15] = x;
          }
      }
  
      static byte kuz_mul_gf256_fast(byte a, byte b) {
          if (a == 0 || b == 0) return 0;
          int t = (gf256_L[(a & 0xff)] & 0xff) + (gf256_L[(b & 0xff)] & 0xff);
          if (t > 255) t = t - 255;
          return gf256_E[(t & 0xff)];
      }
  
      private static final int BLOCK_SIZE = 16;
  
      private int[][] key;
      private int C0;
      private int C1;
      private int C2;
      private int C3;
  
      public KuznechikFastEngine(byte[] key) {
          this.key = convertKey(key);
      }
  
      @Override
      public int getBlockSize() {
          return BLOCK_SIZE;
      }
  
      @Override
      public void encryptBlock(byte[] data, int offset, byte[] dest, int destOffset) {
  
          int A0, A1, A2, A3, T0, T1, T2, T3;
  
          unpackBlock(data, offset);
  
          for (int i = 0; i < 9; i++) {
  
              C0 = C0 ^ key[i][0];
              C1 = C1 ^ key[i][1];
              C2 = C2 ^ key[i][2];
              C3 = C3 ^ key[i][3];
  
              C0 = (kuz_pi[C0 & 0xFF] & 0xFF)
                      + ((kuz_pi[(C0 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(C0 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(C0 >> 24) & 0xFF] & 0xFF) << 24);
  
              C1 = (kuz_pi[C1 & 0xFF] & 0xFF)
                      + ((kuz_pi[(C1 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(C1 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(C1 >> 24) & 0xFF] & 0xFF) << 24);
  
              C2 = (kuz_pi[C2 & 0xFF] & 0xFF)
                      + ((kuz_pi[(C2 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(C2 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(C2 >> 24) & 0xFF] & 0xFF) << 24);
  
              C3 = (kuz_pi[C3 & 0xFF] & 0xFF)
                      + ((kuz_pi[(C3 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(C3 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(C3 >> 24) & 0xFF] & 0xFF) << 24);
  
              T0 = (0 + (((C0 >> 24) & 0xFF) << 4)) << 2;
              T1 = (1 + (((C0 >> 16) & 0xFF) << 4)) << 2;
              T2 = (2 + (((C0 >> 8) & 0xFF) << 4)) << 2;
              T3 = (3 + (((C0 >> 0) & 0xFF) << 4)) << 2;
  
              A0 = gf256res[T0 + 0] ^ gf256res[T1 + 0] ^ gf256res[T2 + 0] ^ gf256res[T3 + 0];
              A1 = gf256res[T0 + 1] ^ gf256res[T1 + 1] ^ gf256res[T2 + 1] ^ gf256res[T3 + 1];
              A2 = gf256res[T0 + 2] ^ gf256res[T1 + 2] ^ gf256res[T2 + 2] ^ gf256res[T3 + 2];
              A3 = gf256res[T0 + 3] ^ gf256res[T1 + 3] ^ gf256res[T2 + 3] ^ gf256res[T3 + 3];
  
  
              T0 = (4 + (((C1 >> 24) & 0xFF) << 4)) << 2;
              T1 = (5 + (((C1 >> 16) & 0xFF) << 4)) << 2;
              T2 = (6 + (((C1 >> 8) & 0xFF) << 4)) << 2;
              T3 = (7 + (((C1 >> 0) & 0xFF) << 4)) << 2;
              A0 = A0 ^ gf256res[T0 + 0] ^ gf256res[T1 + 0] ^ gf256res[T2 + 0] ^ gf256res[T3 + 0];
              A1 = A1 ^ gf256res[T0 + 1] ^ gf256res[T1 + 1] ^ gf256res[T2 + 1] ^ gf256res[T3 + 1];
              A2 = A2 ^ gf256res[T0 + 2] ^ gf256res[T1 + 2] ^ gf256res[T2 + 2] ^ gf256res[T3 + 2];
              A3 = A3 ^ gf256res[T0 + 3] ^ gf256res[T1 + 3] ^ gf256res[T2 + 3] ^ gf256res[T3 + 3];
  
  
              T0 = (8 + (((C2 >> 24) & 0xFF) << 4)) << 2;
              T1 = (9 + (((C2 >> 16) & 0xFF) << 4)) << 2;
              T2 = (10 + (((C2 >> 8) & 0xFF) << 4)) << 2;
              T3 = (11 + (((C2 >> 0) & 0xFF) << 4)) << 2;
              A0 = A0 ^ gf256res[T0 + 0] ^ gf256res[T1 + 0] ^ gf256res[T2 + 0] ^ gf256res[T3 + 0];
              A1 = A1 ^ gf256res[T0 + 1] ^ gf256res[T1 + 1] ^ gf256res[T2 + 1] ^ gf256res[T3 + 1];
              A2 = A2 ^ gf256res[T0 + 2] ^ gf256res[T1 + 2] ^ gf256res[T2 + 2] ^ gf256res[T3 + 2];
              A3 = A3 ^ gf256res[T0 + 3] ^ gf256res[T1 + 3] ^ gf256res[T2 + 3] ^ gf256res[T3 + 3];
  
  
              T0 = (12 + (((C3 >> 24) & 0xFF) << 4)) << 2;
              T1 = (13 + (((C3 >> 16) & 0xFF) << 4)) << 2;
              T2 = (14 + (((C3 >> 8) & 0xFF) << 4)) << 2;
              T3 = (15 + (((C3 >> 0) & 0xFF) << 4)) << 2;
              C0 = A0 ^ gf256res[T0 + 0] ^ gf256res[T1 + 0] ^ gf256res[T2 + 0] ^ gf256res[T3 + 0];
              C1 = A1 ^ gf256res[T0 + 1] ^ gf256res[T1 + 1] ^ gf256res[T2 + 1] ^ gf256res[T3 + 1];
              C2 = A2 ^ gf256res[T0 + 2] ^ gf256res[T1 + 2] ^ gf256res[T2 + 2] ^ gf256res[T3 + 2];
              C3 = A3 ^ gf256res[T0 + 3] ^ gf256res[T1 + 3] ^ gf256res[T2 + 3] ^ gf256res[T3 + 3];
          }
  
          C0 = C0 ^ key[9][0];
          C1 = C1 ^ key[9][1];
          C2 = C2 ^ key[9][2];
          C3 = C3 ^ key[9][3];
  
          packBlock(dest, destOffset);
      }
  
      @Override
      public void decryptBlock(byte[] data, int offset, byte[] dest, int destOffset) {
  
          int A0, A1, A2, A3, T0, T1, T2, T3;
  
          unpackBlock(data, offset);
  
          C0 = C0 ^ key[9][0];
          C1 = C1 ^ key[9][1];
          C2 = C2 ^ key[9][2];
          C3 = C3 ^ key[9][3];
  
          for (int i = 8; i >= 0; i--) {
  
              T0 = (0 + (((C0 >> 24) & 0xFF) << 4)) << 2;
              T1 = (1 + (((C0 >> 16) & 0xFF) << 4)) << 2;
              T2 = (2 + (((C0 >> 8) & 0xFF) << 4)) << 2;
              T3 = (3 + (((C0 >> 0) & 0xFF) << 4)) << 2;
  
              A0 = gf256resInv[T0 + 0] ^ gf256resInv[T1 + 0] ^ gf256resInv[T2 + 0] ^ gf256resInv[T3 + 0];
              A1 = gf256resInv[T0 + 1] ^ gf256resInv[T1 + 1] ^ gf256resInv[T2 + 1] ^ gf256resInv[T3 + 1];
              A2 = gf256resInv[T0 + 2] ^ gf256resInv[T1 + 2] ^ gf256resInv[T2 + 2] ^ gf256resInv[T3 + 2];
              A3 = gf256resInv[T0 + 3] ^ gf256resInv[T1 + 3] ^ gf256resInv[T2 + 3] ^ gf256resInv[T3 + 3];
  
  
              T0 = (4 + (((C1 >> 24) & 0xFF) << 4)) << 2;
              T1 = (5 + (((C1 >> 16) & 0xFF) << 4)) << 2;
              T2 = (6 + (((C1 >> 8) & 0xFF) << 4)) << 2;
              T3 = (7 + (((C1 >> 0) & 0xFF) << 4)) << 2;
              A0 = A0 ^ gf256resInv[T0 + 0] ^ gf256resInv[T1 + 0] ^ gf256resInv[T2 + 0] ^ gf256resInv[T3 + 0];
              A1 = A1 ^ gf256resInv[T0 + 1] ^ gf256resInv[T1 + 1] ^ gf256resInv[T2 + 1] ^ gf256resInv[T3 + 1];
              A2 = A2 ^ gf256resInv[T0 + 2] ^ gf256resInv[T1 + 2] ^ gf256resInv[T2 + 2] ^ gf256resInv[T3 + 2];
              A3 = A3 ^ gf256resInv[T0 + 3] ^ gf256resInv[T1 + 3] ^ gf256resInv[T2 + 3] ^ gf256resInv[T3 + 3];
  
  
              T0 = (8 + (((C2 >> 24) & 0xFF) << 4)) << 2;
              T1 = (9 + (((C2 >> 16) & 0xFF) << 4)) << 2;
              T2 = (10 + (((C2 >> 8) & 0xFF) << 4)) << 2;
              T3 = (11 + (((C2 >> 0) & 0xFF) << 4)) << 2;
              A0 = A0 ^ gf256resInv[T0 + 0] ^ gf256resInv[T1 + 0] ^ gf256resInv[T2 + 0] ^ gf256resInv[T3 + 0];
              A1 = A1 ^ gf256resInv[T0 + 1] ^ gf256resInv[T1 + 1] ^ gf256resInv[T2 + 1] ^ gf256resInv[T3 + 1];
              A2 = A2 ^ gf256resInv[T0 + 2] ^ gf256resInv[T1 + 2] ^ gf256resInv[T2 + 2] ^ gf256resInv[T3 + 2];
              A3 = A3 ^ gf256resInv[T0 + 3] ^ gf256resInv[T1 + 3] ^ gf256resInv[T2 + 3] ^ gf256resInv[T3 + 3];
  
  
              T0 = (12 + (((C3 >> 24) & 0xFF) << 4)) << 2;
              T1 = (13 + (((C3 >> 16) & 0xFF) << 4)) << 2;
              T2 = (14 + (((C3 >> 8) & 0xFF) << 4)) << 2;
              T3 = (15 + (((C3 >> 0) & 0xFF) << 4)) << 2;
              C0 = A0 ^ gf256resInv[T0 + 0] ^ gf256resInv[T1 + 0] ^ gf256resInv[T2 + 0] ^ gf256resInv[T3 + 0];
              C1 = A1 ^ gf256resInv[T0 + 1] ^ gf256resInv[T1 + 1] ^ gf256resInv[T2 + 1] ^ gf256resInv[T3 + 1];
              C2 = A2 ^ gf256resInv[T0 + 2] ^ gf256resInv[T1 + 2] ^ gf256resInv[T2 + 2] ^ gf256resInv[T3 + 2];
              C3 = A3 ^ gf256resInv[T0 + 3] ^ gf256resInv[T1 + 3] ^ gf256resInv[T2 + 3] ^ gf256resInv[T3 + 3];
  
  
              C0 = (kuz_pi_inv[C0 & 0xFF] & 0xFF)
                      + ((kuz_pi_inv[(C0 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi_inv[(C0 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi_inv[(C0 >> 24) & 0xFF] & 0xFF) << 24);
  
              C1 = (kuz_pi_inv[C1 & 0xFF] & 0xFF)
                      + ((kuz_pi_inv[(C1 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi_inv[(C1 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi_inv[(C1 >> 24) & 0xFF] & 0xFF) << 24);
  
              C2 = (kuz_pi_inv[C2 & 0xFF] & 0xFF)
                      + ((kuz_pi_inv[(C2 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi_inv[(C2 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi_inv[(C2 >> 24) & 0xFF] & 0xFF) << 24);
  
              C3 = (kuz_pi_inv[C3 & 0xFF] & 0xFF)
                      + ((kuz_pi_inv[(C3 >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi_inv[(C3 >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi_inv[(C3 >> 24) & 0xFF] & 0xFF) << 24);
  
  
              C0 = C0 ^ key[i][0];
              C1 = C1 ^ key[i][1];
              C2 = C2 ^ key[i][2];
              C3 = C3 ^ key[i][3];
          }
  
          packBlock(dest, destOffset);
      }
  
      private void unpackBlock(byte[] bytes, int off) {
          this.C0 = Pack.bigEndianToInt(bytes, off);
          this.C1 = Pack.bigEndianToInt(bytes, off + 4);
          this.C2 = Pack.bigEndianToInt(bytes, off + 8);
          this.C3 = Pack.bigEndianToInt(bytes, off + 12);
      }
  
      private void packBlock(byte[] dest, int destOffset) {
          Pack.intToBigEndian(C0, dest, destOffset);
          Pack.intToBigEndian(C1, dest, destOffset + 4);
          Pack.intToBigEndian(C2, dest, destOffset + 8);
          Pack.intToBigEndian(C3, dest, destOffset + 12);
      }
  
      int[][] getKey() {
          return key;
      }
  
      static int[][] convertKey(byte[] key) {
          if (key.length != 32) {
              throw new RuntimeException("Key might be 32 bytes length");
          }
  
          int[][] kuz = new int[10][4];
  
          // w128_t c, x, y, z;
          int[] c = new int[4];
          int[] x = new int[4];
          int[] y = new int[4];
          int[] z = new int[4];
  
          kuz[0][0] = x[0] = Pack.bigEndianToInt(key, 0);
          kuz[0][1] = x[1] = Pack.bigEndianToInt(key, 4);
          kuz[0][2] = x[2] = Pack.bigEndianToInt(key, 8);
          kuz[0][3] = x[3] = Pack.bigEndianToInt(key, 12);
  
          kuz[1][0] = y[0] = Pack.bigEndianToInt(key, 16);
          kuz[1][1] = y[1] = Pack.bigEndianToInt(key, 20);
          kuz[1][2] = y[2] = Pack.bigEndianToInt(key, 24);
          kuz[1][3] = y[3] = Pack.bigEndianToInt(key, 28);
  
          for (int i = 1; i <= 32; i++) {
  
              c[0] = 0;
              c[1] = 0;
              c[2] = 0;
              c[3] = i;
  
              kuz_l_fast(c);
  
              z[0] = x[0] ^ c[0];
              z[1] = x[1] ^ c[1];
              z[2] = x[2] ^ c[2];
              z[3] = x[3] ^ c[3];
  
              z[0] = (kuz_pi[z[0] & 0xFF] & 0xFF)
                      + ((kuz_pi[(z[0] >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(z[0] >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(z[0] >> 24) & 0xFF] & 0xFF) << 24);
  
              z[1] = (kuz_pi[z[1] & 0xFF] & 0xFF)
                      + ((kuz_pi[(z[1] >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(z[1] >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(z[1] >> 24) & 0xFF] & 0xFF) << 24);
  
              z[2] = (kuz_pi[z[2] & 0xFF] & 0xFF)
                      + ((kuz_pi[(z[2] >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(z[2] >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(z[2] >> 24) & 0xFF] & 0xFF) << 24);
  
              z[3] = (kuz_pi[z[3] & 0xFF] & 0xFF)
                      + ((kuz_pi[(z[3] >> 8) & 0xFF] & 0xFF) << 8)
                      + ((kuz_pi[(z[3] >> 16) & 0xFF] & 0xFF) << 16)
                      + ((kuz_pi[(z[3] >> 24) & 0xFF] & 0xFF) << 24);
  
              kuz_l_fast(z);
  
              z[0] = z[0] ^ y[0];
              z[1] = z[1] ^ y[1];
              z[2] = z[2] ^ y[2];
              z[3] = z[3] ^ y[3];
  
              y[0] = x[0];
              y[1] = x[1];
              y[2] = x[2];
              y[3] = x[3];
  
              x[0] = z[0];
              x[1] = z[1];
              x[2] = z[2];
              x[3] = z[3];
  
              if ((i & 7) == 0) {
                  kuz[i >> 2][0] = x[0];
                  kuz[i >> 2][1] = x[1];
                  kuz[i >> 2][2] = x[2];
                  kuz[i >> 2][3] = x[3];
  
                  kuz[(i >> 2) + 1][0] = y[0];
                  kuz[(i >> 2) + 1][1] = y[1];
                  kuz[(i >> 2) + 1][2] = y[2];
                  kuz[(i >> 2) + 1][3] = y[3];
              }
          }
  
          return kuz;
      }
  }