Регистр сдвига линейной обратной связи?

страница, гораздо лучше, чем (поначалу) загадочный Википедии. Поэтому я хотел написать небольшой код для программы, которая работала как LFSR. Чтобы быть более точным, что как-то показали, как работает регистр сдвига. Вот самая чистая вещь. Я могу придумать после некоторых lenghtier попытки (питон):

def lfsr(seed, taps):
    sr, xor = seed, 0
    while 1:
        for t in taps:
            xor += int(sr[t-1])
        if xor%2 == 0.0:
            xor = 0
        else:
            xor = 1
        print xor
        sr, xor = str(xor) + sr[:-1], 0
        print sr
        if sr == seed:
            break

lfsr('11001001', (8,7,6,1))      #example

Я назвал" xor " вывод функции XOR, не очень правильный. Однако это просто должно показать, как он обходит свои возможные состояния, на самом деле вы заметили, что регистр представлен строкой. Не очень-то логично.

Это можно легко превратить в хорошую игрушку, которую вы можете смотреть часами (по крайней мере, я мог: -)

def lfsr(seed, taps):
    import time
    sr, xor = seed, 0
    while 1:
        for t in taps:
            xor += int(sr[t-1])
        if xor%2 == 0.0:
            xor = 0
        else:
            xor = 1
        print xor
        print
        time.sleep(0.75)
        sr, xor = str(xor) + sr[:-1], 0
        print sr
        print
        time.sleep(0.75)

затем меня поразило, какая польза в этом написание программного обеспечения? Я слышал, что он может генерировать случайные числа; это правда? как? Поэтому, было бы неплохо, если бы кто-то мог:

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

кроме того, поскольку вокруг этой части логики и цифровых схем не так много дидактических вещей, было бы неплохо, если бы это могло быть место нубами (как я), чтобы получить лучшее понимание этого вещь, или лучше, чтобы понять, что это такое и как это может быть полезно при написании программного обеспечения. Должен был сделать это сообщество wiki?

это сказал, Если кто-то чувствует, как гольф... Добро пожаловать.

7 ответов


на самом деле алгоритмы, основанные на LFSR, очень распространены. CRC фактически напрямую основан на LFSR. Конечно, на занятиях по информатике люди говорят о многочленах, когда они говорят о том, как входное значение должно быть связано с накопленным значением, в электорнике вместо этого мы говорим о кранах. Это одна и та же терминология.

CRC32 является очень распространенным. Он используется для обнаружения ошибок в кадрах Ethernet. Это означает, что, когда я опубликовал это ответ Мой компьютер использовал алгоритм на основе LFSR для генерации хэша IP-пакета, чтобы мой маршрутизатор мог проверить, что то, что он передает, не повреждено.

Zip и gzip файлы являются еще одним примером. Оба используют CRC для обнаружения ошибок. Zip использует CRC32, а Gzip использует CRC16 и CRC32.

CRCs-это в основном хэш-функции. И этого достаточно, чтобы интернет заработал. Это означает, что LFSRs-довольно хорошие хэш-функции. Я не уверен, знаете ли вы это, но в целом хороший хэш функции считаются хорошими генераторами случайных чисел. Но дело с LFSR в том, что выбор правильных отводов (полиномов) очень важен для качества хэша/случайного числа.

ваш код, как правило, игрушечный код, так как он работает на строке единиц и нулей. В реальном мире LFSR работает на битах в байте. Каждый байт вы пропихиваете РСЛОС изменяет накопленное значение регистра. Это значение фактически является контрольной суммой всех байтов, которые вы протолкнули через реестр. Два распространенных способа использования этого значения в качестве случайного числа-либо использовать счетчик и протолкнуть последовательность чисел через регистр, тем самым преобразовав линейную последовательность 1,2,3,4 в некоторую хэшированную последовательность, такую как 15306,22,5587,994, либо вернуть текущее значение в регистр для генерации нового числа в кажущейся случайной последовательности.

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

но иногда может пригодиться простой бит-крутящийся LFSR. Я когда-то написал Modbus драйвер для PIC micro и этот протокол использовали CRC16. Предварительно вычисленная таблица требует 256 байт памяти, а мой процессор имел только 68 байт (я не шучу!--14-->). Поэтому мне пришлось использовать LFSR.


