Расшифровка закрытого текста с помощью частотного анализа

у меня есть зашифрованный текст. я разбил его на диады чтобы получить числа для частотного анализа. написал html программу которая подсчитала количество чисел и их частоту и сопоставила с частотностью букв русского языка. ниже приложу непосредственно шифртекст и код.

проблема заключается в том что при подстановке в соответствии с посчитанной частотой получается несвязанный текст. прошу вас помочь, кто разбирается в этом. предположительно текст должен быть из серии книг о незнайке.

Вот шифртекст: 81 69 83 90 69 83 88 17 54 83 88 45 17 82 69 66 35 82 69 87 
17 11 70 17 69 75 93 35 69 87 21 57 83 79 30 87 35 21 88 54 35 82 69 87 83 
87 35 93 83 54 57 17 55 57 17 57 79 83 93 83 11 83 12 64 35 45 35 53 35 87 
83 57 21 82 54 21 45 35 58 17 55 57 17 57 82 69 83 45 83 64 35 54 83 12 58 
35 82 93 21 87 11 17 82 69 45 17 11 17 93 17 83 69 82 54 83 35 12 87 35 30 
57 93 99 64 35 82 69 21 21 35 29 35 53 83 93 75 66 35 83 69 69 83 38 83 81 
69 83 87 35 53 42 93 17 87 21 64 35 87 29 21 87 83 12 87 21 11 35 54 83 81 
57 83 12 54 66 57 83 93 35 54 82 35 35 29 35 83 53 40 83 11 21 93 83 82 75 
87 83 83 87 17 88 17 57 83 87 81 21 93 17 30 81 35 53 30 21 87 21 57 69 83 
57 17 88 17 93 83 82 75 87 35 21 79 35 93 87 21 79 17 93 35 12 66 35 38 83 
58 45 35 11 82 69 17 54 93 35 87 21 55 83 35 35 53 30 11 30 29 35 79 83 69 
35 70 82 83 53 21 45 17 93 82 55 83 69 58 45 17 54 21 69 75 35 35 87 17 82 
93 35 11 30 99 29 30 99 88 21 79 30 54 58 17 45 21 64 87 83 90 69 83 35 12 
82 83 54 35 45 66 35 87 87 83 87 35 30 93 42 53 17 93 83 82 75 58 45 17 54 
11 17 21 69 83 81 69 83 35 12 53 83 93 75 66 35 40 83 69 35 93 83 82 75 83 
82 69 17 54 17 69 75 82 55 11 83 79 17 83 87 17 83 82 83 88 87 17 93 17 90 
69 83 87 35 11 17 54 87 83 87 83 81 35 69 57 83 83 87 17 87 35 87 17 54 21 
11 35 93 17 17 45 93 35 87 30

вот html файл:

начало файла прикрепляю фото:

// Ваш зашифрованный текст (диады)
const encryptedText = "81 69 83 90 69 83 88 17 54 83 88 45 17 82 69 66 35 82 69 87 17 11 70 17 69 75 93 35 69 87 21 57 83 79 30 87 35 21 88 54 35 82 69 87 83 87 35 93 83 54 57 17 55 57 17 57 79 83 93 83 11 83 12 64 35 45 35 53 35 87 83 57 21 82 54 21 45 35 58 17 55 57 17 57 82 69 83 45 83 64 35 54 83 12 58 35 82 93 21 87 11 17 82 69 45 17 11 17 93 17 83 69 82 54 83 35 12 87 35 30 57 93 99 64 35 82 69 21 21 35 29 35 53 83 93 75 66 35 83 69 69 83 38 83 81 69 83 87 35 53 42 93 17 87 21 64 35 87 29 21 87 83 12 87 21 11 35 54 83 81 57 83 12 54 66 57 83 93 35 54 82 35 35 29 35 83 53 40 83 11 21 93 83 82 75 87 83 83 87 17 88 17 57 83 87 81 21 93 17 30 81 35 53 30 21 87 21 57 69 83 57 17 88 17 93 83 82 75 87 35 21 79 35 93 87 21 79 17 93 35 12 66 35 38 83 58 45 35 11 82 69 17 54 93 35 87 21 55 83 35 35 53 30 11 30 29 35 79 83 69 35 70 82 83 53 21 45 17 93 82 55 83 69 58 45 17 54 21 69 75 35 35 87 17 82 93 35 11 30 99 29 30 99 88 21 79 30 54 58 17 45 21 64 87 83 90 69 83 35 12 82 83 54 35 45 66 35 87 87 83 87 35 30 93 42 53 17 93 83 82 75 58 45 17 54 11 17 21 69 83 81 69 83 35 12 53 83 93 75 66 35 40 83 69 35 93 83 82 75 83 82 69 17 54 17 69 75 82 55 11 83 79 17 83 87 17 83 82 83 88 87 17 93 17 90 69 83 87 35 11 17 54 87 83 87 83 81 35 69 57 83 83 87 17 87 35 87 17 54 21 11 35 93 17 17 45 93 35 87 30";

