diff --git a/Filelist.txt b/Filelist.txt index 83acac8d..fd6471ed 100644 --- a/Filelist.txt +++ b/Filelist.txt @@ -287,6 +287,7 @@ simple.cpp simple.h siphash.h simeck.cpp +simeck-simd.cpp simeck.h simon.cpp simon-simd.cpp diff --git a/GNUmakefile b/GNUmakefile index cdd798b1..df63a11a 100755 --- a/GNUmakefile +++ b/GNUmakefile @@ -252,6 +252,7 @@ ifeq ($(findstring -DCRYPTOPP_DISABLE_SSSE3,$(CXXFLAGS)),) CHAM_FLAG = -mssse3 LEA_FLAG = -mssse3 SSSE3_FLAG = -mssse3 + SIMECK_FLAG = -mssse3 SIMON_FLAG = -mssse3 SPECK_FLAG = -mssse3 endif @@ -293,6 +294,7 @@ ifeq ($(SUN_COMPILER),1) ARIA_FLAG = -xarch=ssse3 -D__SSSE3__=1 CHAM_FLAG = -xarch=ssse3 -D__SSSE3__=1 LEA_FLAG = -xarch=ssse3 -D__SSSE3__=1 + SIMECK_FLAG = -xarch=ssse3 -D__SSSE3__=1 SIMON_FLAG = -xarch=ssse3 -D__SSSE3__=1 SPECK_FLAG = -xarch=ssse3 -D__SSSE3__=1 LDFLAGS += -xarch=ssse3 @@ -379,6 +381,7 @@ ifeq ($(IS_NEON),1) ARIA_FLAG = -march=armv7-a -mfloat-abi=$(FP_ABI) -mfpu=neon BLAKE2_FLAG = -march=armv7-a -mfloat-abi=$(FP_ABI) -mfpu=neon LEA_FLAG = -march=armv7-a -mfloat-abi=$(FP_ABI) -mfpu=neon + SIMECK_FLAG = -march=armv7-a -mfloat-abi=$(FP_ABI) -mfpu=neon SIMON_FLAG = -march=armv7-a -mfloat-abi=$(FP_ABI) -mfpu=neon SPECK_FLAG = -march=armv7-a -mfloat-abi=$(FP_ABI) -mfpu=neon endif @@ -391,6 +394,7 @@ ifeq ($(IS_ARMV8),1) BLAKE2_FLAG = -march=armv8-a LEA_FLAG = -march=armv8-a NEON_FLAG = -march=armv8-a + SIMECK_FLAG = -march=armv8-a SIMON_FLAG = -march=armv8-a SPECK_FLAG = -march=armv8-a endif @@ -416,6 +420,7 @@ ifneq ($(IS_PPC32)$(IS_PPC64)$(IS_AIX),000) ARIA_FLAG = -mcpu=power4 -maltivec BLAKE2_FLAG = -mcpu=power4 -maltivec SIMON_FLAG = -mcpu=power4 -maltivec + SIMECK_FLAG = -mcpu=power4 -maltivec SPECK_FLAG = -mcpu=power4 -maltivec endif # GCC and some compatibles @@ -425,6 +430,7 @@ ifneq ($(IS_PPC32)$(IS_PPC64)$(IS_AIX),000) AES_FLAG = -mcpu=power8 -maltivec GCM_FLAG = -mcpu=power8 -maltivec SHA_FLAG = -mcpu=power8 -maltivec + SIMECK_FLAG = -mcpu=power8 -maltivec SIMON_FLAG = -mcpu=power8 -maltivec SPECK_FLAG = -mcpu=power8 -maltivec endif @@ -434,6 +440,7 @@ ifneq ($(IS_PPC32)$(IS_PPC64)$(IS_AIX),000) ALTIVEC_FLAG = -qarch=pwr7 -qaltivec ARIA_FLAG = -qarch=pwr7 -qaltivec BLAKE2_FLAG = -qarch=pwr7 -qaltivec + SIMECK_FLAG = -qarch=pwr7 -qaltivec SIMON_FLAG = -qarch=pwr7 -qaltivec SPECK_FLAG = -qarch=pwr7 -qaltivec endif @@ -446,6 +453,7 @@ ifneq ($(IS_PPC32)$(IS_PPC64)$(IS_AIX),000) SHA_FLAG = -qarch=pwr8 -qaltivec ARIA_FLAG = -qarch=pwr8 -qaltivec BLAKE2_FLAG = -qarch=pwr8 -qaltivec + SIMECK_FLAG = -qarch=pwr8 -qaltivec SIMON_FLAG = -qarch=pwr8 -qaltivec SPECK_FLAG = -qarch=pwr8 -qaltivec endif @@ -1096,6 +1104,10 @@ sha-simd.o : sha-simd.cpp shacal2-simd.o : shacal2-simd.cpp $(CXX) $(strip $(CXXFLAGS) $(SHA_FLAG) -c) $< +# SSSE3 or NEON available +simeck-simd.o : simeck-simd.cpp + $(CXX) $(strip $(CXXFLAGS) $(SIMECK_FLAG) -c) $< + # SSSE3 or NEON available simon-simd.o : simon-simd.cpp $(CXX) $(strip $(CXXFLAGS) $(SIMON_FLAG) -c) $< diff --git a/bench1.cpp b/bench1.cpp index 4cee1702..a322e70b 100644 --- a/bench1.cpp +++ b/bench1.cpp @@ -525,6 +525,10 @@ void Benchmark2(double t, double hertz) std::cout << "\nAlgorithmMiB/Second" << cpb; std::cout << "Microseconds to
Setup Key and IV" << cpk; + BenchMarkByName("SIMECK-32/CTR", 8, "SIMECK-32(64)/CTR (64-bit key)"); + BenchMarkByName("SIMECK-64/CTR", 16, "SIMECK-64(128)/CTR (128-bit key)"); + return; + std::cout << "\n"; { #if CRYPTOPP_AESNI_AVAILABLE diff --git a/cryptest.nmake b/cryptest.nmake index f94466ed..b2015dbf 100644 --- a/cryptest.nmake +++ b/cryptest.nmake @@ -47,9 +47,9 @@ # If you use 'make sources' from Linux makefile, then add 'winpipes.cpp' to the list below. -LIB_SRCS = cryptlib.cpp cpu.cpp integer.cpp 3way.cpp adler32.cpp algebra.cpp algparam.cpp arc4.cpp aria-simd.cpp aria.cpp ariatab.cpp asn.cpp authenc.cpp base32.cpp base64.cpp basecode.cpp bfinit.cpp blake2-simd.cpp blake2.cpp blowfish.cpp blumshub.cpp camellia.cpp cast.cpp casts.cpp cbcmac.cpp ccm.cpp chacha.cpp cham.cpp cham-simd.cpp channels.cpp cmac.cpp crc-simd.cpp crc.cpp default.cpp des.cpp dessp.cpp dh.cpp dh2.cpp dll.cpp dsa.cpp eax.cpp ec2n.cpp eccrypto.cpp ecp.cpp elgamal.cpp emsa2.cpp eprecomp.cpp esign.cpp files.cpp filters.cpp fips140.cpp fipstest.cpp gcm-simd.cpp gcm.cpp gf256.cpp gf2_32.cpp gf2n.cpp gfpcrypt.cpp gost.cpp gzip.cpp hex.cpp hight.cpp hmac.cpp hrtimer.cpp ida.cpp idea.cpp iterhash.cpp kalyna.cpp kalynatab.cpp keccak.cpp lea.cpp lea-simd.cpp luc.cpp mars.cpp marss.cpp md2.cpp md4.cpp md5.cpp misc.cpp modes.cpp mqueue.cpp mqv.cpp nbtheory.cpp neon-simd.cpp network.cpp oaep.cpp osrng.cpp padlkrng.cpp panama.cpp pkcspad.cpp poly1305.cpp polynomi.cpp pssr.cpp pubkey.cpp queue.cpp rabin.cpp randpool.cpp rc2.cpp rc5.cpp rc6.cpp rdrand.cpp rdtables.cpp rijndael-simd.cpp rijndael.cpp ripemd.cpp rng.cpp rsa.cpp rw.cpp safer.cpp salsa.cpp scrypt.cpp seal.cpp seed.cpp serpent.cpp sha-simd.cpp sha.cpp sha3.cpp shacal2-simd.cpp shacal2.cpp shark.cpp sharkbox.cpp simeck.cpp simon.cpp simon-simd.cpp skipjack.cpp sm3.cpp sm4.cpp socketft.cpp sosemanuk.cpp speck.cpp speck-simd.cpp square.cpp squaretb.cpp sse-simd.cpp strciphr.cpp tea.cpp tftables.cpp threefish.cpp tiger.cpp tigertab.cpp trdlocal.cpp ttmac.cpp tweetnacl.cpp twofish.cpp vmac.cpp wait.cpp wake.cpp whrlpool.cpp winpipes.cpp xtr.cpp xtrcrypt.cpp zdeflate.cpp zinflate.cpp zlib.cpp +LIB_SRCS = cryptlib.cpp cpu.cpp integer.cpp 3way.cpp adler32.cpp algebra.cpp algparam.cpp arc4.cpp aria-simd.cpp aria.cpp ariatab.cpp asn.cpp authenc.cpp base32.cpp base64.cpp basecode.cpp bfinit.cpp blake2-simd.cpp blake2.cpp blowfish.cpp blumshub.cpp camellia.cpp cast.cpp casts.cpp cbcmac.cpp ccm.cpp chacha.cpp cham.cpp cham-simd.cpp channels.cpp cmac.cpp crc-simd.cpp crc.cpp default.cpp des.cpp dessp.cpp dh.cpp dh2.cpp dll.cpp dsa.cpp eax.cpp ec2n.cpp eccrypto.cpp ecp.cpp elgamal.cpp emsa2.cpp eprecomp.cpp esign.cpp files.cpp filters.cpp fips140.cpp fipstest.cpp gcm-simd.cpp gcm.cpp gf256.cpp gf2_32.cpp gf2n.cpp gfpcrypt.cpp gost.cpp gzip.cpp hex.cpp hight.cpp hmac.cpp hrtimer.cpp ida.cpp idea.cpp iterhash.cpp kalyna.cpp kalynatab.cpp keccak.cpp lea.cpp lea-simd.cpp luc.cpp mars.cpp marss.cpp md2.cpp md4.cpp md5.cpp misc.cpp modes.cpp mqueue.cpp mqv.cpp nbtheory.cpp neon-simd.cpp network.cpp oaep.cpp osrng.cpp padlkrng.cpp panama.cpp pkcspad.cpp poly1305.cpp polynomi.cpp pssr.cpp pubkey.cpp queue.cpp rabin.cpp randpool.cpp rc2.cpp rc5.cpp rc6.cpp rdrand.cpp rdtables.cpp rijndael-simd.cpp rijndael.cpp ripemd.cpp rng.cpp rsa.cpp rw.cpp safer.cpp salsa.cpp scrypt.cpp seal.cpp seed.cpp serpent.cpp sha-simd.cpp sha.cpp sha3.cpp shacal2-simd.cpp shacal2.cpp shark.cpp sharkbox.cpp simeck-simd.cpp simeck.cpp simon.cpp simon-simd.cpp skipjack.cpp sm3.cpp sm4.cpp socketft.cpp sosemanuk.cpp speck.cpp speck-simd.cpp square.cpp squaretb.cpp sse-simd.cpp strciphr.cpp tea.cpp tftables.cpp threefish.cpp tiger.cpp tigertab.cpp trdlocal.cpp ttmac.cpp tweetnacl.cpp twofish.cpp vmac.cpp wait.cpp wake.cpp whrlpool.cpp winpipes.cpp xtr.cpp xtrcrypt.cpp zdeflate.cpp zinflate.cpp zlib.cpp -LIB_OBJS = cryptlib.obj cpu.obj integer.obj 3way.obj adler32.obj algebra.obj algparam.obj arc4.obj aria-simd.obj aria.obj ariatab.obj asn.obj authenc.obj base32.obj base64.obj basecode.obj bfinit.obj blake2-simd.obj blake2.obj blowfish.obj blumshub.obj camellia.obj cast.obj casts.obj cbcmac.obj ccm.obj chacha.obj cham.obj cham-simd.obj channels.obj cmac.obj crc-simd.obj crc.obj default.obj des.obj dessp.obj dh.obj dh2.obj dll.obj dsa.obj eax.obj ec2n.obj eccrypto.obj ecp.obj elgamal.obj emsa2.obj eprecomp.obj esign.obj files.obj filters.obj fips140.obj fipstest.obj gcm-simd.obj gcm.obj gf256.obj gf2_32.obj gf2n.obj gfpcrypt.obj gost.obj gzip.obj hex.obj hight.obj hmac.obj hrtimer.obj ida.obj idea.obj iterhash.obj kalyna.obj kalynatab.obj keccak.obj lea.obj lea-simd.obj luc.obj mars.obj marss.obj md2.obj md4.obj md5.obj misc.obj modes.obj mqueue.obj mqv.obj nbtheory.obj neon-simd.obj network.obj oaep.obj osrng.obj padlkrng.obj panama.obj pkcspad.obj poly1305.obj polynomi.obj pssr.obj pubkey.obj queue.obj rabin.obj randpool.obj rc2.obj rc5.obj rc6.obj rdrand.obj rdtables.obj rijndael-simd.obj rijndael.obj ripemd.obj rng.obj rsa.obj rw.obj safer.obj salsa.obj scrypt.obj seal.obj seed.obj serpent.obj sha-simd.obj sha.obj sha3.obj shacal2-simd.obj shacal2.obj shark.obj sharkbox.obj simeck.obj simon.obj simon-simd.obj skipjack.obj sm3.obj sm4.obj socketft.obj sosemanuk.obj speck.obj speck-simd.obj square.obj squaretb.obj sse-simd.obj strciphr.obj tea.obj tftables.obj threefish.obj tiger.obj tigertab.obj trdlocal.obj ttmac.obj tweetnacl.obj twofish.obj vmac.obj wait.obj wake.obj whrlpool.obj winpipes.obj xtr.obj xtrcrypt.obj zdeflate.obj zinflate.obj zlib.obj +LIB_OBJS = cryptlib.obj cpu.obj integer.obj 3way.obj adler32.obj algebra.obj algparam.obj arc4.obj aria-simd.obj aria.obj ariatab.obj asn.obj authenc.obj base32.obj base64.obj basecode.obj bfinit.obj blake2-simd.obj blake2.obj blowfish.obj blumshub.obj camellia.obj cast.obj casts.obj cbcmac.obj ccm.obj chacha.obj cham.obj cham-simd.obj channels.obj cmac.obj crc-simd.obj crc.obj default.obj des.obj dessp.obj dh.obj dh2.obj dll.obj dsa.obj eax.obj ec2n.obj eccrypto.obj ecp.obj elgamal.obj emsa2.obj eprecomp.obj esign.obj files.obj filters.obj fips140.obj fipstest.obj gcm-simd.obj gcm.obj gf256.obj gf2_32.obj gf2n.obj gfpcrypt.obj gost.obj gzip.obj hex.obj hight.obj hmac.obj hrtimer.obj ida.obj idea.obj iterhash.obj kalyna.obj kalynatab.obj keccak.obj lea.obj lea-simd.obj luc.obj mars.obj marss.obj md2.obj md4.obj md5.obj misc.obj modes.obj mqueue.obj mqv.obj nbtheory.obj neon-simd.obj network.obj oaep.obj osrng.obj padlkrng.obj panama.obj pkcspad.obj poly1305.obj polynomi.obj pssr.obj pubkey.obj queue.obj rabin.obj randpool.obj rc2.obj rc5.obj rc6.obj rdrand.obj rdtables.obj rijndael-simd.obj rijndael.obj ripemd.obj rng.obj rsa.obj rw.obj safer.obj salsa.obj scrypt.obj seal.obj seed.obj serpent.obj sha-simd.obj sha.obj sha3.obj shacal2-simd.obj shacal2.obj shark.obj sharkbox.obj simeck-simd.obj simeck.obj simon.obj simon-simd.obj skipjack.obj sm3.obj sm4.obj socketft.obj sosemanuk.obj speck.obj speck-simd.obj square.obj squaretb.obj sse-simd.obj strciphr.obj tea.obj tftables.obj threefish.obj tiger.obj tigertab.obj trdlocal.obj ttmac.obj tweetnacl.obj twofish.obj vmac.obj wait.obj wake.obj whrlpool.obj winpipes.obj xtr.obj xtrcrypt.obj zdeflate.obj zinflate.obj zlib.obj TEST_SRCS = bench1.cpp bench2.cpp test.cpp validat0.cpp validat1.cpp validat2.cpp validat3.cpp validat4.cpp datatest.cpp regtest1.cpp regtest2.cpp regtest3.cpp fipsalgt.cpp dlltest.cpp fipstest.cpp diff --git a/cryptlib.vcxproj b/cryptlib.vcxproj index c217bbf8..a0bff0d4 100644 --- a/cryptlib.vcxproj +++ b/cryptlib.vcxproj @@ -296,6 +296,7 @@ + diff --git a/cryptlib.vcxproj.filters b/cryptlib.vcxproj.filters index 054aad47..a8478033 100644 --- a/cryptlib.vcxproj.filters +++ b/cryptlib.vcxproj.filters @@ -380,6 +380,9 @@ Source Files + + Source Files + Source Files diff --git a/simeck-simd.cpp b/simeck-simd.cpp new file mode 100644 index 00000000..1994a911 --- /dev/null +++ b/simeck-simd.cpp @@ -0,0 +1,323 @@ +// simeck-simd.cpp - written and placed in the public domain by Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// SSSE3, ARM NEON and ARMv8a, and Power7 Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#include "simeck.h" +#include "misc.h" +#include "adv-simd.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both simon.cpp and simon-simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include +# include +#endif + +#if defined(__AVX512F__) && defined(__AVX512VL__) +# define CRYPTOPP_AVX512_ROTATE 1 +# include +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word16; +using CryptoPP::word32; + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +////////////////////////////////////////////////////////////////////////// + +template +inline __m128i RotateLeft32(const __m128i& val) +{ +#if defined(CRYPTOPP_AVX512_ROTATE) + return _mm_rol_epi32(val, R); +#else + return _mm_or_si128( + _mm_slli_epi32(val, R), _mm_srli_epi32(val, 32-R)); +#endif +} + +template +inline __m128i RotateRight32(const __m128i& val) +{ +#if defined(CRYPTOPP_AVX512_ROTATE) + return _mm_ror_epi32(val, R); +#else + return _mm_or_si128( + _mm_slli_epi32(val, 32-R), _mm_srli_epi32(val, R)); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline __m128i RotateLeft32<8>(const __m128i& val) +{ + const __m128i mask = _mm_set_epi8(14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3); + return _mm_shuffle_epi8(val, mask); +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline __m128i RotateRight32<8>(const __m128i& val) +{ + const __m128i mask = _mm_set_epi8(12,15,14,13, 8,11,10,9, 4,7,6,5, 0,3,2,1); + return _mm_shuffle_epi8(val, mask); +} + +template +inline __m128i UnpackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // Should not be instantiated + CRYPTOPP_ASSERT(0);; + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // SIMECK implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpacklo_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // SIMECK implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpackhi_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // SIMECK implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpacklo_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // SIMECK implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpackhi_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template +inline __m128i UnpackXMM(const __m128i& v) +{ + // Should not be instantiated + CRYPTOPP_ASSERT(0);; + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(4,5,6,7, 4,5,6,7, 4,5,6,7, 4,5,6,7)); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(8,9,10,11, 8,9,10,11, 8,9,10,11, 8,9,10,11)); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(12,13,14,15, 12,13,14,15, 12,13,14,15, 12,13,14,15)); +} + +template +inline __m128i RepackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + return UnpackXMM(a, b, c, d); +} + +template +inline __m128i RepackXMM(const __m128i& v) +{ + return UnpackXMM(v); +} + +inline void SIMECK64_Encrypt(__m128i &a, __m128i &b, + __m128i &c, __m128i &d, const __m128i key) +{ + //temp = left + //left = (left & rotlConstant<5>(left)) ^ rotlConstant<1>(left) ^ right ^ key; + //right = left + + const __m128i s = a, t = c; + a = _mm_xor_si128(_mm_and_si128(a, RotateLeft32<5>(a)), RotateLeft32<1>(a)); + c = _mm_xor_si128(_mm_and_si128(c, RotateLeft32<5>(c)), RotateLeft32<1>(c)); + a = _mm_xor_si128(a, _mm_xor_si128(b, key)); + c = _mm_xor_si128(c, _mm_xor_si128(d, key)); + b = s; d = t; +} + +inline __m128i SIMECK64_LoadKey(const word32* subkey) +{ + float f[2]; + std::memcpy(f, subkey, 4); + return _mm_castps_si128(_mm_load_ps1(f)); +} + +inline void SIMECK64_Enc_Block(__m128i &block0, + const word32 *subkeys, unsigned int rounds) +{ + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(block0); + __m128i b = UnpackXMM<1>(block0); + __m128i c = UnpackXMM<2>(block0); + __m128i d = UnpackXMM<3>(block0); + + for (int i=0; i(rounds); ++i) + SIMECK64_Encrypt(a, b, c, d, SIMECK64_LoadKey(subkeys + i)); + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + block0 = RepackXMM<0>(a,b,c,d); +} + +inline void SIMECK64_Dec_Block(__m128i &block0, + const word32 *subkeys, unsigned int rounds) +{ + // SIMECK requires a word swap on the decryption side + __m128i w = _mm_shuffle_epi32(block0, _MM_SHUFFLE(2, 3, 0, 1)); + + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(w); + __m128i b = UnpackXMM<1>(w); + __m128i c = UnpackXMM<2>(w); + __m128i d = UnpackXMM<3>(w); + + for (int i = static_cast(rounds)-1; i >= 0; --i) + SIMECK64_Encrypt(a, b, c, d, SIMECK64_LoadKey(subkeys + i)); + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + w = RepackXMM<0>(a,b,c,d); + + block0 = _mm_shuffle_epi32(w, _MM_SHUFFLE(2, 3, 0, 1)); +} + +inline void SIMECK64_Enc_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int rounds) +{ + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(block0, block1, block2, block3); + __m128i b = UnpackXMM<1>(block0, block1, block2, block3); + __m128i c = UnpackXMM<2>(block0, block1, block2, block3); + __m128i d = UnpackXMM<3>(block0, block1, block2, block3); + + for (int i=0; i(rounds); ++i) + SIMECK64_Encrypt(a, b, c, d, SIMECK64_LoadKey(subkeys + i)); + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + block0 = RepackXMM<0>(a, b, c, d); + block1 = RepackXMM<1>(a, b, c, d); + block2 = RepackXMM<2>(a, b, c, d); + block3 = RepackXMM<3>(a, b, c, d); +} + +inline void SIMECK64_Dec_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int rounds) +{ + // SIMECK requires a word swap on the decryption side + __m128i w = _mm_shuffle_epi32(block0, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i x = _mm_shuffle_epi32(block1, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i y = _mm_shuffle_epi32(block2, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i z = _mm_shuffle_epi32(block3, _MM_SHUFFLE(2, 3, 0, 1)); + + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(w, x, y, z); + __m128i b = UnpackXMM<1>(w, x, y, z); + __m128i c = UnpackXMM<2>(w, x, y, z); + __m128i d = UnpackXMM<3>(w, x, y, z); + + for (int i = static_cast(rounds)-1; i >= 0; --i) + SIMECK64_Encrypt(a, b, c, d, SIMECK64_LoadKey(subkeys + i)); + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + w = RepackXMM<0>(a, b, c, d); + x = RepackXMM<1>(a, b, c, d); + y = RepackXMM<2>(a, b, c, d); + z = RepackXMM<3>(a, b, c, d); + + block0 = _mm_shuffle_epi32(w, _MM_SHUFFLE(2, 3, 0, 1)); + block1 = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1)); + block2 = _mm_shuffle_epi32(y, _MM_SHUFFLE(2, 3, 0, 1)); + block3 = _mm_shuffle_epi32(z, _MM_SHUFFLE(2, 3, 0, 1)); +} + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) +size_t SIMECK64_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks64_4x1_SSE(SIMECK64_Enc_Block, SIMECK64_Enc_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SIMECK64_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks64_4x1_SSE(SIMECK64_Dec_Block, SIMECK64_Dec_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SSSE3_AVAILABLE + +NAMESPACE_END diff --git a/simeck.cpp b/simeck.cpp index 6bd99e69..e0d165f0 100644 --- a/simeck.cpp +++ b/simeck.cpp @@ -19,13 +19,12 @@ using CryptoPP::rotrConstant; /// \param key the key for the round or iteration /// \param left the first value /// \param right the second value -/// \param temp a temporary workspace /// \details SIMECK_Encryption serves as the key schedule, encryption and /// decryption functions. template -inline void SIMECK_Encryption(const T key, T& left, T& right, T& temp) +inline void SIMECK_Encryption(const T key, T& left, T& right) { - temp = left; + const T temp = left; left = (left & rotlConstant<5>(left)) ^ rotlConstant<1>(left) ^ right ^ key; right = temp; } @@ -34,6 +33,16 @@ ANONYMOUS_NAMESPACE_END NAMESPACE_BEGIN(CryptoPP) +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS +# if (CRYPTOPP_SSSE3_AVAILABLE) +extern size_t SIMECK64_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SIMECK64_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +# endif // CRYPTOPP_SSSE3_AVAILABLE +#endif // CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + void SIMECK32::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) { CRYPTOPP_UNUSED(params); @@ -52,7 +61,7 @@ void SIMECK32::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength constant |= sequence & 1; sequence >>= 1; - SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0], m_t[4]); + SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0]); // rotate the LFSR of m_t m_t[4] = m_t[1]; @@ -69,7 +78,7 @@ void SIMECK32::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock iblock(m_t[1])(m_t[0]); for (int idx = 0; idx < ROUNDS; ++idx) - SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0], m_t[4]); + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[1])(m_t[0]); @@ -82,7 +91,7 @@ void SIMECK32::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock iblock(m_t[0])(m_t[1]); for (int idx = ROUNDS - 1; idx >= 0; --idx) - SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0], m_t[4]); + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[0])(m_t[1]); @@ -106,7 +115,7 @@ void SIMECK64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength constant |= sequence & 1; sequence >>= 1; - SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0], m_t[4]); + SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0]); // rotate the LFSR of m_t m_t[4] = m_t[1]; @@ -123,7 +132,7 @@ void SIMECK64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock iblock(m_t[1])(m_t[0]); for (int idx = 0; idx < ROUNDS; ++idx) - SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0], m_t[4]); + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[1])(m_t[0]); @@ -136,10 +145,36 @@ void SIMECK64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock iblock(m_t[0])(m_t[1]); for (int idx = ROUNDS - 1; idx >= 0; --idx) - SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0], m_t[4]); + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[0])(m_t[1]); } +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS +size_t SIMECK64::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) { + return SIMECK64_Enc_AdvancedProcessBlocks_SSSE3(m_rk, ROUNDS, + inBlocks, xorBlocks, outBlocks, length, flags); + } +# endif // CRYPTOPP_SSSE3_AVAILABLE + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SIMECK64::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) { + return SIMECK64_Dec_AdvancedProcessBlocks_SSSE3(m_rk, ROUNDS, + inBlocks, xorBlocks, outBlocks, length, flags); + } +# endif // CRYPTOPP_SSSE3_AVAILABLE + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + NAMESPACE_END diff --git a/simeck.h b/simeck.h index b3345f4d..a6d44293 100644 --- a/simeck.h +++ b/simeck.h @@ -14,6 +14,10 @@ #include "secblock.h" #include "algparam.h" +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) +# define CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS 1 +#endif + NAMESPACE_BEGIN(CryptoPP) /// \brief SIMECK block cipher information @@ -57,7 +61,7 @@ public: void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); FixedSizeSecBlock m_rk; - mutable FixedSizeSecBlock m_t; + mutable FixedSizeSecBlock m_t; }; /// \brief Provides implementation for encryption transformation @@ -106,7 +110,7 @@ public: void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); FixedSizeSecBlock m_rk; - mutable FixedSizeSecBlock m_t; + mutable FixedSizeSecBlock m_t; }; /// \brief Provides implementation for encryption transformation @@ -117,6 +121,10 @@ public: { public: void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif }; /// \brief Provides implementation for encryption transformation @@ -127,6 +135,10 @@ public: { public: void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif }; typedef BlockCipherFinal Encryption;