e-olimp 4650. Граф-Турнир

Задача на e-olimp

Оригинал решения 

Тесты на Try Haxe!

Постановка задачи:

Построить на [latex]n[/latex] вершинах турнир, расстояние между любой парой вершин в котором не превышает двух рёбер.

Алгоритм решения:

Условию удовлетворяет любая тройка вершин, принадлежащих циклу длины три, следовательно, искомый граф сильно связен. Уместно взять за основу полный неориентированный граф [latex]K_n[/latex] (не ограничивая общности рассуждений, будем представлять граф на плоскости как правильный n-угольник) и задать на нём ориентацию рёбер согласно набору правил:

Контур графа (рёбра вида [latex](k,k+1)[/latex]) ориентирован по часовой стрелке.
В дальнейших построениях будем отталкиваться от контура: каждая вершина графа должна находиться в хотя бы в одном цикле длины три с данной. Опишем процедуру построения такого орграфа: начиная с вершины под номером 1 будем просматривать все остальные вершины. Если на некотором шаге ребро, связывающее вершины, не ориентировано, то ориентируем его образом, противоположным ориентации ребра, соединяющего текущую вершину-исток и предыдущую по номеру вершину в обходе. Более конструктивно процедура формулируется так: обойти все вершины в порядке их следования в контуре. Пусть номер стартовой вершины для исходной итерации — [latex]V_i[/latex], рассматриваемой на данном шаге — [latex]V_k[/latex] Если ребро [latex](V_i,V_k)[/latex] не ориентировано, и номера обеих вершин (не)чётны — задать ориентацию [latex][V_i,V_k][/latex], иначе — [latex][V_k,V_i][/latex].

Исключение — граф [latex]K_4[/latex]: степень каждой вершины равна трём, следовательно, одно ребро каждой вершины не принадлежит контуру. Но таких рёбер всего два, следовательно, невозможно задать чередование ориентаций рёбер и получить четыре цикла длины 3. Для всех графов на большем числе вершин построение всегда возможно.

Реализация:

Для решения задачи достаточно хранить граф в форме матрицы смежности.

Тесты:

n = 5 \begin{pmatrix}0 & 1 & 1&0&0 \\0 & 0 & 1&1&0 \\0 & 0 &0&1&1\\1 & 0& 0&0&1\\1 & 1 & 0&0&0\end{pmatrix}
n = 3 \begin{pmatrix}0 & 1 & 0 \\0 & 0 & 1 \\1 & 0 & 0 \end{pmatrix}

Код:

A704

Задача взята отсюда.

Условие

Даны квадратные матрицы с целыми числами $A$, $B$ и $C$ порядка $n$. Получить матрицу $(A+B)*C$.

Входные данные

В первой строке — размерность матриц $n$. Далее вводятся построчно матрицы $A$, $B$ и $C$.

Выходные данные

Вывести построчно результирующую матрицу $(A+B)*C$.

Тесты:

Тесты:

$n$ $A$ $B$ $C$ Output
$3$ $1$ $2$ $3$
$4$ $5$ $6$
$7$ $8$ $9$
$0$ $1$ $0$
$0$ $0$ $0$
$0$ $0$ $0$
$1$ $0$ $0$
$0$ $1$ $0$
$0$ $0$ $1$
$1$ $3$ $3$
$4$ $5$ $6$
$7$ $8$ $9$
$2$ $4$ $6$
$12$ $7$
$3$ $2$
$1$ $1$
$7$ $3$
$2$ $8$
$65$ $85$
$107$ $103$
$3$ $3$ $4$ $1$
$1$ $2$ $1$
$5$ $6$ $7$
$1$ $3$ $1$
$2$ $4$ $5$
$6$ $5$ $1$
$1$ $1$ $0$
$5$ $8$ $1$
$2$ $3$ $2$
$43$ $66$ $11$
$45$ $69$ $18$
$82$ $123$ $27$

Код на Haxe:

Ход решения:

В первом цикле читаем матрицу $A$:

Во втором цикле считываем элементы матрицы $B$ и сразу прибавляем их к соответствующим элементам матрицы $A$:

В третьем цикле читаем матрицу $C$:

Наконец, в четвертом цикле вычисляем и выводим элементы результирующей матрицы $D = (A + B) * C$:

Ссылки:

Рабочий код для тестирования на try.haxe.org: Try Haxe !

A703

Условие
Даны квадратная матрица $A$ порядка $n$, векторы $x$ и $y$ с $n$ элементами каждый. Получить вектор $A(x+y)$.

Входные данные
Число $n$, матрица $A$, вектор $x$, вектор $y$.

Выходные данные
Результирующий вектор $A(x+y)$.

Тесты

Число $n$ Матрица $A$ Вектор $x$ Вектор $y$ Результирующий вектор $A(x+y)$
2 2 3
3 2
3 4 5 6 46 44
3 2 1 4
5 2 6
3 4 8
2 2 2 3 3 3 42 78 90
4 1 2 3 4
3 4 1 6
2 3 8 1
4 5 0 8
1 2 3 4 5 4 3 2 60 84 84 102

Решение
Вводим число $n$, матрицу $A$, вектора $x$ и $y$. Заходим в цикл в котором считаем сумму векторов $x$ и $y$. В следующем цикле считаем произведение матрицы $A$ на результат сложения векторов $x$ и $y$. Выводим результирующий вектор $res = A(x+y)$.

Try Haxe !

А412г

Ссылка на оригинальное решение

Задача:

Даны две целочисленные квадратные матрицы порядка $ 6 $. Найти последовательность из нулей и единиц $ b_1, \dots , b_6 $ такую, что $ b_i = 1 $, когда количество отрицательных и неотрицательных элементов $ i $-й строки первой матрицы совпадает соответственно с количеством отрицательных и неотрицательных элементов $ i $-й строки второй матрицы.

Тесты:

Матрица $ A $ Матрица $ B $ Выходные данные
1 1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
2  1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
0 0 0 0 0 0
3  1 1 1 1 1 1
-1 -1 -1 -1 -1 -1
1 1 1 1 1 1
1 1 1 1 1 1
-1 -1 -1 -1 -1 -1
1 1 1 1 1 1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
0 1 0 0 1 0
4 0 2 2 3 4 4
1 3 3 4 5 5
2 4 4 5 6 6
3 5 5 6 7 7
4 6 6 7 8 8
5 7 7 8 9 9
0 2 2 3 4 4
-1 3 1 4 3 5
-2 4 0 5 2 6
-3 5 -1 6 1 7
-4 6 -2 7 0 8
-5 7 -3 8 -1 9
1 0 0 0 0 0

Код программы:

 

Ссылка на tryhaxe

Решение:

Заведем массив  ans , в который будем дописывать $ 1 $, если количество неотрицательных элементов матрицы $ A $ в текущей строке совпадает с количеством неотрицательных элементов матрицы $ B $ в текущей строке, и $ 0 $  в противном случае. Проверять совпадение количества отрицательных элементов отдельно не нужно, потому как строки в матрицах одинаковой длины, т. е. количество отрицательных элементов всегда равно $ 6 — $ (количество_неотрицательных).

В цикле по переменной i  проходимся по каждой из шести строк матриц, каждый раз заводя счетчики на количество неотрицательных элементов. Цикл по j идет по столбцам матриц, проверяя каждый элемент. Если встретили неотрицательный элемент в матрице $ A $, увеличиваем счетик  a_positive . Если неотрицательный элемент попался в $ B $, увеличиваем  b_positive .

По истечении прохода по текущей строке проверяем, совпадает ли количество неотрицательных элементов в строке $ i $ для обеих матриц. Если да, дописываем в ответ единицу, иначе — ноль.

 

a406

Задача. С помощью [latex]x_{ij}, i=1,2; j=1,…,n[/latex] — действительной матрицы на плоскости задано [latex]n[/latex] точек так, что [latex]x_{1j},x_{2j} [/latex] — координаты [latex]j [/latex]— точки. Точки попарно соединены отрезками. Найти длину наибольшего отрезка.

