Crypto++  7.0
Free C++ class library of cryptographic schemes
simon.cpp
1 // simon.h - written and placed in the public domain by Jeffrey Walton
2 
3 #include "pch.h"
4 #include "config.h"
5 
6 #include "simon.h"
7 #include "misc.h"
8 #include "cpu.h"
9 
10 // Uncomment for benchmarking C++ against SSE or NEON.
11 // Do so in both simon.cpp and simon-simd.cpp.
12 // #undef CRYPTOPP_SSSE3_AVAILABLE
13 // #undef CRYPTOPP_SSE41_AVAILABLE
14 // #undef CRYPTOPP_ARM_NEON_AVAILABLE
15 
16 ANONYMOUS_NAMESPACE_BEGIN
17 
18 using CryptoPP::word32;
19 using CryptoPP::word64;
22 
23 /// \brief Round transformation helper
24 /// \tparam W word type
25 /// \param v value
26 template <class W>
27 inline W f(const W v)
28 {
29  return (rotlConstant<1>(v) & rotlConstant<8>(v)) ^ rotlConstant<2>(v);
30 }
31 
32 /// \brief Round transformation
33 /// \tparam W word type
34 /// \param x value
35 /// \param y value
36 /// \param k value
37 /// \param l value
38 template <class W>
39 inline void R2(W& x, W& y, const W k, const W l)
40 {
41  y ^= f(x); y ^= k;
42  x ^= f(y); x ^= l;
43 }
44 
45 /// \brief Forward transformation
46 /// \tparam W word type
47 /// \tparam R number of rounds
48 /// \param c output array
49 /// \param p input array
50 /// \param k subkey array
51 template <class W, unsigned int R>
52 inline void SIMON_Encrypt(W c[2], const W p[2], const W k[R])
53 {
54  c[0]=p[0]; c[1]=p[1];
55 
56  for (int i = 0; i < static_cast<int>(R-1); i += 2)
57  R2(c[0], c[1], k[i], k[i + 1]);
58 
59  if (R & 1)
60  {
61  c[1] ^= f(c[0]); c[1] ^= k[R-1];
62  W t = c[0]; c[0] = c[1]; c[1] = t;
63  }
64 }
65 
66 /// \brief Reverse transformation
67 /// \tparam W word type
68 /// \tparam R number of rounds
69 /// \param p output array
70 /// \param c input array
71 /// \param k subkey array
72 template <class W, unsigned int R>
73 inline void SIMON_Decrypt(W p[2], const W c[2], const W k[R])
74 {
75  p[0]=c[0]; p[1]=c[1];
76  unsigned int rounds = R;
77 
78  if (R & 1)
79  {
80  const W t = p[1]; p[1] = p[0]; p[0] = t;
81  p[1] ^= k[R - 1]; p[1] ^= f(p[0]);
82  rounds--;
83  }
84 
85  for (int i = static_cast<int>(rounds - 2); i >= 0; i -= 2)
86  R2(p[1], p[0], k[i + 1], k[i]);
87 }
88 
89 /// \brief Subkey generation function
90 /// \details Used for SIMON-64 with 96-bit key and 42 rounds. A template was
91 /// not worthwhile because all instantiations would need specialization.
92 /// \param key empty subkey array
93 /// \param k user key array
94 inline void SIMON64_ExpandKey_3W(word32 key[42], const word32 k[3])
95 {
96  const word32 c = 0xfffffffc;
97  word64 z = W64LIT(0x7369f885192c0ef5);
98 
99  key[0] = k[2]; key[1] = k[1]; key[2] = k[0];
100  for (size_t i = 3; i<42; ++i)
101  {
102  key[i] = c ^ (z & 1) ^ key[i - 3] ^ rotrConstant<3>(key[i - 1]) ^ rotrConstant<4>(key[i - 1]);
103  z >>= 1;
104  }
105 }
106 
107 /// \brief Subkey generation function
108 /// \details Used for SIMON-64 with 128-bit key and 44 rounds. A template was
109 /// not worthwhile because all instantiations would need specialization.
110 /// \param key empty subkey array
111 /// \param k user key array
112 inline void SIMON64_ExpandKey_4W(word32 key[44], const word32 k[4])
113 {
114  const word32 c = 0xfffffffc;
115  word64 z = W64LIT(0xfc2ce51207a635db);
116 
117  key[0] = k[3]; key[1] = k[2]; key[2] = k[1]; key[3] = k[0];
118  for (size_t i = 4; i<44; ++i)
119  {
120  key[i] = c ^ (z & 1) ^ key[i - 4] ^ rotrConstant<3>(key[i - 1]) ^ key[i - 3] ^ rotrConstant<4>(key[i - 1]) ^ rotrConstant<1>(key[i - 3]);
121  z >>= 1;
122  }
123 }
124 
125 /// \brief Subkey generation function
126 /// \details Used for SIMON-128 with 128-bit key and 68 rounds. A template was
127 /// not worthwhile because all instantiations would need specialization.
128 /// \param key empty subkey array
129 /// \param k user key array
130 inline void SIMON128_ExpandKey_2W(word64 key[68], const word64 k[2])
131 {
132  const word64 c = W64LIT(0xfffffffffffffffc);
133  word64 z = W64LIT(0x7369f885192c0ef5);
134 
135  key[0] = k[1]; key[1] = k[0];
136  for (size_t i=2; i<66; ++i)
137  {
138  key[i] = c ^ (z & 1) ^ key[i - 2] ^ rotrConstant<3>(key[i - 1]) ^ rotrConstant<4>(key[i - 1]);
139  z>>=1;
140  }
141 
142  key[66] = c ^ 1 ^ key[64] ^ rotrConstant<3>(key[65]) ^ rotrConstant<4>(key[65]);
143  key[67] = c^key[65] ^ rotrConstant<3>(key[66]) ^ rotrConstant<4>(key[66]);
144 }
145 
146 /// \brief Subkey generation function
147 /// \details Used for SIMON-128 with 192-bit key and 69 rounds. A template was
148 /// not worthwhile because all instantiations would need specialization.
149 /// \param key empty subkey array
150 /// \param k user key array
151 inline void SIMON128_ExpandKey_3W(word64 key[69], const word64 k[3])
152 {
153  const word64 c = W64LIT(0xfffffffffffffffc);
154  word64 z = W64LIT(0xfc2ce51207a635db);
155 
156  key[0]=k[2]; key[1]=k[1]; key[2]=k[0];
157  for (size_t i=3; i<67; ++i)
158  {
159  key[i] = c ^ (z & 1) ^ key[i - 3] ^ rotrConstant<3>(key[i - 1]) ^ rotrConstant<4>(key[i - 1]);
160  z>>=1;
161  }
162 
163  key[67] = c^key[64] ^ rotrConstant<3>(key[66]) ^ rotrConstant<4>(key[66]);
164  key[68] = c ^ 1 ^ key[65] ^ rotrConstant<3>(key[67]) ^ rotrConstant<4>(key[67]);
165 }
166 
167 /// \brief Subkey generation function
168 /// \details Used for SIMON-128 with 256-bit key and 72 rounds. A template was
169 /// not worthwhile because all instantiations would need specialization.
170 /// \param key empty subkey array
171 /// \param k user key array
172 inline void SIMON128_ExpandKey_4W(word64 key[72], const word64 k[4])
173 {
174  const word64 c = W64LIT(0xfffffffffffffffc);
175  word64 z = W64LIT(0xfdc94c3a046d678b);
176 
177  key[0]=k[3]; key[1]=k[2]; key[2]=k[1]; key[3]=k[0];
178  for (size_t i=4; i<68; ++i)
179  {
180  key[i] = c ^ (z & 1) ^ key[i - 4] ^ rotrConstant<3>(key[i - 1]) ^ key[i - 3] ^ rotrConstant<4>(key[i - 1]) ^ rotrConstant<1>(key[i - 3]);
181  z>>=1;
182  }
183 
184  key[68] = c^key[64] ^ rotrConstant<3>(key[67]) ^ key[65] ^ rotrConstant<4>(key[67]) ^ rotrConstant<1>(key[65]);
185  key[69] = c ^ 1 ^ key[65] ^ rotrConstant<3>(key[68]) ^ key[66] ^ rotrConstant<4>(key[68]) ^ rotrConstant<1>(key[66]);
186  key[70] = c^key[66] ^ rotrConstant<3>(key[69]) ^ key[67] ^ rotrConstant<4>(key[69]) ^ rotrConstant<1>(key[67]);
187  key[71] = c^key[67] ^ rotrConstant<3>(key[70]) ^ key[68] ^ rotrConstant<4>(key[70]) ^ rotrConstant<1>(key[68]);
188 }
189 
190 ANONYMOUS_NAMESPACE_END
191 
192 ///////////////////////////////////////////////////////////
193 
194 NAMESPACE_BEGIN(CryptoPP)
195 
196 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
197 extern size_t SIMON64_Enc_AdvancedProcessBlocks_NEON(const word32* subKeys, size_t rounds,
198  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
199 
200 extern size_t SIMON64_Dec_AdvancedProcessBlocks_NEON(const word32* subKeys, size_t rounds,
201  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
202 #endif
203 
204 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
205 extern size_t SIMON128_Enc_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds,
206  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
207 
208 extern size_t SIMON128_Dec_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds,
209  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
210 #endif
211 
212 #if defined(CRYPTOPP_SSE41_AVAILABLE)
213 extern size_t SIMON64_Enc_AdvancedProcessBlocks_SSE41(const word32* subKeys, size_t rounds,
214  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
215 
216 extern size_t SIMON64_Dec_AdvancedProcessBlocks_SSE41(const word32* subKeys, size_t rounds,
217  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
218 #endif
219 
220 #if defined(CRYPTOPP_SSSE3_AVAILABLE)
221 extern size_t SIMON128_Enc_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds,
222  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
223 
224 extern size_t SIMON128_Dec_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds,
225  const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags);
226 #endif
227 
228 void SIMON64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params)
229 {
230  CRYPTOPP_ASSERT(keyLength == 12 || keyLength == 16);
231  CRYPTOPP_UNUSED(params);
232 
233  // Building the key schedule table requires {3,4} words workspace.
234  // Encrypting and decrypting requires 4 words workspace.
235  m_kwords = keyLength/sizeof(word32);
236  m_wspace.New(4U);
237 
238  // Do the endian gyrations from the paper and align pointers
239  typedef GetBlock<word32, LittleEndian, false> KeyBlock;
240  KeyBlock kblk(userKey);
241 
242  switch (m_kwords)
243  {
244  case 3:
245  m_rkeys.New((m_rounds = 42));
246  kblk(m_wspace[2])(m_wspace[1])(m_wspace[0]);
247  SIMON64_ExpandKey_3W(m_rkeys, m_wspace);
248  break;
249  case 4:
250  m_rkeys.New((m_rounds = 44));
251  kblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]);
252  SIMON64_ExpandKey_4W(m_rkeys, m_wspace);
253  break;
254  default:
255  CRYPTOPP_ASSERT(0);;
256  }
257 }
258 
259 void SIMON64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
260 {
261  // Do the endian gyrations from the paper and align pointers
263  InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]);
264 
265  switch (m_rounds)
266  {
267  case 42:
268  SIMON_Encrypt<word32, 42>(m_wspace+2, m_wspace+0, m_rkeys);
269  break;
270  case 44:
271  SIMON_Encrypt<word32, 44>(m_wspace+2, m_wspace+0, m_rkeys);
272  break;
273  default:
274  CRYPTOPP_ASSERT(0);;
275  }
276 
277  // Do the endian gyrations from the paper and align pointers
278  typedef PutBlock<word32, LittleEndian, false> OutBlock;
279  OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]);
280 }
281 
282 void SIMON64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
283 {
284  // Do the endian gyrations from the paper and align pointers
286  InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]);
287 
288  switch (m_rounds)
289  {
290  case 42:
291  SIMON_Decrypt<word32, 42>(m_wspace+2, m_wspace+0, m_rkeys);
292  break;
293  case 44:
294  SIMON_Decrypt<word32, 44>(m_wspace+2, m_wspace+0, m_rkeys);
295  break;
296  default:
297  CRYPTOPP_ASSERT(0);;
298  }
299 
300  // Do the endian gyrations from the paper and align pointers
301  typedef PutBlock<word32, LittleEndian, false> OutBlock;
302  OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]);
303 }
304 
305 ///////////////////////////////////////////////////////////
306 
307 void SIMON128::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs &params)
308 {
309  CRYPTOPP_ASSERT(keyLength == 16 || keyLength == 24 || keyLength == 32);
310  CRYPTOPP_UNUSED(params);
311 
312  // Building the key schedule table requires {2,3,4} words workspace.
313  // Encrypting and decrypting requires 4 words workspace.
314  m_kwords = keyLength/sizeof(word64);
315  m_wspace.New(4U);
316 
317  // Do the endian gyrations from the paper and align pointers
318  typedef GetBlock<word64, LittleEndian, false> KeyBlock;
319  KeyBlock kblk(userKey);
320 
321  switch (m_kwords)
322  {
323  case 2:
324  m_rkeys.New((m_rounds = 68));
325  kblk(m_wspace[1])(m_wspace[0]);
326  SIMON128_ExpandKey_2W(m_rkeys, m_wspace);
327  break;
328  case 3:
329  m_rkeys.New((m_rounds = 69));
330  kblk(m_wspace[2])(m_wspace[1])(m_wspace[0]);
331  SIMON128_ExpandKey_3W(m_rkeys, m_wspace);
332  break;
333  case 4:
334  m_rkeys.New((m_rounds = 72));
335  kblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]);
336  SIMON128_ExpandKey_4W(m_rkeys, m_wspace);
337  break;
338  default:
339  CRYPTOPP_ASSERT(0);;
340  }
341 }
342 
343 void SIMON128::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
344 {
345  // Do the endian gyrations from the paper and align pointers
347  InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]);
348 
349  switch (m_rounds)
350  {
351  case 68:
352  SIMON_Encrypt<word64, 68>(m_wspace+2, m_wspace+0, m_rkeys);
353  break;
354  case 69:
355  SIMON_Encrypt<word64, 69>(m_wspace+2, m_wspace+0, m_rkeys);
356  break;
357  case 72:
358  SIMON_Encrypt<word64, 72>(m_wspace+2, m_wspace+0, m_rkeys);
359  break;
360  default:
361  CRYPTOPP_ASSERT(0);;
362  }
363 
364  // Do the endian gyrations from the paper and align pointers
365  typedef PutBlock<word64, LittleEndian, false> OutBlock;
366  OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]);
367 }
368 
369 void SIMON128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
370 {
371  // Do the endian gyrations from the paper and align pointers
373  InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]);
374 
375  switch (m_rounds)
376  {
377  case 68:
378  SIMON_Decrypt<word64, 68>(m_wspace+2, m_wspace+0, m_rkeys);
379  break;
380  case 69:
381  SIMON_Decrypt<word64, 69>(m_wspace+2, m_wspace+0, m_rkeys);
382  break;
383  case 72:
384  SIMON_Decrypt<word64, 72>(m_wspace+2, m_wspace+0, m_rkeys);
385  break;
386  default:
387  CRYPTOPP_ASSERT(0);;
388  }
389 
390  // Do the endian gyrations from the paper and align pointers
391  typedef PutBlock<word64, LittleEndian, false> OutBlock;
392  OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]);
393 }
394 
395 #if defined(CRYPTOPP_SIMON64_ADVANCED_PROCESS_BLOCKS)
396 size_t SIMON64::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
397  byte *outBlocks, size_t length, word32 flags) const
398 {
399 #if defined(CRYPTOPP_SSE41_AVAILABLE)
400  if (HasSSE41())
401  return SIMON64_Enc_AdvancedProcessBlocks_SSE41(m_rkeys, (size_t)m_rounds,
402  inBlocks, xorBlocks, outBlocks, length, flags);
403 #endif
404 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
405  if (HasNEON())
406  return SIMON64_Enc_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds,
407  inBlocks, xorBlocks, outBlocks, length, flags);
408 #endif
409  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
410 }
411 
412 size_t SIMON64::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
413  byte *outBlocks, size_t length, word32 flags) const
414 {
415 #if defined(CRYPTOPP_SSE41_AVAILABLE)
416  if (HasSSE41())
417  return SIMON64_Dec_AdvancedProcessBlocks_SSE41(m_rkeys, (size_t)m_rounds,
418  inBlocks, xorBlocks, outBlocks, length, flags);
419 #endif
420 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
421  if (HasNEON())
422  return SIMON64_Dec_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds,
423  inBlocks, xorBlocks, outBlocks, length, flags);
424 #endif
425  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
426 }
427 #endif // CRYPTOPP_SIMON64_ADVANCED_PROCESS_BLOCKS
428 
429 #if defined(CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS)
430 size_t SIMON128::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
431  byte *outBlocks, size_t length, word32 flags) const
432 {
433 #if defined(CRYPTOPP_SSSE3_AVAILABLE)
434  if (HasSSSE3())
435  return SIMON128_Enc_AdvancedProcessBlocks_SSSE3(m_rkeys, (size_t)m_rounds,
436  inBlocks, xorBlocks, outBlocks, length, flags);
437 #endif
438 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
439  if (HasNEON())
440  return SIMON128_Enc_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds,
441  inBlocks, xorBlocks, outBlocks, length, flags);
442 #endif
443  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
444 }
445 
446 size_t SIMON128::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks,
447  byte *outBlocks, size_t length, word32 flags) const
448 {
449 #if defined(CRYPTOPP_SSSE3_AVAILABLE)
450  if (HasSSSE3())
451  return SIMON128_Dec_AdvancedProcessBlocks_SSSE3(m_rkeys, (size_t)m_rounds,
452  inBlocks, xorBlocks, outBlocks, length, flags);
453 #endif
454 #if (CRYPTOPP_ARM_NEON_AVAILABLE)
455  if (HasNEON())
456  return SIMON128_Dec_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds,
457  inBlocks, xorBlocks, outBlocks, length, flags);
458 #endif
459  return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags);
460 }
461 #endif // CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS
462 
463 NAMESPACE_END
Utility functions for the Crypto++ library.
bool HasSSSE3()
Determines SSSE3 availability.
Definition: cpu.h:129
Library configuration file.
void New(size_type newSize)
Change size without preserving contents.
Definition: secblock.h:729
T rotlConstant(T x)
Performs a left rotate.
Definition: misc.h:1365
virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
Encrypt and xor multiple blocks using additional flags.
Definition: cryptlib.cpp:147
Precompiled header file.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
Functions for CPU features and intrinsics.
T rotrConstant(T x)
Performs a right rotate.
Definition: misc.h:1391
Access a block of memory.
Definition: misc.h:2324
Classes for the Simon block cipher.
bool HasSSE41()
Determines SSE4.1 availability.
Definition: cpu.h:140
Access a block of memory.
Definition: misc.h:2365
Crypto++ library namespace.
bool HasNEON()
Determine if an ARM processor has Advanced SIMD available.
Definition: cpu.h:329
Interface for retrieving values given their names.
Definition: cryptlib.h:290