2010-09-17 89 views
8

Últimamente tropecé repetidamente con el concepto de LFSR, que me parece bastante interesante debido a sus vínculos con diferentes campos y también fascinante en sí mismo. Me tomó un poco de esfuerzo entender, la ayuda final fue realmente buena page, mucho mejor que la (al principio) críptica wikipedia entry. Así que quería escribir un pequeño código para un programa que funcionaba como un LFSR. Para ser más precisos, de alguna manera mostró cómo funciona un LFSR. Aquí está la cosa más limpio que podía llegar a después de algunos intentos lenghtier (Python):Registro de desplazamiento de realimentación lineal?

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 

puse el nombre de "XOR" la salida de la función XOR, no muy correcta. Sin embargo, esto solo pretende mostrar cómo circula en sus posibles estados, de hecho, notó que el registro está representado por una cadena. No hay mucha coherencia lógica.

Esto puede ser fácilmente convertida en un bonito juguete se puede ver por horas (por lo menos que podía :-)

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) 

Entonces se me ocurrió, ¿para qué sirve esto en la escritura de software? Escuché que puede generar números aleatorios; ¿es verdad? ¿cómo? Por lo tanto, sería bueno si alguien pudiera:

  • explicar cómo utilizar un dispositivo de este tipo en el desarrollo de software
  • llegar a algún código, para apoyar el punto anterior o igual a la mía para mostrar diferentes formas de hazlo, en cualquier idioma

también, como theres cosas no mucho didáctica alrededor de esta pieza de la lógica y los circuitos digitales, sería bueno si esto podría ser un lugar para noobies (como yo) para obtener una mejor comprensión de esto cosa, o mejor, para entender qué es y cómo puede ser útil al escribir software. ¿Debería haberlo convertido en una wiki comunitaria?

Dicho esto, si alguien se siente como jugar al golf ... de nada.

+0

Si busca LFSR en lo que se encuentra una gran cantidad ... –

+0

Yo, no tanto lo que quería – MattiaG

+1

Por qué el presente etiquetado como código de golf? – Landei

Respuesta

5

En realidad, los algoritmos basados ​​en LFSR son muy comunes. CRC se basa directamente en LFSR. Por supuesto, en las clases de informática las personas hablan de polinomios cuando hablan sobre cómo se supone que el valor de entrada debe ser XOR con el valor acumulado, en la ingeniería de electornics hablamos de grifos en su lugar. Son la misma terminología diferente.

CRC32 es muy común. Se usa para detectar errores en marcos Ethernet. Eso significa que cuando publiqué esta respuesta, mi PC utilizó un algoritmo basado en LFSR para generar un hash del paquete IP para que mi enrutador pueda verificar que lo que está transmitiendo no está dañado.

archivos Gzip Zip y son otro ejemplo. Ambos usan CRC para la detección de errores. Zip usa CRC32 y Gzip usa CRC16 y CRC32.

Los CRC son básicamente funciones hash. Y es lo suficientemente bueno para hacer que Internet funcione. Lo que significa que los LFSR son bastante buenas funciones hash. No estoy seguro si usted sabe esto, pero en general, las buenas funciones hash se consideran buenos generadores de números aleatorios. Pero lo que sucede con LFSR es que seleccionar los toques correctos (polinomios) es muy importante para la calidad del número aleatorio/aleatorio.

Su código es generalmente código de juguete, ya que opera en una serie de unos y ceros. En el mundo real, LFSR trabaja con bits en un byte. Cada byte que empuja a través del LFSR cambia el valor acumulado del registro. Ese valor es efectivamente una suma de comprobación de todos los bytes que ha introducido en el registro. Dos formas comunes de usar ese valor como un número aleatorio es utilizar un contador e insertar una secuencia de números a través del registro, transformando así la secuencia lineal 1, 2, 3, 4 en alguna secuencia con hash como 15306, 22, 587, 994, o para retroalimentar el valor actual en el registro para generar un nuevo número en una secuencia aparentemente aleatoria.

Debe tenerse en cuenta que hacerlo de forma ingenua utilizando LFSR con manipulación de bits es bastante lento, ya que debe procesar bits a la vez. Entonces, la gente ha ideado maneras de usar tablas precalculadas para hacerlo en ocho bits a la vez o incluso en 32 bits a la vez. Es por eso que casi nunca se ve el código LFSR en la naturaleza. En la mayoría de los códigos de producción se hace pasar por otra cosa.

