3 #include "rapidjson/document.h"
4 #include "rapidjson/filereadstream.h"
5 #include "rapidjson/stringbuffer.h"
6 #include "rapidjson/writer.h"
18 #include <immintrin.h>
21 #elif defined(__ARM_NEON)
49 static int size(
u64 dw,
int level);
59 memset(dw64, 0,
sizeof(dw64));
72 memset(dw64, 0xFF,
sizeof(
u64));
75 memset(dw64, 0xFF, 2 *
sizeof(
u64));
78 memset(dw64, 0xFF,
sizeof(dw64));
85 for (
int i = 0; i < 4; i++)
97 for (
int i = 0; i < 4; i++)
104 std::cerr <<
"Called smallset_t::least_bit() on empty set\n" << std::endl;
114 retval.dw64[0] = temp.dw64[2];
115 retval.dw64[1] = temp.dw64[3];
116 retval.dw64[2] = temp.dw64[0];
117 retval.dw64[3] = temp.dw64[1];
122 retval.dw64[0] = temp.dw64[1];
123 retval.dw64[1] = temp.dw64[0];
124 retval.dw64[2] = temp.dw64[3];
125 retval.dw64[3] = temp.dw64[2];
129 for (
int i = 0; i < 4; i++)
131 retval.dw64[i] = ((retval.dw64[i] & 0xFFFFFFFF00000000ULL) >> 32) | ((retval.dw64[i] & 0x00000000FFFFFFFFULL) << 32);
136 for (
int i = 0; i < 4; i++)
138 retval.dw64[i] = ((retval.dw64[i] & 0xFFFF0000FFFF0000ULL) >> 16) | ((retval.dw64[i] & 0x0000FFFF0000FFFFULL) << 16);
143 for (
int i = 0; i < 4; i++)
145 retval.dw64[i] = ((retval.dw64[i] & 0xFF00FF00FF00FF00ULL) >> 8) | ((retval.dw64[i] & 0x00FF00FF00FF00FFULL) << 8);
150 for (
int i = 0; i < 4; i++)
152 retval.dw64[i] = ((retval.dw64[i] & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | ((retval.dw64[i] & 0x0F0F0F0F0F0F0F0FULL) << 4);
157 for (
int i = 0; i < 4; i++)
159 retval.dw64[i] = ((retval.dw64[i] & 0xCCCCCCCCCCCCCCCCULL) >> 2) | ((retval.dw64[i] & 0x3333333333333333ULL) << 2);
164 for (
int i = 0; i < 4; i++)
166 retval.dw64[i] = ((retval.dw64[i] & 0xAAAAAAAAAAAAAAAAULL) >> 1) | ((retval.dw64[i] & 0x5555555555555555ULL) << 1);
174 for (
int i = 0; i < 4; i++)
176 arr[i] = dw64[swap ? 3 - i : i];
182 dw64[bit / 64] |= (
_ONE_ << (bit % 64));
187 return (dw64[bit / 64] & (
_ONE_ << (bit % 64))) != 0;
193 for (
int i = 0; i < 4; i++)
194 retval +=
size(dw64[i], 0);
200 static const u64 segmask[] = {0xFFFFFFFF, 0xFFFF, 0xFF, 0xF};
201 static const int segshft[] = {32, 16, 8, 4};
202 static const int szlookup[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
205 return szlookup[dw & 0xF];
208 retval +=
size(dw & segmask[level], level + 1);
209 dw >>= segshft[level];
210 retval +=
size(dw & segmask[level], level + 1);
217 static const u64 segmask[] = {0xFFFFFFFF, 0xFFFF, 0xFF, 0xF};
218 static const int lblookup[16] = {-61, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
223 for (
int iseg = 0; iseg < 4; iseg++)
225 if (!(dw & segmask[iseg]))
233 return retval + lblookup[dw & 0xF];
238 for (
int i = 3; i >= 0; i--)
239 printf(
"%016lx", dw64[i]);
242 for (
unsigned int i = 0; i < 256; i++)
244 if (dw64[i / 64] & (
_ONE_ << (i % 64)))
252 for (
int i = 0; i < 4; i++)
253 retval.dw64[i] |= dw64[i];
260 for (
int i = 0; i < 4; i++)
261 retval.dw64[i] &= dw64[i];
268 for (
int i = 0; i < 4; i++)
269 retval.dw64[i] ^= dw64[i];
287 if (
const auto res = db.load(file_path); res.is_ok())
293 return ERR(res.get_error());
300 u32 bit_size = std::log2(sbox.size());
304 return ERR(
"S-box '" +
name +
"' has bit-size greater 8, but only S-boxes of up to 8 bits are supported");
307 for (
size_t alpha = 0; alpha < sbox.size(); alpha++)
309 std::vector<u8> sbox_alpha;
310 for (
u32 i = 0; i < sbox.size(); i++)
312 sbox_alpha.push_back(sbox.at(i) ^ alpha);
315 m_data[bit_size][lin_rep].push_back(std::make_pair(
name, alpha));
322 for (
const auto& [
name, sbox] : sboxes)
324 if (
const auto res =
add(
name, sbox); res.is_error())
326 return ERR(res.get_error());
334 FILE* fp = fopen(file_path.string().c_str(),
"r");
337 return ERR(
"could not parse S-box database file '" + file_path.string() +
"' : unable to open file");
341 rapidjson::FileReadStream is(fp, buffer,
sizeof(buffer));
342 rapidjson::Document document;
343 document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(is);
346 if (document.HasParseError())
348 return ERR(
"could not parse S-box database file '" + file_path.string() +
"': failed parsing JSON format");
356 for (
auto size_it = document.MemberBegin(); size_it != document.MemberEnd(); ++size_it)
358 u32 bit_size = std::stoul(std::string(size_it->name.GetString()));
359 const rapidjson::Value& cipher_val = size_it->value;
361 for (
auto cipher_it = cipher_val.MemberBegin(); cipher_it != cipher_val.MemberEnd(); ++cipher_it)
363 std::string cipher_name = cipher_it->name.GetString();
364 const rapidjson::Value& const_val = cipher_it->value;
366 for (
auto const_it = const_val.MemberBegin(); const_it != const_val.MemberEnd(); ++const_it)
368 u8 const_alpha = (
u8)std::stoul(std::string(const_it->name.GetString()));
369 const rapidjson::Value& lin_rep_val = const_it->value;
371 std::vector<u8> lin_rep;
372 for (
u32 i = 0; i < lin_rep_val.Size(); i++)
374 lin_rep.push_back((
u8)(lin_rep_val[i].GetUint()));
377 m_data[bit_size][lin_rep].push_back(std::make_pair(cipher_name, const_alpha));
387 FILE* fp = fopen(file_path.string().c_str(),
"w");
390 return ERR(
"could not write S-box database file '" + file_path.string() +
"' : unable to open file");
393 rapidjson::Document document;
394 document.SetObject();
396 rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
398 for (
const auto& [bit_size, lin_rep_map] : m_data)
400 std::map<std::string, std::map<u8, std::vector<u8>>> pretty_data;
401 for (
const auto& [lin_rep, cipher_vec] : lin_rep_map)
403 for (
const auto& [
name, alpha] : cipher_vec)
405 pretty_data[
name][alpha] = lin_rep;
409 rapidjson::Value cipher_json(rapidjson::kObjectType);
410 for (
const auto& [cipher_name, lin_rep_map] : pretty_data)
412 rapidjson::Value alpha_json(rapidjson::kObjectType);
413 for (
const auto& [const_alph, lin_rep] : lin_rep_map)
415 rapidjson::Value lin_rep_json(rapidjson::kArrayType);
416 for (
const auto val : lin_rep)
418 lin_rep_json.PushBack(val, allocator);
420 alpha_json.AddMember(rapidjson::Value(std::to_string(const_alph).c_str(), allocator).Move(), lin_rep_json, allocator);
422 cipher_json.AddMember(rapidjson::Value(cipher_name.c_str(), allocator).Move(), alpha_json, allocator);
424 document.AddMember(rapidjson::Value(std::to_string(bit_size).c_str(), allocator).Move(), cipher_json, allocator);
427 rapidjson::StringBuffer buffer;
428 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
430 document.Accept(writer);
432 std::ofstream file(file_path);
433 file << buffer.GetString();
436 return ERR(
"not implemented");
441 u32 bit_size = std::log2(sbox.size());
445 return ERR(
"S-box has bit-size greater 8, but only S-boxes of up to 8 bits are supported");
448 const auto size_it = m_data.find(bit_size);
449 if (size_it == m_data.end())
451 return ERR(
"no S-box of matching bit-size of " + std::to_string(bit_size) +
" bits contained in database");
454 for (
u8 beta = 0; beta < sbox.size(); beta++)
456 std::vector<u8> sbox_beta;
457 for (
u32 i = 0; i < sbox.size(); i++)
459 sbox_beta.push_back(sbox.at(i) ^ beta);
463 const auto& matching_size_data = std::get<1>(*size_it);
464 const auto rep_it = matching_size_data.find(lin_rep);
465 if (rep_it != matching_size_data.end())
467 return OK(rep_it->second.front().first);
471 return ERR(
"no match found within database");
476 for (
const auto& [bit_size, lin_rep_map] : m_data)
478 std::cout << std::endl;
479 std::cout <<
"### WIDTH: " << bit_size << std::endl;
480 std::cout <<
"#######################" << std::endl;
482 std::map<std::string, std::map<u8, std::vector<u8>>> pretty_data;
483 for (
const auto& [lin_rep, cipher_vec] : lin_rep_map)
485 for (
const auto& [
name, alpha] : cipher_vec)
487 pretty_data[
name][alpha] = lin_rep;
491 for (
const auto& [cipher_name, lin_rep_map] : pretty_data)
493 std::cout <<
"* " << cipher_name << std::endl;
495 for (
const auto& [const_alph, lin_rep] : lin_rep_map)
497 std::cout <<
" - " << (
u32)const_alph <<
": [" << (
u32)(lin_rep.at(0));
498 for (
u32 i = 1; i < lin_rep.size(); i++)
500 std::cout <<
", " << (
u32)(lin_rep.at(i));
502 std::cout <<
"]" << std::endl;
507 std::cout << std::endl;
517 elements[0] = _mm256_extract_epi64(a, 3);
518 elements[1] = _mm256_extract_epi64(a, 2);
519 elements[2] = _mm256_extract_epi64(a, 1);
520 elements[3] = _mm256_extract_epi64(a, 0);
521 #elif defined(__ARM_NEON)
522 elements[0] = a.val[1][1];
523 elements[1] = a.val[1][0];
524 elements[2] = a.val[0][1];
525 elements[3] = a.val[0][0];
529 std::cout <<
name <<
": 0b";
530 for (
u32 i = 0; i < 4; i++)
532 for (
int j = 63; j >= 0; j--)
534 u32 bit = (elements[i] >> j) & 1;
539 std::cout << std::endl;
546 chunks[0] = _mm256_extract_epi64(a, 0);
547 chunks[1] = _mm256_extract_epi64(a, 1);
548 chunks[2] = _mm256_extract_epi64(a, 2);
549 chunks[3] = _mm256_extract_epi64(a, 3);
550 #elif defined(__ARM_NEON)
551 chunks[0] = a.val[0][0];
552 chunks[1] = a.val[0][1];
553 chunks[2] = a.val[1][0];
554 chunks[3] = a.val[1][1];
558 for (
u32 i = 0; i < 4; i++)
560 u64 current_chunk = chunks[i];
561 if (current_chunk != 0)
563 u8 idx = __builtin_ctzll(current_chunk) + i * 64;
569 std::cout <<
"CALLED LEAST ELEMENT ON EMPTY SET!" << std::endl;
576 return _mm256_and_si256(a, b);
577 #elif defined(__ARM_NEON)
578 return {vandq_u64(a.val[0], b.val[0]), vandq_u64(a.val[1], b.val[1])};
587 return _mm256_or_si256(a, b);
588 #elif defined(__ARM_NEON)
589 return {vorrq_u64(a.val[0], b.val[0]), vorrq_u64(a.val[1], b.val[1])};
599 u64 chunk = _mm256_extract_epi64(a, 0);
600 count += __builtin_popcountll(chunk);
601 chunk = _mm256_extract_epi64(a, 1);
602 count += __builtin_popcountll(chunk);
603 chunk = _mm256_extract_epi64(a, 2);
604 count += __builtin_popcountll(chunk);
605 chunk = _mm256_extract_epi64(a, 3);
606 count += __builtin_popcountll(chunk);
607 #elif defined(__ARM_NEON)
608 count += __builtin_popcountll(a.val[0][0]);
609 count += __builtin_popcountll(a.val[0][1]);
610 count += __builtin_popcountll(a.val[1][0]);
611 count += __builtin_popcountll(a.val[1][1]);
618 inline bool smallset_is_empty(
const smallset_t& a)
621 return _mm256_testz_si256(a, a);
622 #elif defined(__ARM_NEON)
623 auto tmp = vandq_u64(vceqzq_u64(a.val[0]), vceqzq_u64(a.val[1]));
624 return (tmp[0] & tmp[1]) & 1;
637 __m256i _mask = _mm256_set_epi64x(mask[3], mask[2], mask[1], mask[0]);
638 return _mm256_or_si256(a, _mask);
639 #elif defined(__ARM_NEON)
641 mask[
index & 1] = (
u64)1 << (elm % 64);
642 auto _mask = vld1q_u64(mask);
645 return {vorrq_u64(a.val[0], _mask), a.val[1]};
649 return {a.val[0], vorrq_u64(a.val[1], _mask)};
660 #if !defined(__AVX2__) && !defined(__ARM_NEON)
666 if ((shift >> 7) & 0x1)
669 a = _mm256_permute2x128_si256(a, a, 1);
670 #elif defined(__ARM_NEON)
675 if ((shift >> 6) & 0x1)
678 a = _mm256_permute4x64_epi64(a, _MM_SHUFFLE(2, 3, 0, 1));
679 #elif defined(__ARM_NEON)
680 a.val[0] = vextq_u64(a.val[0], a.val[0], 1);
681 a.val[1] = vextq_u64(a.val[1], a.val[1], 1);
684 if ((shift >> 5) & 0x1)
687 a = _mm256_shuffle_epi32(a, _MM_SHUFFLE(2, 3, 0, 1));
688 #elif defined(__ARM_NEON)
689 a.val[0] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[0]);
690 a.val[1] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[1]);
694 if ((shift >> 4) & 0x1)
697 a = _mm256_shufflelo_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
698 a = _mm256_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
699 #elif defined(__ARM_NEON)
700 a.val[0] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[0]);
701 a.val[0] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[0]);
702 a.val[1] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[1]);
703 a.val[1] = (uint64x2_t) vrev64q_u32((uint32x4_t) a.val[1]);
706 if ((shift >> 3) & 0x1)
709 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);
710 a = _mm256_shuffle_epi8(a, mask);
711 #elif defined(__ARM_NEON)
712 a.val[0] = (uint64x2_t) vrev64q_u8 ((uint8x16_t) a.val[0]);
713 a.val[0] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[0]);
714 a.val[1] = (uint64x2_t) vrev64q_u8 ((uint8x16_t) a.val[1]);
715 a.val[1] = (uint64x2_t) vrev64q_u16((uint16x8_t) a.val[1]);
718 if ((shift >> 2) & 0x1)
721 const __m256i mask_high = _mm256_set1_epi8((
char)0xF0);
722 const __m256i mask_low = _mm256_set1_epi8(0x0F);
723 const __m256i high = _mm256_and_si256(a, mask_high);
724 const __m256i low = _mm256_and_si256(a, mask_low);
725 a = _mm256_or_si256(_mm256_srli_epi16(high, 4), _mm256_slli_epi16(low, 4));
726 #elif defined(__ARM_NEON)
727 const auto mask_high = vdupq_n_u64(0xF0F0F0F0F0F0F0F0);
728 const auto mask_low = vdupq_n_u64(0x0F0F0F0F0F0F0F0F);
730 for (
u32 i = 0; i < 2; i++)
732 const auto high = vandq_u64(a.val[i], mask_high);
733 const auto low = vandq_u64(a.val[i], mask_low);
735 a.val[i] = vorrq_u64(vshrq_n_u64(high, 4), vshlq_n_u64(low, 4));
739 if ((shift >> 1) & 0x1)
742 const __m256i mask_high = _mm256_set1_epi8((
char)0xCC);
743 const __m256i mask_low = _mm256_set1_epi8(0x33);
744 const __m256i high = _mm256_and_si256(a, mask_high);
745 const __m256i low = _mm256_and_si256(a, mask_low);
746 a = _mm256_or_si256(_mm256_srli_epi16(high, 2), _mm256_slli_epi16(low, 2));
747 #elif defined(__ARM_NEON)
748 const auto mask_high = vdupq_n_u64(0xCCCCCCCCCCCCCCCC);
749 const auto mask_low = vdupq_n_u64(0x3333333333333333);
751 for (
u32 i = 0; i < 2; i++)
753 const auto high = vandq_u64(a.val[i], mask_high);
754 const auto low = vandq_u64(a.val[i], mask_low);
756 a.val[i] = vorrq_u64(vshrq_n_u64(high, 2), vshlq_n_u64(low, 2));
763 const __m256i mask_high = _mm256_set1_epi8((
char)0xAA);
764 const __m256i mask_low = _mm256_set1_epi8(0x55);
765 const __m256i high = _mm256_and_si256(a, mask_high);
766 const __m256i low = _mm256_and_si256(a, mask_low);
767 a = _mm256_or_si256(_mm256_srli_epi16(high, 1), _mm256_slli_epi16(low, 1));
768 #elif defined(__ARM_NEON)
769 const auto mask_high = vdupq_n_u64(0xAAAAAAAAAAAAAAAA);
770 const auto mask_low = vdupq_n_u64(0x5555555555555555);
772 for (
u32 i = 0; i < 2; i++)
774 const auto high = vandq_u64(a.val[i], mask_high);
775 const auto low = vandq_u64(a.val[i], mask_low);
777 a.val[i] = vorrq_u64(vshrq_n_u64(high, 1), vshlq_n_u64(low, 1));
787 return smallset_union(a, b);
790 std::vector<u8> smallset_get_elements(
const smallset_t& a)
795 chunks[0] = _mm256_extract_epi64(a, 0);
796 chunks[1] = _mm256_extract_epi64(a, 1);
797 chunks[2] = _mm256_extract_epi64(a, 2);
798 chunks[3] = _mm256_extract_epi64(a, 3);
799 #elif defined(__ARM_NEON)
800 chunks[0] = a.val[0][0];
801 chunks[1] = a.val[0][1];
802 chunks[2] = a.val[1][0];
803 chunks[3] = a.val[1][1];
807 for (
u32 i = 0; i < 4; i++)
809 u64 current_chunk = chunks[i];
810 while (current_chunk != 0)
812 u8 idx = __builtin_ctzll(current_chunk) + i * 64;
814 current_chunk &= (current_chunk - 1);
823 return _mm256_setzero_si256();
824 #elif defined(__ARM_NEON)
825 return {vdupq_n_u64(0), vdupq_n_u64(0)};
833 #if !defined(__AVX2__) && !defined(__ARM_NEON)
840 return _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
841 #elif defined(__ARM_NEON)
842 return {vdupq_n_u64(0xFFFFFFFFFFFFFFFF), vdupq_n_u64(0xFFFFFFFFFFFFFFFF)};
848 return _mm256_set_epi64x(0, 0, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
849 #elif defined(__ARM_NEON)
850 return {vdupq_n_u64(0xFFFFFFFFFFFFFFFF), vdupq_n_u64(0)};
856 return _mm256_set_epi64x(0, 0, 0, 0xFFFFFFFFFFFFFFFF);
857 #elif defined(__ARM_NEON)
858 auto tmp = vdupq_n_u64(0);
859 return {vsetq_lane_u64(0xFFFFFFFFFFFFFFFF, tmp, 0), vdupq_n_u64(0)};
865 return _mm256_set_epi64x(0, 0, 0, 0xFFFFFFFF);
866 #elif defined(__ARM_NEON)
867 auto tmp = vdupq_n_u64(0);
868 return {(uint64x2_t)vsetq_lane_u32(0xFFFFFFFF, (uint32x4_t)tmp, 0), vdupq_n_u64(0)};
874 return _mm256_set_epi64x(0, 0, 0, 0xFFFF);
875 #elif defined(__ARM_NEON)
876 auto tmp = vdupq_n_u64(0);
877 return {(uint64x2_t)vsetq_lane_u16(0xFFFF, (uint16x8_t)tmp, 0), vdupq_n_u64(0)};
883 return _mm256_set_epi64x(0, 0, 0, 0xFF);
884 #elif defined(__ARM_NEON)
885 auto tmp = vdupq_n_u64(0);
886 return {(uint64x2_t)vsetq_lane_u8(0xFF, (uint8x16_t)tmp, 0), vdupq_n_u64(0)};
892 return _mm256_set_epi64x(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
893 #elif defined(__ARM_NEON)
894 return {vdupq_n_u64(0xFFFFFFFFFFFFFFFF), vdupq_n_u64(0xFFFFFFFFFFFFFFFF)};
903 return _mm256_xor_si256(a, b);
904 #elif defined(__ARM_NEON)
905 return {veorq_u64(a.val[0], b.val[0]), veorq_u64(a.val[1], b.val[1])};
913 const smallset_t b_not = smallset_invert(b, len);
914 return smallset_intersect(a, b_not);
917 bool smallset_elm_is_in_set(
const u8 e,
const smallset_t& a)
919 #if !defined(__AVX2__) && !defined(__ARM_NEON)
923 b = smallset_add_element(b, e);
924 b = smallset_intersect(a, b);
925 return !smallset_is_empty(b);
947 bool is_greater(
const std::vector<u8>&
R_S,
const std::vector<u8>& R_S_best,
const u32 len)
949 if ((R_S_best[0] == 0) && (R_S_best[1] == 0))
952 for (
u32 x = 0;
x < len;
x++)
956 if (
R_S[
x] > R_S_best[
x])
958 if (
R_S[
x] < R_S_best[
x])
965 bool update_linear(std::vector<u8>&
A,
u8 new_x,
const u32 len)
968 for (
u32 i = 1; i < len; i++)
973 else if (
A[new_x ^ i] == 0)
974 A[new_x ^ i] = e ^ new_y;
975 else if (
A[new_x ^ i] != (e ^ new_y))
983 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)
985 std::vector<u8>
A(
state.A);
986 std::vector<u8>
B(
state.B);
998 while (!smallset_is_empty(
N_A))
1000 u8 x = smallset_least_element(
N_A);
1001 u8 y = smallset_least_element(
U_B);
1004 if (!update_linear(
B,
y, len))
1007 D_B = smallset_union(
D_B, D_B_new);
1008 U_B = smallset_setminus(
U_B, D_B_new, len);
1011 for (
u8 x : smallset_get_elements(
N_A))
1013 SoA_N_A = smallset_add_element(SoA_N_A, S[
A[
x]]);
1015 smallset_t B_D_B_new = smallset_init_empty();
1016 for (
u8 d : smallset_get_elements(D_B_new))
1018 B_D_B_new = smallset_add_element(B_D_B_new,
B[d]);
1019 if (smallset_elm_is_in_set(
B[d], SoA_N_A))
1021 C_B = smallset_add_element(
C_B, d);
1025 N_B = smallset_add_element(
N_B, d);
1029 for (
u8 x : smallset_get_elements(
N_A))
1031 if (smallset_elm_is_in_set(S[
A[
x]], B_D_B_new))
1033 C_A_new = smallset_add_element(C_A_new,
x);
1036 C_A = smallset_union(
C_A, C_A_new);
1037 N_A = smallset_setminus(
N_A, C_A_new, len);
1038 for (
u8 x : smallset_get_elements(C_A_new))
1041 for (
u32 i = 0; i < len; i++)
1043 if (
B[i] == S[
A[
x]])
1051 if (is_greater(
R_S, R_S_best, len))
1056 while (smallset_is_empty(
N_A) && !smallset_is_empty(
N_B))
1058 u8 x = smallset_least_element(
U_A);
1059 u8 y = smallset_least_element(
N_B);
1061 if (!update_linear(
A,
x, len))
1066 D_A = smallset_union(
D_A, D_A_new);
1067 U_A = smallset_setminus(
U_A, D_A_new, len);
1068 smallset_t SinvoB_N_B = smallset_init_empty();
1069 for (
u8 y : smallset_get_elements(
N_B))
1071 SinvoB_N_B = smallset_add_element(SinvoB_N_B, S_inv[
B[
y]]);
1073 smallset_t A_D_A_new = smallset_init_empty();
1074 for (
u8 d : smallset_get_elements(D_A_new))
1076 A_D_A_new = smallset_add_element(A_D_A_new,
A[d]);
1077 if (smallset_elm_is_in_set(
A[d], SinvoB_N_B))
1079 C_A = smallset_add_element(
C_A, d);
1083 N_A = smallset_add_element(
N_A, d);
1087 for (
u8 y : smallset_get_elements(
N_B))
1089 if (smallset_elm_is_in_set(S_inv[
B[
y]], A_D_A_new))
1091 C_B_new = smallset_add_element(C_B_new,
y);
1094 C_B = smallset_union(
C_B, C_B_new);
1095 N_B = smallset_setminus(
N_B, C_B_new, len);
1096 for (
u8 y : smallset_get_elements(C_B_new))
1099 for (
u32 i = 0; i < len; i++)
1101 if (
A[i] == S_inv[
B[
y]])
1109 if (is_greater(
R_S, R_S_best, len))
1115 if (smallset_is_empty(
U_A) && smallset_is_empty(
U_B))
1117 for (
u32 i = 0; i < len; i++)
1120 R_S_best[i] =
R_S[i];
1126 u8 x = smallset_least_element(
U_A);
1128 U_A = smallset_setminus(
U_A, D_A_new, len);
1129 D_A = smallset_union(
D_A, D_A_new);
1130 N_A = smallset_union(
N_A, D_A_new);
1134 for (
u32 i = 0; i < len; i++)
1136 A_set = smallset_add_element(A_set,
A[i]);
1138 Y = smallset_setminus(Y, A_set, len);
1139 for (
u8 y : smallset_get_elements(Y))
1141 std::vector<u8> A_next_guess(len);
1143 for (
u32 i = 0; i < len; i++)
1145 A_next_guess[i] =
A[i];
1147 A_next_guess[
x] =
y;
1148 if (!update_linear(A_next_guess,
x, len))
1151 state_next.A = A_next_guess;
1153 state_next.R_S =
R_S;
1154 state_next.D_A =
D_A;
1155 state_next.D_B =
D_B;
1156 state_next.C_A =
C_A;
1157 state_next.C_B =
C_B;
1158 state_next.N_A =
N_A;
1159 state_next.N_B =
N_B;
1160 state_next.U_A =
U_A;
1161 state_next.U_B =
U_B;
1163 if (subroutine(S, S_inv, state_next, R_S_best, len))
1176 u32 len = sbox.size();
1179 std::vector<u8> R_S_best(len, 0);
1182 std::vector<u8> S_inv(len, 0);
1183 for (
u32 x = 0;
x < len;
x++)
1191 state.A = std::vector<u8>(len, 0);
1192 state.B = std::vector<u8>(len, 0);
1193 state.R_S = std::vector<u8>(len, 0);
1195 state.D_A = smallset_add_element(smallset_init_empty(), 0);
1196 state.D_B = smallset_add_element(smallset_init_empty(), 0);
1198 state.C_A = smallset_init_empty();
1199 state.C_B = smallset_init_empty();
1201 state.N_A = smallset_add_element(smallset_init_empty(), 0);
1202 state.N_B = smallset_add_element(smallset_init_empty(), 0);
1204 state.U_A = smallset_setminus(smallset_init_full(len),
state.D_A, len);
1205 state.U_B = smallset_setminus(smallset_init_full(len),
state.D_A, len);
1210 state.C_A = smallset_add_element(smallset_init_empty(), 0);
1211 state.C_B = smallset_add_element(smallset_init_empty(), 0);
1213 state.N_A = smallset_init_empty();
1214 state.N_B = smallset_init_empty();
1218 subroutine(sbox, S_inv,
state, R_S_best, len);
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
This file contains the S-box database class that holds and manages known cryptographic S-boxes up to ...