package im.actor.runtime.crypto.primitives.kuznechik;
import im.actor.runtime.Crypto;
import im.actor.runtime.crypto.BlockCipher;
import im.actor.runtime.crypto.primitives.util.Pack;
// Disabling Bounds checks for speeding up calculations
/*-[
#define J2OBJC_DISABLE_ALL_CHECKS 1
]-*/
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 int[] gf256res;
private static int[] gf256resInv;
public static void initCalc() {
if (gf256res != null || gf256resInv != null) {
return;
}
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);
}
}
}
public static void initDump(final byte[] data) {
if (gf256res != null || gf256resInv != null) {
return;
}
gf256res = new int[16 * 256 * 4];
gf256resInv = new int[16 * 256 * 4];
int offset = 0;
int n;
for (int i = 0; i < gf256res.length; ++i) {
n = data[offset++] << 24;
n |= (data[offset++] & 0xff) << 16;
n |= (data[offset++] & 0xff) << 8;
n |= (data[offset++] & 0xff);
gf256res[i] = n;
}
for (int i = 0; i < gf256resInv.length; ++i) {
n = data[offset++] << 24;
n |= (data[offset++] & 0xff) << 16;
n |= (data[offset++] & 0xff) << 8;
n |= (data[offset++] & 0xff);
gf256resInv[i] = n;
}
}
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) {
Crypto.waitForCryptoLoaded();
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;
}
}