Тест

n Матрица [latex]x_{ij}, i=1,2[/latex] Длина наибольшего отрезка  Комментарий
3 2 8 4

9 1 5

10 Пройдено
4 6 14 2 1

9 3 8 0

13.3417 Пройдено
5 1 8 4 3 7

2 9 5 0 11

11.7047 Пройдено

 

Код программы

Ход решения:

  1. Вводим матрицу построчно (не очень удобно).
  2. Находим длину наибольшего отрезка.
    С помощью вложенных циклов мы находим длины всех отрезков по формуле
    AB=(x2−x1)2+(y2−y1)2,A(x1,y1),B(x2,y2).
  3. По алгоритму нахождения максимума находим длину наибольшего отрезка.
  4. Выводим матрицу.
  5. Выводим длину наибольшего отрезка.

Пример выполнения

A710

Ссылка на оригинальное задания: тут.

Условие

Дана матрица $A$ размера [latex]n \times m[/latex]. Получить транспонированную матрицу $A^*$ (ее размер [latex]m \times n[/latex]).

Входные данные.

Первая строка содержит параметры $n$ и $m$. В следующих $n$ строках содержится матрица $A$.

Выходные данные.

Матрица $A^*$.

Тесты

n m A A*
3 4 1 2 3 4
2 3 4 5
3 4 5 6
1 2 3
2 3 4
3 4 5
4 5 6
2 3 1 2 3
2 3 4
1 2
2 3
3 4

Код.

Решение.

Считываем матрицу [latex]n \times m[/latex], а затем создаем транспонированную матрицу, в которой строки исходной матрицы являются столбцами и наоборот. Выводим $A^*$.
Ссылка на решение задачи на сайте Try Haxe!

А400

Задача. Дана действительная квадратная матрица порядка [latex]n[/latex]. Получить [latex]x_{1}x_{n} + x_{2}x_{n-1}+ \cdots + x_{n}x_{1}  [/latex], где[latex] x_k[/latex] — наибольшее значение элементов [latex]k[/latex]-й строки данной матрицы.

Суть задачи. Происходит заполнение многомерного массива. После этого в силу коммутативности умножения первая сумма полностью совпадает с последней, вторая — с предпоследней и т.д. Т.е. все слагаемые берутся дважды, кроме середины для нечётного [latex]n[/latex]. Это означает, что каждый максимум при вычислении суммы потребуется ровно один раз и никакой массив максимумов не нужен.

Оригинал решения

Решение на Try Haxe!

Тесты

[latex]n[/latex] Элементы Результат
2 1 2 3 4 16
3 1 2 3
4 5 6
7 8 9
1146

Код

А694а

Ссылка на оригинальную статью

Ссылка на Try Haxe!

Задача
Получить квадратную матрицу порядка [latex]n[/latex] [latex]\begin{pmatrix}1 &0 &\cdots & 0 \\ 0 & 1 &\cdots &0 \\ \cdots &\cdots &\cdots \cdots & \cdots \\ 0 & 0 & \cdots & 1\end{pmatrix}[/latex]

Тесты

n Матрица
2 [latex]\begin{pmatrix}1 & 0 \\ 0 & 1 \end{pmatrix}[/latex]
4 [latex]\begin{pmatrix}1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}[/latex]

Код

Решение
Из входного потока считываем $n$ — размер матрицы. Создаем матрицу со значением ноль по умолчанию. Затем в цикле заполняем главную диагональ единицами.

A694a

Ссылка на оригинальную статью.

Ссылка на решение задачи на сайте Try Haxe!

Условие:

Получить квадратную матрицу порядка [latex]n[/latex] [latex]\begin{pmatrix}1 &0 &\cdots & 0 \\ 0 & 1 &\cdots &0 \\ \cdots &\cdots &\cdots \cdots & \cdots \\ 0 & 0 & \cdots & 1\end{pmatrix}[/latex]

Тесты