Pero a veces, un LFSR sencillo y entremezclado puede ser útil. Una vez escribí un controlador Modbus para un micro PIC y ese protocolo usó CRC16. Una tabla precalculada requiere 256 bytes de memoria y mi CPU solo tenía 68 bytes (I'm not kidding). Entonces tuve que usar un LFSR.

+0

TCP/IP usa una suma de comprobación simple, no CRC32. Otros protocolos pueden tener medios adicionales para detectar errores (por ejemplo, Ethernet tiene un FCS que IIRC es un CRC). – ninjalj

+0

@ninjalj: corregido. Gracias por destacar eso. – slebetman

1

para que sea realmente elegante y Pythonic, intenta crear un generador, yield -ing valores sucesivos de la LFSR. Además, comparar con un punto flotante 0.0 es innecesario y confuso.

Un LFSR es sólo una de las muchas maneras de crear números pseudo-aleatorios en los ordenadores. Pseudoaleatorio, porque los números no son realmente aleatorios: puede repetirlos fácilmente comenzando con la semilla (valor inicial) y procediendo con las mismas operaciones matemáticas.

+0

Lo intentaré, aunque ahora mismo no estoy seguro de cómo hacerlo. Pensé que el 0.0 me permitiría evitar otra expresión ... de hecho tienes razón, es inútil. Entonces, genera un número para cada estado, quiero decir, ¿los estados son los números que genera? ¿tiene otros usos? – MattiaG

+0

@Mattia: ¿viste la sección de "aplicaciones" en Wikipedia? Parece bastante completa –

+0

es bueno, todavía su enfoque es más hacia las aplicaciones de hardware, y también me hubiera gustado ver algún código con él. – MattiaG

1

A continuación se muestra una variación de su código que utiliza enteros y operadores binarios en lugar de cadenas. También usa el rendimiento como alguien sugirió.

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:] 
2

Existen muchas aplicaciones de LFSR. Uno de ellos genera ruido, por ejemplo, el SN76489 y las variantes (utilizadas en el sistema maestro, Game Gear, MegaDrive, NeoGeo Pocket, ...) usan un LFSR para generar ruido blanco/periódico. Hay una muy buena descripción del LFSR in this page de SN76489.

+0

Recientemente tuve que escribir algún software que calibra detectores sísmicos. Resulta que al menos una compañía (nanométrica) usa LFSR para generar una señal de "ruido" utilizada para medir la respuesta de frecuencia (usted alimenta este ruido a los detectores, mide la respuesta y luego compara la FFT de la respuesta con la FFT de la entrada, que le da la respuesta del sistema a un rango de frecuencias). –

0

Si asumimos que la semilla es una lista de enteros en lugar de una cadena (o convertirlo si no lo es), entonces el siguiente debería hacer lo que quiera con un poco más de elegancia:

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

Ejemplo:

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

esto es realmente interesante para mí, aún por alguna razón no puedo hacerlo funcionar. ¿Puedes mostrar un ejemplo de su uso? gracias – MattiaG

+0

Hubo un par de errores tipográficos ahí, parece funcionar bien ahora. – Amoss

9

Como estaba buscando una implementación de LFSR en Python, me encontré con este tema. Sin embargo he encontrado que la siguiente era un poco más precisa de acuerdo a mis necesidades:

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 

El LFSR-generador anterior se basa en GF (2 k) módulo de cálculo (GF = Galois Field). Después de haber completado un curso de Algebra, voy a explicar esto de la manera matemática.inicio

de Let tomando, por ejemplo, GF (2), que es igual a {a x + un x + un x + a x + a x | un , un , ..., a ∈ Z } (para aclarar, Z n = {0,1, ..., n-1} y por lo tanto Z = {0,1}, es decir, un bit). Esto significa que este es el conjunto de todos los polinomios de cuarto grado con todos los factores presentes o no, pero sin múltiplos de estos factores (por ejemplo, no hay 2x k). x , x + x , 1 y x + x + x + x + 1, son ejemplos de miembros de este grupo.

Consideramos que este módulo de conjunto es un polinomio de cuarto grado (es decir, P (x) ∈ GF (2)), p. P (x) = x + x + x . Esta operación de módulo en un grupo también se denota como GF (2)/P (x). Para su referencia, P (x) describe los 'grifos' dentro del LFSR.