// Русский алфавит в порядке убывания частоты
const russianAlphabet = [
  'о', 'е', 'а', 'и', 'н', 'т', 'с', 'р', 'в', 'л',
  'к', 'м', 'д', 'п', 'у', 'я', 'ы', 'ь', 'г', 'з',
  'б', 'ч', 'й', 'х', 'ж', 'ш', 'ю', 'ц', 'щ', 'э',
  'ф', 'ъ'
];

// Используем вашу таблицу частот (диады отсортированы по убыванию частоты)
const frequencyData = [{
    diad: '83',
    count: 57
  },
  {
    diad: '35',
    count: 50
  },
  {
    diad: '17',
    count: 38
  },
  {
    diad: '87',
    count: 34
  },
  {
    diad: '69',
    count: 27
  },
  {
    diad: '93',
    count: 24
  },
  {
    diad: '21',
    count: 23
  },
  {
    diad: '82',
    count: 22
  },
  {
    diad: '54',
    count: 17
  },
  {
    diad: '57',
    count: 14
  },
  {
    diad: '11',
    count: 13
  },
  {
    diad: '45',
    count: 12
  },
  {
    diad: '30',
    count: 11
  },
  {
    diad: '53',
    count: 9
  },
  {
    diad: '75',
    count: 9
  },
  {
    diad: '12',
    count: 8
  },
  {
    diad: '79',
    count: 7
  },
  {
    diad: '81',
    count: 7
  },
  {
    diad: '88',
    count: 7
  },
  {
    diad: '58',
    count: 6
  },
  {
    diad: '66',
    count: 6
  },
  {
    diad: '29',
    count: 5
  },
  {
    diad: '55',
    count: 5
  },
  {
    diad: '64',
    count: 5
  },
  {
    diad: '90',
    count: 3
  },
  {
    diad: '99',
    count: 3
  },
  {
    diad: '38',
    count: 2
  },
  {
    diad: '40',
    count: 2
  },
  {
    diad: '42',
    count: 2
  },
  {
    diad: '70',
    count: 2
  }
];

// Отображаем исходный текст
$("#code").text(encryptedText);

// Заполняем таблицу русского алфавита
russianAlphabet.forEach(function(letter, index) {
  $(`<td style="width: 35px; font-size: 14px; font-weight: bold;">${letter}</td>`).appendTo("#letters");
  $(`<td style="width: 35px; background-color: #f8f9fa; font-size: 13px;">${index + 1}</td>`).appendTo("#freq-order");
});

// Заполняем горизонтальную таблицу частотности
let diadsHeaderHtml = '';
let countsHtml = '';
let inputsHtml = '';

frequencyData.forEach(function(item, index) {
  diadsHeaderHtml += `<td class="diad-cell">${item.diad}</td>`;
  countsHtml += `<td class="count-cell">${item.count}</td>`;
  inputsHtml += `
                <td class="input-cell">
                    <input class="substitution-input"
                           data-diad="${item.diad}"
                           style="width:32px; height:28px;"
                           maxlength="1"/>
                </td>
            `;
});