n Матрица
3 1 0 0

0 1 0

0 0 1

4 1 0 0 0

0 1 0 0

0 0 1 0

0 0 0 1

6 1 0 0 0 0 0

0 1 0 0 0 0

0 0 1 0 0 0

0 0 0 1 0 0

0 0 0 0 1 0

0 0 0 0 0 1

Решение:

Сначала создаётся переменная [latex] h[/latex], которая задаёт размерность двумерного массива(матрицы), после чего создаётся собственно массив(матрица) указанной размерности, изначально заполненный нулями. С помощью цикла главная диагональ заполняется единицами. Далее циклом выводим массив.

Код программы:

 

Алгоритм шифрования MARS

MARS — шифр-кандидат в AES был разработан коллективом криптологов из корпорации IBM. Именно IBM в свое время разработала семейство алгоритмов Lucifer, которое легло в основу прошлого стандарта шифрования США — DES.

Cтруктура алгоритма:

  1. Предварительное наложение ключа: на [latex]32[/latex]-битные субблоки [latex]A, B, C, D[/latex] накладываются [latex]4[/latex] фрагмента расширенного ключа [latex]k_{0}…k_{3}[/latex] операцией сложения по модулю [latex]2^{32}[/latex];
  2. Выполняются [latex]8[/latex] раундов прямого перемешивания (без участия ключа шифрования);
  3. Выполняются [latex]8[/latex] раундов прямого криптопреобразования;
  4. Выполняются [latex]8[/latex] раундов обратного криптопреобразования;
  5. Выполняются [latex]8[/latex] раундов обратного перемешивания, также без участия ключа шифрования;
  6. Финальное наложение фрагментов расширенного ключа [latex]k_{36}…k_{39}[/latex] операцией вычитания по модулю [latex]2^{32}[/latex].

Алгоритм уникален тем, что использовал практически все существующие технологии, применяемые в криптоалгоритмах, а именно:

  • простейшие операции сложение, вычитание, исключающее или
  • подстановки с использованием таблицы замен
  • фиксированный циклический сдвиг
  • зависимый от данных циклический сдвиг
  • умножение по модулю [latex]2^{32}[/latex]
  • ключевое забеливание
Следовательно, для реализации алгоритма было бы удобно завести некоторую «обертку» над [latex]32[/latex] битным интом (поскольку мы оперируем [latex]32[/latex]-битными субблоками).

Нам понадобится реализовать:

  • циклический сдвиг влево/вправо на [latex]n[/latex]-ое кол-во бит
  • выделение [latex]n[/latex]-ого байта из субблока
  • выделение последних [latex]n[/latex] бит из субблока

Реализуем новый абстрактный тип Integer (прежде стоит ознакомиться с логическими операциями):

Добавим методы циклического сдвига:

Для наглядности подробно разберем принцип работы одного из методов, основанных на битовых операциях, для краткости возьмем не [latex]32[/latex]-битное число, а [latex]8[/latex]-битное. Пусть нам нужен циклический сдвиг влево на [latex]4[/latex] бита.
Из этого следует что, нам нужно сдвинуть входное число на [latex]4[/latex] бита влево, предварительно сохранив [latex]4[/latex] старших бита, чтобы не потерять их. Для этого воспользуемся операцией сдвига вправо на [latex]n — 4[/latex] бита с заполнением нулями, где [latex]n[/latex] — максимальное кол-во бит в числе. Сохраним результат  в переменную  ones  .
Далее сдвинем исходное слово на [latex]4[/latex] бита влево и операцией «побитовое или» соединим с   ones.
Аналогично реализуем метод циклического сдвига вправо:

Так же нам потребуется реализовать метод выделения [latex]n[/latex]-ого байта из субблока. Для этого мы будем сдвигать требуемый байт на место младшего байта и выделим его с помощью операции «логическое и» маской [latex]255[/latex] (в битовом представлении подряд идущих [latex]8[/latex] единиц, начиная с младшего бита) .