También tomamos un polinomio aleatorio de grado 3 o inferior (para que no se vea afectado por nuestro módulo, de lo contrario podríamos realizar la operación de módulo directamente en él), p. A (x) = x . Ahora, cada A siguiente (x) se calcula multiplicándolo por x: A i (x) = A i-1 (x) * x mod P (x).

Puesto que estamos en un campo limitado, la operación de módulo puede tener un efecto, pero sólo cuando la resultante A i (x) tiene al menos un factor de x (nuestro más alto factor de P (x)) Tenga en cuenta que, dado que estamos trabajando con números en Z , realizar la operación del módulo en sí no es más que determinar si cada i se convierte en 0 o 1 al agregar los dos valores de P (x) y A i (x) juntos (es decir, 0 + 0 = 0, 0 + 1 = 1, 1 + 1 = 0, o 'xoring' estos dos).

Cada polinomio se puede escribir como un conjunto de bits, por ejemplo x + x + x ~ 10011. El A (x) puede ser visto como la semilla. La operación 'times x' se puede ver como una operación de desplazamiento a la izquierda. La operación del módulo se puede ver como una operación de enmascaramiento de bits, siendo la máscara nuestra P (x).

El algoritmo representado anteriormente genera, por lo tanto, (una secuencia infinita de) patrones válidos de cuatro bits LFSR. Por ejemplo, para nuestra definido A (x) (x) y P (x) (x + x + x), podemos definir la siguiente primero dado resultados en GF (2) (nótese que a no se cede hasta que al final de la primera ronda - matemáticos generalmente empieza a contar en '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) 

Nota que y nuestra máscara debe contener un '1' en la cuarta posición para asegurarse de que su LFSR genere resultados de cuatro bits. También tenga en cuenta que un '1' debe estar presente en la posición cero para asegurarse de que su flujo de bits no termine con un patrón de 0000 bits, o que el bit final quede sin utilizar (si todos los bits se desplazan hacia la izquierda, lo haría también terminan con un cero en la posición 0 después de un turno).

No todos los P (x) 's necesariamente son generadores de GF (2 k) (es decir, no todas las máscaras de k bits generar todos 2 k-1 -1 números). Por ejemplo, x + x + x + x + x genera 3 grupos de 5 polynomals distintos cada uno, o "3 ciclos de periodo de 5": 0001,0010,0100 , 1000,1111; 0011,0110,1100,0111,1110; y 0101,1010,1011,1001,1101. Tenga en cuenta que nunca se puede generar 0000 y no puede generar ningún otro número.

Normalmente, la salida de un LFSR es el bit que se 'desplaza', que es un '1' si se realiza la operación del módulo, y un '0' cuando no lo es. Los LFSR con un período de 2 k-1 -1, también llamados pseudo-ruido o PN-LFSR, se adhieren a los postulados de aleatoriedad de Golomb, que dice tanto que este bit de salida es "suficiente" al azar.

Por lo tanto, las secuencias de estos bits tienen su uso en criptografía, por ejemplo en los estándares de encriptación móvil A5/1 y A5/2, o en el estándar E0 Bluetooth. Sin embargo, no son tan seguros como cabría esperar: el Berlekamp-Massey algorithm se puede utilizar para realizar ingeniería inversa del polinomio característico (el P (x)) del LFSR. Por lo tanto, los estándares de cifrado fuertes usan Non-linear FSR o funciones no lineales similares. Un tema relacionado a esto es el S-Boxes utilizado en AES.


Tenga en cuenta que he utilizado el int.bit_length() operation. Esto no fue implementado hasta Python 2.7.
Si solo te gusta un patrón de bits finitos, puedes comprobar si la semilla es igual al resultado y luego romper el ciclo.
Puede utilizar mi método LFSR en for-loop (por ejemplo, for xor, pattern in lfsr(0b001,0b10011)) o puede llamar repetidamente a la operación .next() sobre el resultado del método, devolviendo un nuevo (xor, result) -pair cada vez.

0
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 
+1

Por favor, explique qué hace su código y por qué. Simplemente publicar código no suele ser una buena respuesta en SO – dirkk

+0

mi list_init es lo que el pdf de anne llama etapas, mi list_coeff es lo que en el pdf se llama coeficiente de realimentación del lfsr y los resultados se almacenan en una nueva lista, en particular esto tiene el coeficiente y las etapas del ejemplo dado en el pdf cheers ciao :) –

+0

Por favor, edite su respuesta en lugar de publicarla como comentario. – dirkk

Cuestiones relacionadas