4 #include "rapidjson/document.h"
5 #include "rapidjson/filereadstream.h"
6 #include "rapidjson/stringbuffer.h"
7 #include "rapidjson/writer.h"
19 #include <immintrin.h>
22 #elif defined(__ARM_NEON)
50 static int size(
u64 dw,
int level);
60 memset(dw64, 0,
sizeof(dw64));
73 memset(dw64, 0xFF,
sizeof(
u64));
76 memset(dw64, 0xFF, 2 *
sizeof(
u64));
79 memset(dw64, 0xFF,
sizeof(dw64));
86 for (
int i = 0; i < 4; i++)
98 for (
int i = 0; i < 4; i++)
105 std::cerr <<
"Called smallset_t::least_bit() on empty set\n" << std::endl;
115 retval.dw64[0] = temp.dw64[2];
116 retval.dw64[1] = temp.dw64[3];
117 retval.dw64[2] = temp.dw64[0];
118 retval.dw64[3] = temp.dw64[1];
123 retval.dw64[0] = temp.dw64[1];
124 retval.dw64[1] = temp.dw64[0];
125 retval.dw64[2] = temp.dw64[3];
126 retval.dw64[3] = temp.dw64[2];
130 for (
int i = 0; i < 4; i++)
132 retval.dw64[i] = ((retval.dw64[i] & 0xFFFFFFFF00000000ULL) >> 32) | ((retval.dw64[i] & 0x00000000FFFFFFFFULL) << 32);
137 for (
int i = 0; i < 4; i++)
139 retval.dw64[i] = ((retval.dw64[i] & 0xFFFF0000FFFF0000ULL) >> 16) | ((retval.dw64[i] & 0x0000FFFF0000FFFFULL) << 16);
144 for (
int i = 0; i < 4; i++)
146 retval.dw64[i] = ((retval.dw64[i] & 0xFF00FF00FF00FF00ULL) >> 8) | ((retval.dw64[i] & 0x00FF00FF00FF00FFULL) << 8);
151 for (
int i = 0; i < 4; i++)
153 retval.dw64[i] = ((retval.dw64[i] & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | ((retval.dw64[i] & 0x0F0F0F0F0F0F0F0FULL) << 4);
158 for (
int i = 0; i < 4; i++)
160 retval.dw64[i] = ((retval.dw64[i] & 0xCCCCCCCCCCCCCCCCULL) >> 2) | ((retval.dw64[i] & 0x3333333333333333ULL) << 2);
165 for (
int i = 0; i < 4; i++)
167 retval.dw64[i] = ((retval.dw64[i] & 0xAAAAAAAAAAAAAAAAULL) >> 1) | ((retval.dw64[i] & 0x5555555555555555ULL) << 1);
175 for (
int i = 0; i < 4; i++)
177 arr[i] = dw64[swap ? 3 - i : i];
183 dw64[bit / 64] |= (
_ONE_ << (bit % 64));
188 return (dw64[bit / 64] & (
_ONE_ << (bit % 64))) != 0;
194 for (
int i = 0; i < 4; i++)
195 retval +=
size(dw64[i], 0);
201 static const u64 segmask[] = {0xFFFFFFFF, 0xFFFF, 0xFF, 0xF};
202 static const int segshft[] = {32, 16, 8, 4};
203 static const int szlookup[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
206 return szlookup[dw & 0xF];
209 retval +=
size(dw & segmask[level], level + 1);
210 dw >>= segshft[level];
211 retval +=
size(dw & segmask[level], level + 1);
218 static const u64 segmask[] = {0xFFFFFFFF, 0xFFFF, 0xFF, 0xF};
219 static const int lblookup[16] = {-61, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
224 for (
int iseg = 0; iseg < 4; iseg++)
226 if (!(dw & segmask[iseg]))
234 return retval + lblookup[dw & 0xF];
239 for (
int i = 3; i >= 0; i--)
240 printf(
"%016lx", dw64[i]);
243 for (
unsigned int i = 0; i < 256; i++)
245 if (dw64[i / 64] & (
_ONE_ << (i % 64)))
253 for (
int i = 0; i < 4; i++)
254 retval.dw64[i] |= dw64[i];
261 for (
int i = 0; i < 4; i++)
262 retval.dw64[i] &= dw64[i];
269 for (
int i = 0; i < 4; i++)
270 retval.dw64[i] ^= dw64[i];
296 constexpr
u64 LINEAR_REPRESENTATIVE_BUDGET = 250000;
298 std::vector<u8> compute_linear_representative_bounded(
const std::vector<u8>& sbox,
u64& budget);
309 if (
const auto res = db.load(file_path); res.is_ok())
315 return ERR(res.get_error());
322 u32 bit_size = std::log2(sbox.size());
326 return ERR(
"S-box '" +
name +
"' has bit-size greater 8, but only S-boxes of up to 8 bits are supported");
329 for (
size_t alpha = 0; alpha < sbox.size(); alpha++)
331 std::vector<u8> sbox_alpha;
332 for (
u32 i = 0; i < sbox.size(); i++)
334 sbox_alpha.push_back(sbox.at(i) ^ alpha);
336 u64 budget = LINEAR_REPRESENTATIVE_BUDGET;
337 auto lin_rep = compute_linear_representative_bounded(sbox_alpha, budget);
342 return ERR(
"cannot add S-box '" +
name +
"' to the database: the canonical form search was abandoned, the S-box is too close to linear");
344 m_data[bit_size][lin_rep].push_back(std::make_pair(
name, alpha));
351 for (
const auto& [
name, sbox] : sboxes)
353 if (
const auto res =
add(
name, sbox); res.is_error())
355 return ERR(res.get_error());
363 FILE* fp = fopen(file_path.string().c_str(),
"r");
366 return ERR(
"could not parse S-box database file '" + file_path.string() +
"' : unable to open file");
370 rapidjson::FileReadStream is(fp, buffer,
sizeof(buffer));
371 rapidjson::Document document;
372 document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(is);
375 if (document.HasParseError())
377 return ERR(
"could not parse S-box database file '" + file_path.string() +
"': failed parsing JSON format");
385 for (
auto size_it = document.MemberBegin(); size_it != document.MemberEnd(); ++size_it)
387 u32 bit_size = std::stoul(std::string(size_it->name.GetString()));
388 const rapidjson::Value& cipher_val = size_it->value;
390 for (
auto cipher_it = cipher_val.MemberBegin(); cipher_it != cipher_val.MemberEnd(); ++cipher_it)
392 std::string cipher_name = cipher_it->name.GetString();
393 const rapidjson::Value& const_val = cipher_it->value;
395 for (
auto const_it = const_val.MemberBegin(); const_it != const_val.MemberEnd(); ++const_it)
397 u8 const_alpha = (
u8)std::stoul(std::string(const_it->name.GetString()));
398 const rapidjson::Value& lin_rep_val = const_it->value;
400 std::vector<u8> lin_rep;
401 for (
u32 i = 0; i < lin_rep_val.Size(); i++)
403 lin_rep.push_back((
u8)(lin_rep_val[i].GetUint()));
406 m_data[bit_size][lin_rep].push_back(std::make_pair(cipher_name, const_alpha));
416 FILE* fp = fopen(file_path.string().c_str(),
"w");
419 return ERR(
"could not write S-box database file '" + file_path.string() +
"' : unable to open file");
422 rapidjson::Document document;
423 document.SetObject();
425 rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
427 for (
const auto& [bit_size, lin_rep_map] : m_data)
429 std::map<std::string, std::map<u8, std::vector<u8>>> pretty_data;
430 for (
const auto& [lin_rep, cipher_vec] : lin_rep_map)
432 for (
const auto& [
name, alpha] : cipher_vec)
434 pretty_data[
name][alpha] = lin_rep;
438 rapidjson::Value cipher_json(rapidjson::kObjectType);
439 for (
const auto& [cipher_name, lin_rep_map] : pretty_data)
441 rapidjson::Value alpha_json(rapidjson::kObjectType);
442 for (
const auto& [const_alph, lin_rep] : lin_rep_map)
444 rapidjson::Value lin_rep_json(rapidjson::kArrayType);
445 for (
const auto val : lin_rep)
447 lin_rep_json.PushBack(val, allocator);
449 alpha_json.AddMember(rapidjson::Value(std::to_string(const_alph).c_str(), allocator).Move(), lin_rep_json, allocator);
451 cipher_json.AddMember(rapidjson::Value(cipher_name.c_str(), allocator).Move(), alpha_json, allocator);
453 document.AddMember(rapidjson::Value(std::to_string(bit_size).c_str(), allocator).Move(), cipher_json, allocator);
456 rapidjson::StringBuffer buffer;
457 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
459 document.Accept(writer);
461 std::ofstream file(file_path);
464 return ERR(
"could not store the S-box database: failed to open file '" + file_path.string() +
"'");
466 file << buffer.GetString();
474 u32 bit_size = std::log2(sbox.size());
478 return ERR(
"S-box has bit-size greater 8, but only S-boxes of up to 8 bits are supported");
481 const auto size_it = m_data.find(bit_size);
482 if (size_it == m_data.end())
484 return ERR(
"no S-box of matching bit-size of " + std::to_string(bit_size) +
" bits contained in database");
489 for (
u32 beta = 0; beta < sbox.size(); beta++)
491 std::vector<u8> sbox_beta;
492 for (
u32 i = 0; i < sbox.size(); i++)
494 sbox_beta.push_back(sbox.at(i) ^ beta);
497 u64 budget = LINEAR_REPRESENTATIVE_BUDGET;
498 auto lin_rep = compute_linear_representative_bounded(sbox_beta, budget);
503 log_info(
"hawkeye",
"giving up the S-box lookup, as the table is too close to linear to be a real S-box.");
507 const auto& matching_size_data = std::get<1>(*size_it);
508 const auto rep_it = matching_size_data.find(lin_rep);
509 if (rep_it != matching_size_data.end())
511 return OK(rep_it->second.front().first);
515 return ERR(
"no match found within database");
520 for (
const auto& [bit_size, lin_rep_map] : m_data)
522 std::cout << std::endl;
523 std::cout <<
"### WIDTH: " << bit_size << std::endl;
524 std::cout <<
"#######################" << std::endl;
526 std::map<std::string, std::map<u8, std::vector<u8>>> pretty_data;
527 for (
const auto& [lin_rep, cipher_vec] : lin_rep_map)
529 for (
const auto& [
name, alpha] : cipher_vec)
531 pretty_data[
name][alpha] = lin_rep;
535 for (
const auto& [cipher_name, lin_rep_map] : pretty_data)
537 std::cout <<
"* " << cipher_name << std::endl;
539 for (
const auto& [const_alph, lin_rep] : lin_rep_map)
541 std::cout <<
" - " << (
u32)const_alph <<
": [" << (
u32)(lin_rep.at(0));
542 for (
u32 i = 1; i < lin_rep.size(); i++)
544 std::cout <<
", " << (
u32)(lin_rep.at(i));
546 std::cout <<
"]" << std::endl;
551 std::cout << std::endl;
561 elements[0] = _mm256_extract_epi64(a, 3);
562 elements[1] = _mm256_extract_epi64(a, 2);
563 elements[2] = _mm256_extract_epi64(a, 1);
564 elements[3] = _mm256_extract_epi64(a, 0);
565 #elif defined(__ARM_NEON)
566 elements[0] = a.val[1][1];
567 elements[1] = a.val[1][0];
568 elements[2] = a.val[0][1];
569 elements[3] = a.val[0][0];
573 std::cout <<
name <<
": 0b";
574 for (
u32 i = 0; i < 4; i++)
576 for (
int j = 63; j >= 0; j--)
578 u32 bit = (elements[i] >> j) & 1;
583 std::cout << std::endl;
590 chunks[0] = _mm256_extract_epi64(a, 0);
591 chunks[1] = _mm256_extract_epi64(a, 1);
592 chunks[2] = _mm256_extract_epi64(a, 2);
593 chunks[3] = _mm256_extract_epi64(a, 3);
594 #elif defined(__ARM_NEON)
595 chunks[0] = a.val[0][0];
596 chunks[1] = a.val[0][1];
597 chunks[2] = a.val[1][0];
598 chunks[3] = a.val[1][1];
602 for (
u32 i = 0; i < 4; i++)
604 u64 current_chunk = chunks[i];
605 if (current_chunk != 0)
607 u8 idx = __builtin_ctzll(current_chunk) + i * 64;
613 std::cout <<
"CALLED LEAST ELEMENT ON EMPTY SET!" << std::endl;
620 return _mm256_and_si256(a, b);
621 #elif defined(__ARM_NEON)
622 return {vandq_u64(a.val[0], b.val[0]), vandq_u64(a.val[1], b.val[1])};
631 return _mm256_or_si256(a, b);
632 #elif defined(__ARM_NEON)
633 return {vorrq_u64(a.val[0], b.val[0]), vorrq_u64(a.val[1], b.val[1])};
643 u64 chunk = _mm256_extract_epi64(a, 0);
644 count += __builtin_popcountll(chunk);
645 chunk = _mm256_extract_epi64(a, 1);
646 count += __builtin_popcountll(chunk);
647 chunk = _mm256_extract_epi64(a, 2);
648 count += __builtin_popcountll(chunk);
649 chunk = _mm256_extract_epi64(a, 3);
650 count += __builtin_popcountll(chunk);
651 #elif defined(__ARM_NEON)
652 count += __builtin_popcountll(a.val[0][0]);
653 count += __builtin_popcountll(a.val[0][1]);
654 count += __builtin_popcountll(a.val[1][0]);
655 count += __builtin_popcountll(a.val[1][1]);
662 inline bool smallset_is_empty(
const smallset_t& a)
665 return _mm256_testz_si256(a, a);
666 #elif defined(__ARM_NEON)
667 auto tmp = vandq_u64(vceqzq_u64(a.val[0]), vceqzq_u64(a.val[1]));
668 return (tmp[0] & tmp[1]) & 1;
681 __m256i _mask = _mm256_set_epi64x(mask[3], mask[2], mask[1], mask[0]);
682 return _mm256_or_si256(a, _mask);
683 #elif defined(__ARM_NEON)
685 mask[
index & 1] = (
u64)1 << (elm % 64);
686 auto _mask = vld1q_u64(mask);
689 return {vorrq_u64(a.val[0], _mask), a.val[1]};
693 return {a.val[0], vorrq_u64(a.val[1], _mask)};
704 #if !defined(__AVX2__) && !defined(__ARM_NEON)
710 if ((shift >> 7) & 0x1)
713 a = _mm256_permute2x128_si256(a, a, 1);
714 #elif defined(__ARM_NEON)
719 if ((shift >> 6) & 0x1)
722 a = _mm256_permute4x64_epi64(a, _MM_SHUFFLE(2, 3, 0, 1));
723 #elif defined(__ARM_NEON)
724 a.val[0] = vextq_u64(a.val[0], a.val[0], 1);
725 a.val[1] = vextq_u64(a.val[1], a.val[1], 1);
728 if ((shift >> 5) & 0x1)
731 a = _mm256_shuffle_epi32(a, _MM_SHUFFLE(2, 3, 0, 1));
732 #elif defined(__ARM_NEON)
733 a.val[0] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[0]);
734 a.val[1] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[1]);
738 if ((shift >> 4) & 0x1)
741 a = _mm256_shufflelo_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
742 a = _mm256_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
743 #elif defined(__ARM_NEON)
744 a.val[0] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[0]);
745 a.val[0] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[0]);
746 a.val[1] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[1]);
747 a.val[1] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[1]);
750 if ((shift >> 3) & 0x1)
753 const __m256i mask = _mm256_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
754 a = _mm256_shuffle_epi8(a, mask);
755 #elif defined(__ARM_NEON)
756 a.val[0] = (uint64x2_t) vrev64q_u8 ((uint8x16_t) a.val[0]);
757 a.val[0] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[0]);
758 a.val[1] = (uint64x2_t) vrev64q_u8 ((uint8x16_t) a.val[1]);
759 a.val[1] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[1]);
762 if ((shift >> 2) & 0x1)
765 const __m256i mask_high = _mm256_set1_epi8((
char)0xF0);
766 const __m256i mask_low = _mm256_set1_epi8(0x0F);
767 const __m256i high = _mm256_and_si256(a, mask_high);
768 const __m256i low = _mm256_and_si256(a, mask_low);
769 a = _mm256_or_si256(_mm256_srli_epi16(high, 4), _mm256_slli_epi16(low, 4));
770 #elif defined(__ARM_NEON)
771 const auto mask_high = vdupq_n_u64(0xF0F0F0F0F0F0F0F0);
772 const auto mask_low = vdupq_n_u64(0x0F0F0F0F0F0F0F0F);
774 for (
u32 i = 0; i < 2; i++)
776 const auto high = vandq_u64(a.val[i], mask_high);
777 const auto low = vandq_u64(a.val[i], mask_low);
779 a.val[i] = vorrq_u64(vshrq_n_u64(high, 4), vshlq_n_u64(low, 4));
783 if ((shift >> 1) & 0x1)
786 const __m256i mask_high = _mm256_set1_epi8((
char)0xCC);
787 const __m256i mask_low = _mm256_set1_epi8(0x33);
788 const __m256i high = _mm256_and_si256(a, mask_high);
789 const __m256i low = _mm256_and_si256(a, mask_low);
790 a = _mm256_or_si256(_mm256_srli_epi16(high, 2), _mm256_slli_epi16(low, 2));
791 #elif defined(__ARM_NEON)
792 const auto mask_high = vdupq_n_u64(0xCCCCCCCCCCCCCCCC);
793 const auto mask_low = vdupq_n_u64(0x3333333333333333);
795 for (
u32 i = 0; i < 2; i++)
797 const auto high = vandq_u64(a.val[i], mask_high);
798 const auto low = vandq_u64(a.val[i], mask_low);
800 a.val[i] = vorrq_u64(vshrq_n_u64(high, 2), vshlq_n_u64(low, 2));
807 const __m256i mask_high = _mm256_set1_epi8((
char)0xAA);
808 const __m256i mask_low = _mm256_set1_epi8(0x55);
809 const __m256i high = _mm256_and_si256(a, mask_high);
810 const __m256i low = _mm256_and_si256(a, mask_low);
811 a = _mm256_or_si256(_mm256_srli_epi16(high, 1), _mm256_slli_epi16(low, 1));
812 #elif defined(__ARM_NEON)
813 const auto mask_high = vdupq_n_u64(0xAAAAAAAAAAAAAAAA);
814 const auto mask_low = vdupq_n_u64(0x5555555555555555);
816 for (
u32 i = 0; i < 2; i++)
818 const auto high = vandq_u64(a.val[i], mask_high);
819 const auto low = vandq_u64(a.val[i], mask_low);
821 a.val[i] = vorrq_u64(vshrq_n_u64(high, 1), vshlq_n_u64(low, 1));
831 return smallset_union(a, b);
834 std::vector<u8> smallset_get_elements(
const smallset_t& a)
839 chunks[0] = _mm256_extract_epi64(a, 0);
840 chunks[1] = _mm256_extract_epi64(a, 1);
841 chunks[2] = _mm256_extract_epi64(a, 2);
842 chunks[3] = _mm256_extract_epi64(a, 3);
843 #elif defined(__ARM_NEON)
844 chunks[0] = a.val[0][0];
845 chunks[1] = a.val[0][1];
846 chunks[2] = a.val[1][0];
847 chunks[3] = a.val[1][1];
851 for (
u32 i = 0; i < 4; i++)
853 u64 current_chunk = chunks[i];
854 while (current_chunk != 0)
856 u8 idx = __builtin_ctzll(current_chunk) + i * 64;
858 current_chunk &= (current_chunk - 1);
867 return _mm256_setzero_si256();
868 #elif defined(__ARM_NEON)
869 return {vdupq_n_u64(0), vdupq_n_u64(0)};
877 #if !defined(__AVX2__) && !defined(__ARM_NEON)
884 return _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
885 #elif defined(__ARM_NEON)
886 return {vdupq_n_u64(0xFFFFFFFFFFFFFFFF), vdupq_n_u64(0xFFFFFFFFFFFFFFFF)};
892 return _mm256_set_epi64x(0, 0, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
893 #elif defined(__ARM_NEON)
894 return {vdupq_n_u64(0xFFFFFFFFFFFFFFFF), vdupq_n_u64(0)};
900 return _mm256_set_epi64x(0, 0, 0, 0xFFFFFFFFFFFFFFFF);
901 #elif defined(__ARM_NEON)
902 auto tmp = vdupq_n_u64(0);
903 return {vsetq_lane_u64(0xFFFFFFFFFFFFFFFF, tmp, 0), vdupq_n_u64(0)};
909 return _mm256_set_epi64x(0, 0, 0, 0xFFFFFFFF);
910 #elif defined(__ARM_NEON)
911 auto tmp = vdupq_n_u64(0);
912 return {(uint64x2_t)vsetq_lane_u32(0xFFFFFFFF, (uint32x4_t)tmp, 0), vdupq_n_u64(0)};
918 return _mm256_set_epi64x(0, 0, 0, 0xFFFF);
919 #elif defined(__ARM_NEON)
920 auto tmp = vdupq_n_u64(0);
921 return {(uint64x2_t)vsetq_lane_u16(0xFFFF, (uint16x8_t)tmp, 0), vdupq_n_u64(0)};
927 return _mm256_set_epi64x(0, 0, 0, 0xFF);
928 #elif defined(__ARM_NEON)
929 auto tmp = vdupq_n_u64(0);
930 return {(uint64x2_t)vsetq_lane_u8(0xFF, (uint8x16_t)tmp, 0), vdupq_n_u64(0)};
936 return _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
937 #elif defined(__ARM_NEON)
938 return {vdupq_n_u64(0xFFFFFFFFFFFFFFFF), vdupq_n_u64(0xFFFFFFFFFFFFFFFF)};
947 return _mm256_xor_si256(a, b);
948 #elif defined(__ARM_NEON)
949 return {veorq_u64(a.val[0], b.val[0]), veorq_u64(a.val[1], b.val[1])};
957 const smallset_t b_not = smallset_invert(b, len);
958 return smallset_intersect(a, b_not);
961 bool smallset_elm_is_in_set(
const u8 e,
const smallset_t& a)
963 #if !defined(__AVX2__) && !defined(__ARM_NEON)
967 b = smallset_add_element(b, e);
968 b = smallset_intersect(a, b);
969 return !smallset_is_empty(b);
991 bool is_greater(
const std::vector<u8>&
R_S,
const std::vector<u8>& R_S_best,
const u32 len)
993 if ((R_S_best[0] == 0) && (R_S_best[1] == 0))
996 for (
u32 x = 0;
x < len;
x++)
1000 if (
R_S[
x] > R_S_best[
x])
1002 if (
R_S[
x] < R_S_best[
x])
1009 bool update_linear(std::vector<u8>&
A,
u8 new_x,
const u32 len)
1011 u8 new_y =
A[new_x];
1012 for (
u32 i = 1; i < len; i++)
1017 else if (
A[new_x ^ i] == 0)
1018 A[new_x ^ i] = e ^ new_y;
1019 else if (
A[new_x ^ i] != (e ^ new_y))
1027 bool subroutine(
const std::vector<u8>& S,
const std::vector<u8>& S_inv,
const state_t& state, std::vector<u8>& R_S_best,
const u32 len,
u64& budget)
1040 std::vector<u8>
A(
state.A);
1041 std::vector<u8>
B(
state.B);
1053 while (!smallset_is_empty(
N_A))
1055 u8 x = smallset_least_element(
N_A);
1056 u8 y = smallset_least_element(
U_B);
1059 if (!update_linear(
B,
y, len))
1062 D_B = smallset_union(
D_B, D_B_new);
1063 U_B = smallset_setminus(
U_B, D_B_new, len);
1066 for (
u8 x : smallset_get_elements(
N_A))
1068 SoA_N_A = smallset_add_element(SoA_N_A, S[
A[
x]]);
1070 smallset_t B_D_B_new = smallset_init_empty();
1071 for (
u8 d : smallset_get_elements(D_B_new))
1073 B_D_B_new = smallset_add_element(B_D_B_new,
B[d]);
1074 if (smallset_elm_is_in_set(
B[d], SoA_N_A))
1076 C_B = smallset_add_element(
C_B, d);
1080 N_B = smallset_add_element(
N_B, d);
1084 for (
u8 x : smallset_get_elements(
N_A))
1086 if (smallset_elm_is_in_set(S[
A[
x]], B_D_B_new))
1088 C_A_new = smallset_add_element(C_A_new,
x);
1091 C_A = smallset_union(
C_A, C_A_new);
1092 N_A = smallset_setminus(
N_A, C_A_new, len);
1093 for (
u8 x : smallset_get_elements(C_A_new))
1096 for (
u32 i = 0; i < len; i++)
1098 if (
B[i] == S[
A[
x]])
1106 if (is_greater(
R_S, R_S_best, len))
1111 while (smallset_is_empty(
N_A) && !smallset_is_empty(
N_B))
1113 u8 x = smallset_least_element(
U_A);
1114 u8 y = smallset_least_element(
N_B);
1116 if (!update_linear(
A,
x, len))
1121 D_A = smallset_union(
D_A, D_A_new);
1122 U_A = smallset_setminus(
U_A, D_A_new, len);
1123 smallset_t SinvoB_N_B = smallset_init_empty();
1124 for (
u8 y : smallset_get_elements(
N_B))
1126 SinvoB_N_B = smallset_add_element(SinvoB_N_B, S_inv[
B[
y]]);
1128 smallset_t A_D_A_new = smallset_init_empty();
1129 for (
u8 d : smallset_get_elements(D_A_new))
1131 A_D_A_new = smallset_add_element(A_D_A_new,
A[d]);
1132 if (smallset_elm_is_in_set(
A[d], SinvoB_N_B))
1134 C_A = smallset_add_element(
C_A, d);
1138 N_A = smallset_add_element(
N_A, d);
1142 for (
u8 y : smallset_get_elements(
N_B))
1144 if (smallset_elm_is_in_set(S_inv[
B[
y]], A_D_A_new))
1146 C_B_new = smallset_add_element(C_B_new,
y);
1149 C_B = smallset_union(
C_B, C_B_new);
1150 N_B = smallset_setminus(
N_B, C_B_new, len);
1151 for (
u8 y : smallset_get_elements(C_B_new))
1154 for (
u32 i = 0; i < len; i++)
1156 if (
A[i] == S_inv[
B[
y]])
1164 if (is_greater(
R_S, R_S_best, len))
1170 if (smallset_is_empty(
U_A) && smallset_is_empty(
U_B))
1172 for (
u32 i = 0; i < len; i++)
1175 R_S_best[i] =
R_S[i];
1181 u8 x = smallset_least_element(
U_A);
1183 U_A = smallset_setminus(
U_A, D_A_new, len);
1184 D_A = smallset_union(
D_A, D_A_new);
1185 N_A = smallset_union(
N_A, D_A_new);
1189 for (
u32 i = 0; i < len; i++)
1191 A_set = smallset_add_element(A_set,
A[i]);
1193 Y = smallset_setminus(Y, A_set, len);
1194 for (
u8 y : smallset_get_elements(Y))
1196 std::vector<u8> A_next_guess(len);
1198 for (
u32 i = 0; i < len; i++)
1200 A_next_guess[i] =
A[i];
1202 A_next_guess[
x] =
y;
1203 if (!update_linear(A_next_guess,
x, len))
1206 state_next.A = A_next_guess;
1208 state_next.R_S =
R_S;
1209 state_next.D_A =
D_A;
1210 state_next.D_B =
D_B;
1211 state_next.C_A =
C_A;
1212 state_next.C_B =
C_B;
1213 state_next.N_A =
N_A;
1214 state_next.N_B =
N_B;
1215 state_next.U_A =
U_A;
1216 state_next.U_B =
U_B;
1218 if (subroutine(S, S_inv, state_next, R_S_best, len, budget))
1227 std::vector<u8> compute_linear_representative_bounded(
const std::vector<u8>& sbox,
u64& budget)
1232 std::vector<u8> R_S_best(len, 0);
1235 std::vector<u8> S_inv(len, 0);
1236 for (
u32 x = 0;
x < len;
x++)
1244 state.A = std::vector<u8>(len, 0);
1245 state.B = std::vector<u8>(len, 0);
1246 state.R_S = std::vector<u8>(len, 0);
1248 state.D_A = smallset_add_element(smallset_init_empty(), 0);
1249 state.D_B = smallset_add_element(smallset_init_empty(), 0);
1251 state.C_A = smallset_init_empty();
1252 state.C_B = smallset_init_empty();
1254 state.N_A = smallset_add_element(smallset_init_empty(), 0);
1255 state.N_B = smallset_add_element(smallset_init_empty(), 0);
1257 state.U_A = smallset_setminus(smallset_init_full(len),
state.D_A, len);
1258 state.U_B = smallset_setminus(smallset_init_full(len),
state.D_A, len);
1263 state.C_A = smallset_add_element(smallset_init_empty(), 0);
1264 state.C_B = smallset_add_element(smallset_init_empty(), 0);
1266 state.N_A = smallset_init_empty();
1267 state.N_B = smallset_init_empty();
1271 subroutine(sbox, S_inv, state, R_S_best, len, budget);
1279 u64 budget = LINEAR_REPRESENTATIVE_BUDGET;
1280 auto res = compute_linear_representative_bounded(sbox, budget);
1283 log_info(
"hawkeye",
"gave up computing the canonical form of a table of {} entries, as it is too close to linear to be a real S-box.", sbox.size());
Result< std::monostate > add(const std::string &name, const std::vector< u8 > &sbox)
Add an S-box to the database.
SBoxDatabase()=default
Construct an empty S-box database.
Result< std::string > lookup(const std::vector< u8 > &sbox) const
Attempt to look up an S-box in the database.
Result< std::monostate > load(const std::filesystem::path &file_path, bool overwrite=false)
Load S-boxes from a file and add them to the existing database.
static Result< SBoxDatabase > from_file(const std::filesystem::path &file_path)
Construct an S-box database from file.
void print() const
Print the database.
Result< std::monostate > store(const std::filesystem::path &file_path) const
Store the S-box database to a database file.
static std::vector< u8 > compute_linear_representative(const std::vector< u8 > &sbox)
Compute the linear representative of the given S-box.
smallset_t operator^(const smallset_t &other) const
void to_array(u64 *arr, bool swap=false) const
bool is_set(u8 bit) const
smallset_t operator|(const smallset_t &other) const
smallset_t shuffle(u8 shift) const
smallset_t operator&(const smallset_t &other) const
#define log_info(channel,...)
This file contains the S-box database class that holds and manages known cryptographic S-boxes up to ...