Осталось реализовать метод выделения последних [latex]n[/latex] бит из субблока. Для этого мы сначала сдвинем число влево на ([latex]32 — n[/latex]), чтобы на место старших бит встали искомые биты (таким образом стерев ненужные биты). А затем сдвинем их на место младших битов (то есть вправо с заполнением нулями на [latex]32 — n[/latex]).

Для работы алгоритма потребуется объявить некоторые элементы ([latex]S[/latex] и [latex]B[/latex] блоки) — они описаны в конце статьи.

Прямое перемешивание:

Раунд прямого перемешивания показан на рисунке [latex]1[/latex], в раунде выполняются следующие действия:

  1. Значение субблока [latex]A[/latex] прогоняется через таблицу замен [latex]S0[/latex] и накладывается на субблок [latex]B[/latex] операцией [latex]XOR[/latex].
  2. Исходное значение субблока [latex]A[/latex] вращается на [latex]8[/latex] бит вправо.
  3. Результат предыдущего шага обрабатывается таблицей замен [latex]S1[/latex] и снова накладывается на субблок [latex]B[/latex] операцией сложения по модулю [latex]32[/latex].
  4. Результат шага [latex]2[/latex] вращается на [latex]8[/latex] бит вправо.
  5. Результат предыдущего шага обрабатывается таблицей замен [latex]S0[/latex] и накладывается на субблок [latex]С[/latex] операцией сложения по модулю [latex]32[/latex].
  6. Результат шага [latex]4[/latex] вращается на [latex]8[/latex] бит вправо.
  7. Результат предыдущего шага обрабатывается таблицей замен [latex]S1[/latex] и накладывается на субблок [latex]D[/latex] операцией [latex]XOR[/latex].
  8. Субблоки меняются местами, как показано на рис. [latex]1[/latex].

Кроме того, в некоторых раундах прямого перемешивания выполняются следующие дополнительные операции (не приведены на рис. [latex]1[/latex]):
В раундах [latex]0[/latex] и [latex]4[/latex] после шага [latex]7[/latex] выполняется наложение значения субблока [latex]D[/latex] на субблок [latex]A[/latex] операцией сложения по модулю .
В раундах [latex]1[/latex] и [latex]5[/latex] субблок [latex]B[/latex] аналогичным образом накладывается на субблок [latex]A[/latex].


рис. 1.

Стоит заметить, что каждый раз, «прогоняя» [latex]i[/latex]-ий субблок через [latex]S[/latex] блоки мы берем последние [latex]8[/latex] бит, то есть байт субблока и его значение используем в качестве индексного обращения к блоку [latex]S[/latex]. (Понятно, что в блоках [latex]256[/latex]  элементов. О правилах их получения  рассказывается ниже).

Для простоты, мы будем возвращать для «прогона» каждый раз не последний байт, а младший, первый, второй и старший. Потом мы подвинем субблок вправо сразу на [latex]24[/latex] бита.

Заведем класс subblock, который будет содержать четыре [latex]32[/latex]-битные посылки и расширенный ключ (о его получении мы поговорим ниже).

Теперь добавим в него метод прямого перемешивания:

Процесс кодирования алгоритма Mars обратен процессу декодирования. По этому сразу добавим обратный метод. Назовем его backward pass, чтобы не менять порядок следования функции в методе дешифрования, и добавим, в начало названия префикс [latex]d[/latex], чтобы обозначить его принадлежность к методам декодирования. Стоит отметить, что перед этим стоит ознакомиться с понятием обратных операций.

Криптографическое преобразование:

Криптографическое ядро MARS — сеть Фейстеля 3-го типа, содержащая в себе [latex]16[/latex] раундов. [latex]8[/latex] раундов прямого (рис. 2) и [latex]8[/latex] раундов обратного криптопреобразования (рис. 3). В каждом раунде мы используем ключевую [latex]Е[/latex]-функцию, которая является комбинацией умножений, вращений, а также обращений к [latex]S[/latex]-блокам. Функция принимает на вход одно слово данных, а возвращает три слова, с которыми впоследствии будет осуществлена операция сложения или [latex]XOR[/latex] к другим трем словам данным. В дополнении исходное слово вращается на [latex]13[/latex] бит влево.

