Files
@ d19e877af29d
Branch filter:
Location: Shamira/src/shamira/fft.py - annotation
d19e877af29d
1.8 KiB
text/x-python
finite field discrete fourier transform
4d58737e66bd 4d58737e66bd d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d d19e877af29d 4d58737e66bd 4d58737e66bd 4d58737e66bd d19e877af29d 4d58737e66bd d19e877af29d 4d58737e66bd 4d58737e66bd 4d58737e66bd d19e877af29d 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd d19e877af29d 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd d19e877af29d 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd 4d58737e66bd | import math
import cmath
import itertools
from .gf256 import gfmul, gfpow
# values of n-th square roots
SQUARE_ROOTS = {3: 189, 5: 12, 15: 225, 17: 53, 51: 51, 85: 15, 255: 3}
def precompute_x(n):
"""Return a geometric sequence [1, w, w**2, ..., w**(n-1)], where w**n==1.
This can be done only for certain values of n."""
assert n in SQUARE_ROOTS
w = SQUARE_ROOTS[n] # primitive N-th square root of 1
return list(itertools.accumulate([1]+[w]*(n-1), gfmul))
def complex_dft(p):
"""Quadratic formula from the definition. The basic case in complex numbers."""
N = len(p)
w = cmath.exp(-2*math.pi*1j/N) # primitive N-th square root of 1
y = [0]*N
for k in range(N):
xk = w**k
for n in range(N):
y[k] += p[n] * xk**n
return y
def dft(p):
"""Quadratic formula from the definition. In GF256."""
N = len(p)
x = precompute_x(N)
y = [0]*N
for k in range(N):
for n in range(N):
y[k] ^= gfmul(p[n], gfpow(x[k], n))
return y
def compute_inverse(N1, N2):
for i in range(N2):
if N1*i % N2 == 1:
return i
raise ValueError("Failed to find an inverse to {0} mod {1}.".format(N1, N2))
def prime_fft(p, divisors):
"""https://en.wikipedia.org/wiki/Prime-factor_FFT_algorithm"""
if len(divisors) == 1:
return complex_dft(p)
N = len(p)
N1 = divisors[0]
N2 = N//N1
N1_inv = compute_inverse(N1, N2)
N2_inv = compute_inverse(N2, N1)
ys = []
for n1 in range(N1): # compute rows
p_ = [p[(n2*N1+n1*N2) % N] for n2 in range(N2)]
ys.append(prime_fft(p_, divisors[1:]))
for k2 in range(N2): # compute cols
p_ = [row[k2] for row in ys]
y_ = complex_dft(p_)
for (yi, row) in zip(y_, ys): # update col
row[k2] = yi
# remap and output
res = [0]*N
for k1 in range(N1):
for k2 in range(N2):
res[(k1*N2*N2_inv+k2*N1*N1_inv) % N] = ys[k1][k2]
return res
|