$("#diads-header").html(diadsHeaderHtml);
$("#counts").html(countsHtml);
$("#inputs").html(inputsHtml);

// Функция для применения подстановок
function applySubstitutions() {
  let result = encryptedText;

  // Сбрасываем подсветку
  $("#letters td").removeClass('active');

  // Применяем все введенные замены
  $(".substitution-input").each(function() {
    const diad = $(this).data('diad');
    const letter = $(this).val().toLowerCase();

    if (letter && /[а-яё]/.test(letter)) {
      // Заменяем все вхождения диады
      const regex = new RegExp(diad, 'g');
      result = result.replace(regex, `<mark>${letter}</mark>`);

      // Подсвечиваем использованную букву в алфавите
      $('#letters td').each(function() {
        if ($(this).text() === letter) {
          $(this).addClass('active');
        }
      });
    }
  });

  // Отображаем результат
  $("#code").html(result);
}

// Обработчик ввода в поля подстановок
$(document).on('keyup', '.substitution-input', function() {
  applySubstitutions();
});

// Кнопка сброса
$("#reset-btn").click(function() {
  $(".substitution-input").val('');
  applySubstitutions();
});

// Инициализация при загрузке
$(document).ready(function() {
  applySubstitutions();
});
<!-- Русский алфавит -->
<div class="row justify-content-center">
  <div class="col-12">
    <h5 class="text-center mb-2" style="font-size: 16px;">Русский алфавит (по частоте)</h5>
    <div class="table-responsive">
      <table class="table table-bordered table-sm alphabet-table">
        <tr id="letters"></tr>
        <tr id="freq-order"></tr>
      </table>
    </div>
  </div>
</div>

<!-- Горизонтальная таблица частотности диад -->
<div class="mt-3">
  <h5 class="text-center mb-2" style="font-size: 16px;">Частотность диад в тексте</h5>
  <div class="horizontal-table">
    <table class="frequency-table">
      <!-- Строка с диадами -->
      <tr>
        <td class="table-title">ДИАДА</td>
        <td id="diads-header"></td>
      </tr>
      <!-- Строка с количеством -->
      <tr>
        <td class="table-title">КОЛ-ВО</td>
        <td id="counts"></td>
      </tr>
      <!-- Строка с подстановками -->
      <tr>
        <td class="table-title">ЗАМЕНА</td>
        <td id="inputs"></td>
      </tr>
    </table>
  </div>
</div>

<div class="mt-3">
  <h4 style="font-size: 18px;">Результат расшифровки:</h4>
  <div id="code" class="p-2 bg-light border rounded"></div>
</div>

<div class="mt-2">
  <button id="reset-btn" class="btn btn-warning btn-sm">Сбросить все замены</button>
  <span class="ms-2 text-muted" style="font-size: 12px;">Вводите буквы в поля "ЗАМЕНА" для подстановки</span>
</div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

</body>

</html>


Ответы (1 шт):

Автор решения: InterceptorTSK

Если "по-честному", то нужно собирать все частоты, частота - это отношение количества к общему количеству, например может быть выражено в процентах.

Частота "кодов" в зашифрованном тексте:

//  11  3,02%
//  12  1,86%
//  17  8,84%
//  21  5,35%
//  29  1,16%
//  30  2,56%
//  35  11,63%
//  38  0,47%
//  40  0,47%
//  42  0,47%
//  45  2,79%
//  53  2,09%
//  54  3,95%
//  55  1,16%
//  57  3,26%
//  58  1,40%
//  64  1,16%
//  66  1,40%
//  69  6,28%
//  70  0,47%
//  75  2,09%
//  79  1,63%
//  81  1,63%
//  82  5,12%
//  83  13,26%  << аномалия, или это 'o'?
//  87  7,91%
//  88  1,63%
//  90  0,70%
//  93  5,58%
//  99  0,70%

Частота букв русского языка: Частота букв русского языка

Далее, нужно сравнить референсные частоты букв русского языка, с полученными частотами кодов из шифротекста, это весьма не тривиально сделать.

→ Ссылка