рис.2.

Для обеспечения, серьёзного сопротивления к криптоатакам, три выходных значения [latex]Е[/latex]-функции ([latex]O_{1}[/latex], [latex]O_{2}[/latex], [latex]O_{3}[/latex]) используются в первых восьми раундах и в последних восьми раундах в разных порядках. В первые восемь раундов мы добавляем [latex]O_{1}[/latex] и [latex]O_{2}[/latex] к первому и второму целевому слову, соответственно, и [latex]XOR[/latex] [latex]O_{3}[/latex] к третьему целевому слову. За последние восемь раундов, мы добавляем [latex]O_{1}[/latex] и [latex]O_{2}[/latex] к третьему и второму целевому слову, соответственно, и [latex]XOR[/latex] [latex]O_{3}[/latex] к первому целевому слову.

рис.3.

Для декодирования:

 

[latex]E[/latex]-функция

[latex]E[/latex]-функция принимает в качестве входных данных одно слово данных и использует ещё два слова расширенного ключа с индексами [latex]2*i + 4[/latex] и [latex]2*i + 5[/latex] , производя на выходе три слова. В этой функции мы используем три временные переменные, обозначаемые [latex]L[/latex], [latex]M[/latex] и [latex]R[/latex] (для левой, средней и правой).

<p\>Изначально мы устанавливаем в [latex]R[/latex] значение исходного слова смещенного на [latex]13[/latex] бит влево, а в [latex]M[/latex] — сумма исходных слов и первого ключевого слова. Затем мы используем первые девять битов [latex]M[/latex] как индекс к одной из [latex]512[/latex] [latex]S[/latex]-блоков (которое получается совмещением [latex]S0[/latex] и [latex]S1[/latex] смешиванием фазы), и сохраняем в [latex]L[/latex] значение соответствующего [latex]S[/latex]-блока.

Затем умножим второе ключевое слово на [latex]R[/latex], сохранив значение в [latex]R[/latex]. Затем вращаем [latex]R[/latex] на [latex]5[/latex] позиций влево (так, [latex]5[/latex] старших битов становятся [latex]5[/latex] нижними битами [latex]R[/latex] после вращения). Тогда мы делаем [latex]XOR[/latex] [latex]R[/latex] в [latex]L[/latex], а также просматриваем пять нижних бит [latex]R[/latex] для определения величины сдвига (от [latex]0[/latex] до [latex]31[/latex]), и вращаем [latex]M[/latex] влево на эту величину. Далее мы вращаем [latex]R[/latex] ещё на [latex]5[/latex] позиций влево и делаем [latex]XOR[/latex] в [latex]L[/latex]. В заключении, мы вновь смотрим на [latex]5[/latex] младших битов [latex]R[/latex], как на величину вращения и вращаем [latex]L[/latex] на эту величину влево. Таким образом результат работы [latex]E[/latex]-функции — [latex]3[/latex] слова (по порядку): [latex]L, M, R[/latex].

 

Обратное перемешивание:

Раунд обратного перемешивания (см. рис. 4) более существенно отличается от прямого. Фактически, обратное перемешивание выполняет обратные операции в обратной последовательности (см. рис. 1 и 4):

  1. Значение субблока [latex]A[/latex] прогоняется через таблицу замен [latex]S1[/latex] и накладывается на субблок [latex]B[/latex] операцией XOR.
  2. Исходное значение субблока [latex]A[/latex] вращается на [latex]8[/latex] бит влево.
  3. Результат предыдущего шага обрабатывается таблицей замен [latex]S0[/latex] и накладывается на субблок [latex]C[/latex] операцией вычитания по модулю [latex]2^{32}[/latex]/>.
  4. Результат шага [latex]2[/latex] вращается на [latex]8[/latex] бит влево.
  5. Результат предыдущего шага обрабатывается таблицей замен [latex]S1[/latex] и накладывается на субблок [latex]D[/latex] операцией вычитания по модулю [latex]2^{32}[/latex] />.
  6. Результат шага [latex]4[/latex] вращается на [latex]8[/latex] бит влево.
  7. Результат предыдущего шага обрабатывается таблицей замен [latex]S0[/latex] и накладывается на субблок [latex]D[/latex] операцией [latex]XOR[/latex].
  8. Субблоки меняются местами, как показано на рис. 4.

