HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>11 май 2022</li>
2 <ul><li>11 май 2022</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><h2>Майк Паунд: что такое регистры сдвига с обратной связью и для чего они нужны</h2>
4 </ul><h2>Майк Паунд: что такое регистры сдвига с обратной связью и для чего они нужны</h2>
5 <p>Доктор Майк Паунд рассказывает, как с помощью регистров LFSR генерируют псевдослучайные числа и как их используют для защиты информации.</p>
5 <p>Доктор Майк Паунд рассказывает, как с помощью регистров LFSR генерируют псевдослучайные числа и как их используют для защиты информации.</p>
6 <p>Фото: Университет Ноттингема</p>
6 <p>Фото: Университет Ноттингема</p>
7 <p>Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.</p>
7 <p>Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.</p>
8 <p>Научный сотрудник Ноттингемского университета. Известен своими работами в области анализа биоизображений, компьютерного зрения, распознавания изображений и компьютерной безопасности.</p>
8 <p>Научный сотрудник Ноттингемского университета. Известен своими работами в области анализа биоизображений, компьютерного зрения, распознавания изображений и компьютерной безопасности.</p>
9 <p>Регистры сдвига с линейной обратной связью, или LFSR (linear feedback shift register), широко применяются в криптографии, в статистике и имитационном моделировании.</p>
9 <p>Регистры сдвига с линейной обратной связью, или LFSR (linear feedback shift register), широко применяются в криптографии, в статистике и имитационном моделировании.</p>
10 <p>Что мне в них действительно нравится - они невероятно просты по структуре и в то же время могут выдавать невероятно сложные результаты. Кроме того, их легко кодировать.</p>
10 <p>Что мне в них действительно нравится - они невероятно просты по структуре и в то же время могут выдавать невероятно сложные результаты. Кроме того, их легко кодировать.</p>
11 <p>Чтобы понять, о чём речь, вспомним, что регистр - это набор связанных между собой битов, который может хранить, записывать, считывать двоичные данные. А в регистрах сдвига с линейной обратной связью (LFSR) дополнительно установлены некоторые правила того, как перемещать и рассчитывать значения этих битов.</p>
11 <p>Чтобы понять, о чём речь, вспомним, что регистр - это набор связанных между собой битов, который может хранить, записывать, считывать двоичные данные. А в регистрах сдвига с линейной обратной связью (LFSR) дополнительно установлены некоторые правила того, как перемещать и рассчитывать значения этих битов.</p>
12 <p>Это пересказ<a>лекции</a>Майкла с канала Computerphile.</p>
12 <p>Это пересказ<a>лекции</a>Майкла с канала Computerphile.</p>
13 <p>Регистры LFSR используются для генерации псевдослучайных чисел, отличающихся от случайных тем, что каждое последующее число рассчитывается по определённой формуле в зависимости от предыдущих чисел.</p>
13 <p>Регистры LFSR используются для генерации псевдослучайных чисел, отличающихся от случайных тем, что каждое последующее число рассчитывается по определённой формуле в зависимости от предыдущих чисел.</p>
14 <p>Последовательность псевдослучайных чисел полностью определяется формулой и первоначально заданным числом. В какой-то момент она зацикливается - например, сначала в ней будет 4095 разных чисел, а с 4096-го числа она начнёт повторяться. Во многих приложениях такой последовательности вполне достаточно.</p>
14 <p>Последовательность псевдослучайных чисел полностью определяется формулой и первоначально заданным числом. В какой-то момент она зацикливается - например, сначала в ней будет 4095 разных чисел, а с 4096-го числа она начнёт повторяться. Во многих приложениях такой последовательности вполне достаточно.</p>
15 <p>Регистры LFSR работают так:</p>
15 <p>Регистры LFSR работают так:</p>
16 <ul><li>Содержимое регистра сдвигается на один бит вправо.</li>
16 <ul><li>Содержимое регистра сдвигается на один бит вправо.</li>
17 <li>Значение освободившегося бита рассчитывается с помощью линейной булевой функции, в качестве аргументов которой можно использовать все или некоторые значения битов регистра. Очень часто в LFSR используется операция xor - исключающее "или", сложение по модулю 2, - которая обозначается знаком ⊕.</li>
17 <li>Значение освободившегося бита рассчитывается с помощью линейной булевой функции, в качестве аргументов которой можно использовать все или некоторые значения битов регистра. Очень часто в LFSR используется операция xor - исключающее "или", сложение по модулю 2, - которая обозначается знаком ⊕.</li>
18 </ul><p>Рассмотрим работу генератора на примере регистра длиной 4 бита. Назовём биты b0, b1, b2, b3. Каждый из битов может принимать значение 0 или 1.</p>
18 </ul><p>Рассмотрим работу генератора на примере регистра длиной 4 бита. Назовём биты b0, b1, b2, b3. Каждый из битов может принимать значение 0 или 1.</p>
19 <p>Зададим начальное значение случайным образом, например:</p>
19 <p>Зададим начальное значение случайным образом, например:</p>
20 <p>Это будет первое состояние регистра.</p>
20 <p>Это будет первое состояние регистра.</p>
21 <p>Сдвинем содержимое регистра вправо на один бит. Получим:</p>
21 <p>Сдвинем содержимое регистра вправо на один бит. Получим:</p>
22 <p>Единица из бита b3 потерялась, а b0 освободился.</p>
22 <p>Единица из бита b3 потерялась, а b0 освободился.</p>
23 <p>Так как это линейный регистр с обратной связью, нам нужно определить функцию, которая будет вычислять значение освободившегося бита. Пусть в нашем регистре используется функция b2 ⊕ b3. Биты b2 и b3 в LFSR называются отводами.</p>
23 <p>Так как это линейный регистр с обратной связью, нам нужно определить функцию, которая будет вычислять значение освободившегося бита. Пусть в нашем регистре используется функция b2 ⊕ b3. Биты b2 и b3 в LFSR называются отводами.</p>
24 <p>Функция вычисляется так:</p>
24 <p>Функция вычисляется так:</p>
25 <p>Как видим, результат выполнения битовой операции xor в случае двух переменных равен 1, когда одна из переменных равна 1, а другая - 0. Если обе переменные имеют одинаковое значение, результат равен 0.</p>
25 <p>Как видим, результат выполнения битовой операции xor в случае двух переменных равен 1, когда одна из переменных равна 1, а другая - 0. Если обе переменные имеют одинаковое значение, результат равен 0.</p>
26 <p>Новое значение бита b0 рассчитывается до сдвига и записывается в ячейку только после сдвига. Освободившийся бит будет рассчитываться так: 0 ⊕ 1 = 1 (значения b2 и b3 из первого состояния регистра).</p>
26 <p>Новое значение бита b0 рассчитывается до сдвига и записывается в ячейку только после сдвига. Освободившийся бит будет рассчитываться так: 0 ⊕ 1 = 1 (значения b2 и b3 из первого состояния регистра).</p>
27 <em>Скриншот: Skillbox Media</em><p>Второе состояние нашего регистра будет таким:</p>
27 <em>Скриншот: Skillbox Media</em><p>Второе состояние нашего регистра будет таким:</p>
28 <p>Аналогично, чтобы получить третье состояние, сдвигаем биты влево:</p>
28 <p>Аналогично, чтобы получить третье состояние, сдвигаем биты влево:</p>
29 <em>Скриншот: Skillbox Media</em><p>И получаем:</p>
29 <em>Скриншот: Skillbox Media</em><p>И получаем:</p>
30 <em>Скриншот: Skillbox Media</em><p>Таких состояний довольно много. И вот что мы получим в результате:</p>
30 <em>Скриншот: Skillbox Media</em><p>Таких состояний довольно много. И вот что мы получим в результате:</p>
31 <em>Скриншот: Skillbox Media</em><p>В конце концов мы вернулись к первоначальному состоянию регистра - 1001.</p>
31 <em>Скриншот: Skillbox Media</em><p>В конце концов мы вернулись к первоначальному состоянию регистра - 1001.</p>
32 <p>А теперь справа подпишем значения, которые были выведены из регистра.</p>
32 <p>А теперь справа подпишем значения, которые были выведены из регистра.</p>
33 <em>Скриншот: Skillbox Media</em><p>Фактически это результат работы нашего генератора.</p>
33 <em>Скриншот: Skillbox Media</em><p>Фактически это результат работы нашего генератора.</p>
34 <p>Можно заметить, что было состояние, в котором регистр состоял из одних единиц, но не было полностью нулевого состояния (0000). Дело в том, что в этом случае при любом количестве сдвигов мы бы не получили ничего интересного:</p>
34 <p>Можно заметить, что было состояние, в котором регистр состоял из одних единиц, но не было полностью нулевого состояния (0000). Дело в том, что в этом случае при любом количестве сдвигов мы бы не получили ничего интересного:</p>
35 <p>Нули так и остались бы нулями. Поэтому сдвиговому регистру всегда нужно присваивать ненулевое начальное значение.</p>
35 <p>Нули так и остались бы нулями. Поэтому сдвиговому регистру всегда нужно присваивать ненулевое начальное значение.</p>
36 <p>У нас получилось 15 состояний - максимальный период для нашего сдвигового регистра. Генератор выдал все возможные комбинации нулей и единиц.</p>
36 <p>У нас получилось 15 состояний - максимальный период для нашего сдвигового регистра. Генератор выдал все возможные комбинации нулей и единиц.</p>
37 <p>В общем случае для регистра из n бит максимальный период составляет 2n - 1.</p>
37 <p>В общем случае для регистра из n бит максимальный период составляет 2n - 1.</p>
38 <p>Теперь рассмотрим другой пример. Пусть функция, вычисляющая освободившийся бит, выглядит так:</p>
38 <p>Теперь рассмотрим другой пример. Пусть функция, вычисляющая освободившийся бит, выглядит так:</p>
39 <p>А вычисляется таким образом:</p>
39 <p>А вычисляется таким образом:</p>
40 b0b2b3b0 ⊕ b2 ⊕ b300000011010101101001101011001111<p>Как мы видим, функция равна единице там, где единице равно нечётное число аргументов, и нулю - в противном случае. На мой взгляд, здесь происходит гораздо больше интересного. Возьмём то же самое первоначальное заполнение регистра.</p>
40 b0b2b3b0 ⊕ b2 ⊕ b300000011010101101001101011001111<p>Как мы видим, функция равна единице там, где единице равно нечётное число аргументов, и нулю - в противном случае. На мой взгляд, здесь происходит гораздо больше интересного. Возьмём то же самое первоначальное заполнение регистра.</p>
41 <p>Состояние 1:</p>
41 <p>Состояние 1:</p>
42 <p>Сдвинем биты вправо и подставим в освободившуюся ячейку вычисленное значение, равное 0.</p>
42 <p>Сдвинем биты вправо и подставим в освободившуюся ячейку вычисленное значение, равное 0.</p>
43 <p>Состояние 2:</p>
43 <p>Состояние 2:</p>
44 <p>Состояние 3:</p>
44 <p>Состояние 3:</p>
45 <p>Состояние 4:</p>
45 <p>Состояние 4:</p>
46 <p>Цикл закончился, регистр вернулся к первоначальному состоянию. Это означает: если у вас есть какое-то состояние и правило перевода, то вы всегда сможете перейти в то же состояние, которое было у вас раньше.</p>
46 <p>Цикл закончился, регистр вернулся к первоначальному состоянию. Это означает: если у вас есть какое-то состояние и правило перевода, то вы всегда сможете перейти в то же состояние, которое было у вас раньше.</p>
47 <p>Есть математические способы выбора отводов таким образом, чтобы они могли давать максимальный период для регистра определённой длины. Но здесь мы их рассматривать не будем.</p>
47 <p>Есть математические способы выбора отводов таким образом, чтобы они могли давать максимальный период для регистра определённой длины. Но здесь мы их рассматривать не будем.</p>
48 <p>Самое классное в таких генераторах - их очень легко программировать. Правда, программы получаются не слишком эффективными, так как много времени тратится на циклы и перестановки, выполняется множество операций xor.</p>
48 <p>Самое классное в таких генераторах - их очень легко программировать. Правда, программы получаются не слишком эффективными, так как много времени тратится на циклы и перестановки, выполняется множество операций xor.</p>
49 <p>Программы работают медленно, поэтому регистры LFSR часто выполняют в виде электрической схемы, состоящей из дискретных элементов - триггеров, или интегрируют в микросхему.</p>
49 <p>Программы работают медленно, поэтому регистры LFSR часто выполняют в виде электрической схемы, состоящей из дискретных элементов - триггеров, или интегрируют в микросхему.</p>
50 <p>Для примера напишем программу для нашего 4-битного генератора. Сделаем это на Python - в нём много битовых функций, и он позволяет работать с целыми числами произвольной длины.</p>
50 <p>Для примера напишем программу для нашего 4-битного генератора. Сделаем это на Python - в нём много битовых функций, и он позволяет работать с целыми числами произвольной длины.</p>
51 <p>Возьмём условия из первого примера:</p>
51 <p>Возьмём условия из первого примера:</p>
52 <ul><li>первоначальное значение регистра - 1001;</li>
52 <ul><li>первоначальное значение регистра - 1001;</li>
53 <li>функция, вычисляющая освободившийся бит, - b2 ⊕ b3.</li>
53 <li>функция, вычисляющая освободившийся бит, - b2 ⊕ b3.</li>
54 </ul><p>Значение освободившейся ячейки будем рассчитывать следующим образом:</p>
54 </ul><p>Значение освободившейся ячейки будем рассчитывать следующим образом:</p>
55 <p>Найдём результат операции xor над текущим состоянием регистра и состоянием, когда он сдвинут на одну позицию вправо:</p>
55 <p>Найдём результат операции xor над текущим состоянием регистра и состоянием, когда он сдвинут на одну позицию вправо:</p>
56 <em>Скриншот: Skillbox Media</em><p>Нам нужен последний бит результата - это и будет b2 ⊕ b3:</p>
56 <em>Скриншот: Skillbox Media</em><p>Нам нужен последний бит результата - это и будет b2 ⊕ b3:</p>
57 <em>Скриншот: Skillbox Media</em><p>Наша программа будет выглядеть так:</p>
57 <em>Скриншот: Skillbox Media</em><p>Наша программа будет выглядеть так:</p>
58 state = 0b1001 # задаём первоначальное значение регистра for i in range(20): # для примера рассчитаем 20 состояний регистра print("{:04b}".format(state)) # вывод состояния на печать newbit = (state ^ (state &gt;&gt; 1)) &amp; 1 # рассчитываем новое значение освободившегося бита state = (state &gt;&gt; 1) | (newbit &lt;&lt; 3) # новое состояние регистра: сдвигаем содержимое вправо и вставляем в первую позицию слева новый бит<p>Запустим программу и рассмотрим результат:</p>
58 state = 0b1001 # задаём первоначальное значение регистра for i in range(20): # для примера рассчитаем 20 состояний регистра print("{:04b}".format(state)) # вывод состояния на печать newbit = (state ^ (state &gt;&gt; 1)) &amp; 1 # рассчитываем новое значение освободившегося бита state = (state &gt;&gt; 1) | (newbit &lt;&lt; 3) # новое состояние регистра: сдвигаем содержимое вправо и вставляем в первую позицию слева новый бит<p>Запустим программу и рассмотрим результат:</p>
59 <em>Скриншот: Skillbox Media</em><p>Мы видим, что с 16-й позиции генерация значений зациклилась.</p>
59 <em>Скриншот: Skillbox Media</em><p>Мы видим, что с 16-й позиции генерация значений зациклилась.</p>
60 <p>Если вы используете LFSR в качестве генератора случайных чисел, то не обязательно распечатывать каждое состояние полностью, так как между итерациями оно не сильно меняется: содержимое регистра сдвигается вправо, меняется только левый бит. Каждый раз оно будет выглядеть очень похоже.</p>
60 <p>Если вы используете LFSR в качестве генератора случайных чисел, то не обязательно распечатывать каждое состояние полностью, так как между итерациями оно не сильно меняется: содержимое регистра сдвигается вправо, меняется только левый бит. Каждый раз оно будет выглядеть очень похоже.</p>
61 <p>Вместо того чтобы выводить всё состояние целиком, выведем на печать только последний бит. Программа будет выглядеть так:</p>
61 <p>Вместо того чтобы выводить всё состояние целиком, выведем на печать только последний бит. Программа будет выглядеть так:</p>
62 state = 0b1001 for i in range(20): print(state &amp;1, end = '') newbit = (state ^ (state &gt;&gt; 1)) &amp; 1 state = (state &gt;&gt; 1) | (newbit &lt;&lt; 3)<p>В результате получим псевдослучайную битовую последовательность:</p>
62 state = 0b1001 for i in range(20): print(state &amp;1, end = '') newbit = (state ^ (state &gt;&gt; 1)) &amp; 1 state = (state &gt;&gt; 1) | (newbit &lt;&lt; 3)<p>В результате получим псевдослучайную битовую последовательность:</p>
63 <p>Созданный нами 4-битный сдвиговый регистр можно использовать в качестве небольшого генератора случайных чисел, но для создания потокового шифра он не годится - слишком мал.</p>
63 <p>Созданный нами 4-битный сдвиговый регистр можно использовать в качестве небольшого генератора случайных чисел, но для создания потокового шифра он не годится - слишком мал.</p>
64 <p>Рассмотрим ещё один пример - создадим регистр, подходящий для потокового шифра. Увеличим число разрядов регистра до 128, а в качестве начального значения зададим 128-значное число, у которого левый и правый биты равны единице, остальные - нулю.</p>
64 <p>Рассмотрим ещё один пример - создадим регистр, подходящий для потокового шифра. Увеличим число разрядов регистра до 128, а в качестве начального значения зададим 128-значное число, у которого левый и правый биты равны единице, остальные - нулю.</p>
65 <p>Сделаем бесконечным количество итераций и будем останавливать программу, когда захотим. Максимальный период 2128 - 1 для нашего сдвигового регистра даст операция xor над битами номер 0, 1, 2, 7 справа.</p>
65 <p>Сделаем бесконечным количество итераций и будем останавливать программу, когда захотим. Максимальный период 2128 - 1 для нашего сдвигового регистра даст операция xor над битами номер 0, 1, 2, 7 справа.</p>
66 <p>Исправим нашу программу:</p>
66 <p>Исправим нашу программу:</p>
67 state = (1 &lt;&lt; 127) | 1 while True: print(state &amp;1, end = '') newbit = (state ^ (state &gt;&gt; 1) ^ (state &gt;&gt; 2) ^ (state &gt;&gt; 7)) &amp; 1 state = (state &gt;&gt; 1) | (newbit &lt;&lt; 127)<p>Запустим программу и получим такой результат:</p>
67 state = (1 &lt;&lt; 127) | 1 while True: print(state &amp;1, end = '') newbit = (state ^ (state &gt;&gt; 1) ^ (state &gt;&gt; 2) ^ (state &gt;&gt; 7)) &amp; 1 state = (state &gt;&gt; 1) | (newbit &lt;&lt; 127)<p>Запустим программу и получим такой результат:</p>
68 <em>Скриншот: Skillbox Media</em><p>Вы спросите: когда цикл повторится? Мой компьютер выдаёт на экран около миллиона бит в секунду. Вероятно, нам придётся ждать повторения цикла в 1020 раз дольше, чем существует Вселенная.</p>
68 <em>Скриншот: Skillbox Media</em><p>Вы спросите: когда цикл повторится? Мой компьютер выдаёт на экран около миллиона бит в секунду. Вероятно, нам придётся ждать повторения цикла в 1020 раз дольше, чем существует Вселенная.</p>
69 <p>Такие системы используются для генераторов случайных чисел. Статистическая вероятность этих потоков очень хорошая - приблизительно как случайное подбрасывание монеты. Но криптографически они не слишком безопасны - если у вас есть большая часть потока, то вы можете решить множество линейных уравнений и найти числа, которые его сгенерировали, а затем сгенерировать следующий поток. То есть вы взломаете шифр.</p>
69 <p>Такие системы используются для генераторов случайных чисел. Статистическая вероятность этих потоков очень хорошая - приблизительно как случайное подбрасывание монеты. Но криптографически они не слишком безопасны - если у вас есть большая часть потока, то вы можете решить множество линейных уравнений и найти числа, которые его сгенерировали, а затем сгенерировать следующий поток. То есть вы взломаете шифр.</p>
70 <p>Существуют разные способы повышения криптоустойчивости генераторов - например, использование нескольких регистров LFSR. Числа, которые они выдают, становятся аргументами булевой функции, а результаты работы этой функции используются для шифрования. Также возможно использование нелинейной комбинации прямой и обратной связи в регистре - так работает шифр Trivium.</p>
70 <p>Существуют разные способы повышения криптоустойчивости генераторов - например, использование нескольких регистров LFSR. Числа, которые они выдают, становятся аргументами булевой функции, а результаты работы этой функции используются для шифрования. Также возможно использование нелинейной комбинации прямой и обратной связи в регистре - так работает шифр Trivium.</p>
71 <p>Регистры LFSR очень быстры в аппаратной реализации, поэтому их часто используют в маломощных устройствах, например в смарт-картах.</p>
71 <p>Регистры LFSR очень быстры в аппаратной реализации, поэтому их часто используют в маломощных устройствах, например в смарт-картах.</p>
72 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
72 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>