так как я искал реализацию LFSR в Python, я наткнулся на эту тему. Однако я обнаружил, что следующее Было немного более точным в соответствии с моими потребностями:

def lfsr(seed, mask):
    result = seed
    nbits = mask.bit_length()-1
    while True:
        result = (result << 1)
        xor = result >> nbits
        if xor != 0:
            result ^= mask

        yield xor, result

вышеуказанный LFSR-генератор основан на GF (2k) модуль исчисления (GF = Галуа Поля). Только что закончив курс алгебры, я собираюсь объяснить это математическим способом.

начнем с того, что возьмем, например, GF (24), которая равно {a4x4 + a3x3 + a2x2 + a1x1 + a0x0 / a0, a1, ... таким образом,4 Z Z2} (для уточнения, Zn = {0,1,..., n-1} и, следовательно, Z2 = {0,1}, т. е. один бит). Это означает, что это множество всех полиномов четвертой степени при всех факторах либо присутствует, либо нет, но не имеет кратных этих факторов (например, нет 2xk). x3, x4 + x3, 1 и x4 + x3 + x2 + x + 1-все примеры членов этой группы.

мы берем этот модуль множества полиномом четвертой степени (т. е., P (x) ∈ GF(24)), например P (x) = x4+x1+x0. Эта операция модуля в группе также обозначается как GF (24) / P (x). Для справки, P (x) описывает "отводы" в пределах LFSR.

мы также берем случайный многочлен степени 3 или ниже (так что он не зависит от нашего модуля, иначе мы могли бы также выполнить операцию модуля непосредственно на нем), например, a0(x) = x0. Теперь каждый последующий элементя(x) вычисляется путем умножения его на x: aя(x) = Ai-1(x) * X mod P (x).

поскольку мы находимся в ограниченном поле, операция модуля может иметь эффект, но только когда результирующий aя(x) имеет по крайней мере фактор x4 (наш самый высокий коэффициент в P (x)). Обратите внимание, что, поскольку мы работаем с числами в Z2, выполнение самой операции модуля-это не что иное, как определение того, ая становится 0 или 1, добавляя два значения из P (x) и Aя(x) вместе (т. е., 0+0=0, 0+1=1, 1+1=0, или "xoring" эти два).

каждый многочлен может быть записан как набор битов, например x4+x1+x0 ~ 10011. А0(x) можно рассматривать как семя. Операцию "times x" можно рассматривать как операцию сдвига влево. Деятельность модуля можно увидеть как деятельность бита маскируя, с маска является нашим P (x).

алгоритм, изображенный выше, поэтому генерирует (бесконечный поток) допустимых четырех битных шаблонов LFSR. Например, для нашего определен0(x) (x0) и P (x) (x4+x1+x0), мы можем определить следующие первые полученные результаты в GF (24) (обратите внимание, что a0 не сдается до конца первого раунда -- математики обычно начинают считать с "1"):

 i   Ai(x)                   'x⁴'  bit pattern
 0   0x³ + 0x² + 0x¹ + 1x⁰   0     0001        (not yielded)
 1   0x³ + 0x² + 1x¹ + 0x⁰   0     0010
 2   0x³ + 1x² + 0x¹ + 0x⁰   0     0100
 3   1x³ + 0x² + 0x¹ + 0x⁰   0     1000
 4   0x³ + 0x² + 1x¹ + 1x⁰   1     0011        (first time we 'overflow')
 5   0x³ + 1x² + 1x¹ + 0x⁰   0     0110
 6   1x³ + 1x² + 0x¹ + 0x⁰   0     1100
 7   1x³ + 0x² + 1x¹ + 1x⁰   1     1011
 8   0x³ + 1x² + 0x¹ + 1x⁰   1     0101
 9   1x³ + 0x² + 1x¹ + 0x⁰   0     1010
10   0x³ + 1x² + 1x¹ + 1x⁰   1     0111
11   1x³ + 1x² + 1x¹ + 0x⁰   0     1110
12   1x³ + 1x² + 1x¹ + 1x⁰   1     1111
13   1x³ + 1x² + 0x¹ + 1x⁰   1     1101
14   1x³ + 0x² + 0x¹ + 1x⁰   1     1001
15   0x³ + 0x² + 0x¹ + 1x⁰   1     0001        (same as i=0)