Аналогично прямому перемешиванию, в некоторых раундах выполняются следующие дополнительные операции, не показанные на рис. 4:
— В раундах [latex]1[/latex] и [latex]5[/latex] после шага [latex]7[/latex] выполняется наложение значения субблока [latex]A[/latex] на субблок [latex]B[/latex] операцией вычитания по модулю [latex]2^{32}[/latex].

— В раундах [latex]2[/latex] и [latex]6[/latex] субблок [latex]C[/latex] аналогичным образом накладывается на субблок [latex]B[/latex].

и для декодирования:

Финальная реализиция класса Block:

Добавив методы для сложения посылок с подключами мы получаем финальную реализацию класса Block.

 

Свойства [latex]S[/latex]-блоков:

Стоит отметить, что [latex]S[/latex]-блок — это конкатенация блоков [latex]S0[/latex] и [latex]S1[/latex].

  1. [latex]S[/latex]-блок не должен содержать слова, состоящие все [latex]0[/latex] или [latex]1[/latex]
  2. Каждые два [latex]S[/latex]-блока [latex]S0[/latex], [latex]S1[/latex] должны отличаться друг от друга как минимум в [latex]3[/latex] из [latex]4[/latex] байтах.(так как выполнение этого условия для псевдослучайных [latex]S[/latex]-блоков крайне маловероятно, то один из двух [latex]S[/latex]-блоков модифицируется)
  3. S-блок не содержит двух элементов [latex]S[i],S[j](i\neq j)[/latex] таких, что [latex] S\left[i\right]=S\left[j\right][/latex]; [latex]S\left[i\right]=-S\left[j\right][/latex] или [latex] S\left[i\right]=-S\left[j\right][/latex]
  4. В [latex]S[/latex]-блоке не существует двух пар элементов [latex]XOR[/latex]-отличия которых равны и двух пар элементов упорядоченная разность которых равна
  5. Каждые два элемента [latex]S[/latex]-блока должны отличаться хотя бы [latex]4[/latex] битами

В данном программе будем использовать блок, предложенный в реализации IBM для AES.

Расширение ключа:

Процедура расширения ключа расширяет заданный массив ключей [latex]T[][/latex], состоящий из [latex]n[/latex] [latex]32[/latex]-битных слов (где [latex]n[/latex] целое число от [latex]4[/latex] до [latex]14[/latex]) в массив [latex]K[][/latex] из [latex]40[/latex] элементов. Исходный ключ не должен придерживаться какой-либо структуры. В дополнение, процедура расширения ключа гарантирует следующие свойства ключевого слова, используемого при перемножении в криптографическом ядре алгоритма:

  • два младших бита ключевого слова будут всегда единицами
  • ни одно из ключевых слов не будет содержать десять подряд идущих [latex]0[/latex] или [latex]1[/latex]

Опишем алгоритм расширения ключа.

Сначала массив [latex]T[][/latex] дополняется до 15 элементов следующим образом: [latex]T[n]=n[/latex];[latex]T[n+1\ldots 14]=0[/latex]

 

Далее данный процесс повторяется [latex]4[/latex] раза:

    • На каждой итерации генерируются [latex]10[/latex] слов расширенного ключа. [latex]j[/latex] переменная отображающая текущий номер итерации.(для первой итерации [latex]0[/latex], для второй [latex]1[/latex] и т. д.)
      Массив [latex]T[][/latex] преобразуется по следующему правилу: [latex]i=0\ldots 14,T[i]=T[i]\oplus ((T[i-7\mod 15]\oplus T[i-2\mod 15])\lll 3)\oplus (4i+j)[/latex]

 

    • Далее мы перемешиваем массив [latex]T[][/latex] при помощи [latex]4[/latex] раундов Сети Фейстеля 1-го типа. Повторяем четыре раза следующую операцию: [latex]T[i]=(T[i]+S[low~9~bits~of~T[i-1\mod 15]])\lll 9;i=0,1\ldots 14[/latex]

 

  • Далее берем десять слов из массива [latex]T[][/latex] и вставляем их в качестве следующих десяти слов в массив [latex]K[][/latex] ещё раз перемешав: [latex]K[10j+i]=T[4i\mod 15];i=0,1\ldots 9[/latex]

Окончательно, мы пробегаемся по шестнадцати словам, используемыми для перемножения[latex](K[5],K[7]…K[35])[/latex] и модифицируем их для того, чтобы они соответствовали двум свойствам, описанным выше.
Записываем два младших бита [latex]K[i][/latex], по формуле [latex] j=K[i]\land 3[/latex] , а затем записываем вместо этих двух бит единицы, [latex] w=K[i]\lor 3[/latex] .
Собираем маску [latex]M[/latex] для битов [latex]w[/latex], которые принадлежат последовательностям из десяти и более нулей или единиц. К примеру, [latex] M_{l}=1[/latex] , тогда и только тогда, когда [latex]w_{l}[/latex] принадлежит последовательности из [latex]10[/latex] или более одинаковых элементов. Тогда мы сбрасываем (выставляем их в [latex]0[/latex]) значения тех единиц [latex]M[/latex], которые находятся на границах нулевых или единичных последовательностей, а также тех единиц, которые находятся в старшем и младшем битах. К примеру, пусть наше слово выглядит так: [latex] w=0^{3}1^{13}0^{12}1011[/latex] (выражение [latex]0^{i}[/latex] или же [latex] 1^{i}[/latex] обозначает, что [latex]0[/latex] или [latex]1[/latex] будут повторены в слове [latex]i[/latex] раз). Тогда маска [latex]M[/latex] будет выглядеть следующим образом: [latex] 0^{3}1^{25}0^{4}[/latex] . А значит мы сбрасываем биты в [latex]4, 15, 16, 28[/latex] позициях, то есть [latex]M=0^{4}1^{11}001^{10}0^{5}[/latex]
Далее, для исправления, мы используем таблицу из четырёх слов [latex]B[][/latex]. Все элементы таблицы [latex]B[/latex] подобраны так, что для них и для всех их цикличных сдвигов выполняется свойство, что в них нет семи подряд идущих [latex]0[/latex] или [latex]1[/latex]. В реализации IBM использовалась таблица [latex]B[]=\left\{0xa4a8d57b,0x5b5d193b,0xc8a8309b,0x73f9a978\right\}[/latex] . Далее используются два записанных бита [latex]j[/latex] для выбора слова из таблицы [latex]B[/latex], и используются младшие пять бит слова [latex]K[i-1][/latex] для вращения его элементов, [latex]p=B[j]\lll (lowest~5~bits~of~K[i-1])[/latex].
Окончательно, делается [latex]XOR[/latex] шаблона [latex]p[/latex] на исходное слово, при учете маски [latex]М[/latex]: [latex]K[i] = w\oplus (p\land M)[/latex] .

Сначала выделяем маской последовательность из [latex]10[/latex] нулей или единиц, и потом выставляем в маске [latex]1[/latex]-цы пока последовательность не прерывается.

Реализация класса Key:

Теперь, мы реализовали все необходимое, чтобы написать алгоритм кодирования и декодирования:

Осталась последняя проблема, наш алгоритм кодирует только массивы из целочисленных [latex]32[/latex] битных элементов, а хотелось бы сообщения. Исправить эту ситуацию помогут следующие функции:

[latex]S0[/latex], [latex]S1[/latex], [latex]B[/latex] блоки я хранила в классе   MarsInfo, где все поля были статическими:

 

try MARS online