обратите внимание, что ваша маска должна содержать " 1 " в четвертой позиции, чтобы убедиться, что ваш LFSR генерирует четырехразрядные результаты. Также обратите внимание ,что "1" должен присутствовать в нулевой позиции, чтобы убедиться, что ваш битовый поток не закончится с 0000-битным шаблоном или что последний бит станет неиспользуемым (если все биты сдвинуты влево, вы также получите ноль в 0-й позиции после одного сдвиг.)

не все P(x) обязательно являются генераторами для GF(2k) (т. е. не все маски K битов генерируют все 2к-1-1 чисел). Например, x4 + x3 + x2 + x1 + x0 генерирует 3 группы по 5 различных полиномов каждый, или "3 цикла периода 5": 0001,0010,0100,1000,1111; 0011,0110,1100,0111,1110; и 0101,1010,1011,1001,1101. Обратите внимание, что 0000 не может быть создано, и не удается сгенерировать другой номер.

обычно выход LFSR-это бит, который "сдвинут", который является "1", Если выполняется операция модуля, и "0", когда это не так. ЛФСР с периодом 2к-1-1, также называемый псевдо-шумом или PN-LFSR, придерживаются постулатов случайности Голома, что говорит о том, что этот выходной бит является случайным "достаточно".

последовательности этих битов поэтому имеют их использование в криптографии, например в A5 / 1 и мобильные стандарты шифрования A5 / 2, или стандарт E0 Bluetooth. Однако они не так безопасны, как хотелось бы:алгоритм Берлекэмпа-Масси может использоваться для обратного проектирования характеристического полинома (P (x)) LFSR. Поэтому сильные стандарты шифрования используют нелинейный FSRили подобные нелинейные функции. Связанной с этим темой являются S-Блоков используется в AES.


обратите внимание, что я использовал the int.bit_length() операция. Это не было реализовано до Python 2.7.
Если вам нужен только конечный битовый шаблон, вы можете проверить, равно ли семя результату, а затем разорвать цикл.
Вы можете использовать мой LFSR-метод В for-loop (например,for xor, pattern in lfsr(0b001,0b10011)) или вы можете повторно вызвать .next() операция по результату метода, возвращающая новый (xor, result)-пару раз.


существует множество приложений LFSRs. Один из них генерирует шум, например, SN76489 и варианты (используется в главной системе, Game Gear, MegaDrive, NeoGeo Pocket,...) используйте LFSR для генерации белого / периодического шума. Существует действительно хорошее описание LFSR SN76489 на этой странице.


чтобы сделать его действительно шикарным и обновления, попробуйте создать генератор, yield-ING последовательные значения из LFSR. Кроме того, по сравнению с плавающей точкой 0.0 является ненужным и запутанным.

LFSR-это всего лишь один из многих способов создания псевдослучайных чисел в компьютерах. Псевдослучайно, потому что нет чисел действительно random - вы можете легко повторить их, начиная с семени (начальное значение) и продолжая те же математические операции.


Ниже приведен вариант вашего кода с использованием целых чисел и двоичных операторов вместо строк. Он также использует yield, как кто-то предложил.

def lfsr2(seed, taps):
    sr = seed
    nbits = 8
    while 1:
        xor = 1
        for t in taps:
            if (sr & (1<<(t-1))) != 0:
                xor ^= 1
        sr = (xor << nbits-1) + (sr >> 1)
        yield xor, sr
        if sr == seed:
            break

nbits = 8
for xor, sr in lfsr2(0b11001001, (8,7,6,1)):
    print xor, bin(2**nbits+sr)[3:]

если мы предположим, что seed-это список ints, а не строка (или преобразовать его, если это не так), то следующее должно делать то, что вы хотите с немного большей элегантностью:

def lfsr(seed, taps) :
  while True:
    nxt = sum([ seed[x] for x in taps]) % 2
    yield nxt
    seed = ([nxt] + seed)[:max(taps)+1]

пример :

for x in lfsr([1,0,1,1,1,0,1,0,0],[1,5,6]) :
  print x

list_init=[1,0,1,1]
list_coeff=[1,1,0,0]
out=[]
for i in range(15):
    list_init.append(sum([list_init[i]*list_coeff[i] for i in range(len(list_init))])%2)
    out.append(list_init.pop(0))
print(out)

#https://www.rocq.inria.fr/secret/Anne.Canteaut/encyclopedia.pdf