fft.sage 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  2. K = GF(q)
  3. P.<X> = K[]
  4. def get_omega():
  5. generator = K(5)
  6. assert (q - 1) % 2^32 == 0
  7. # Root of unity
  8. t = (q - 1) / 2^32
  9. omega = generator**t
  10. assert omega != 1
  11. assert omega^(2^16) != 1
  12. assert omega^(2^31) != 1
  13. assert omega^(2^32) == 1
  14. return omega
  15. # Order of this element is 2^32
  16. omega = get_omega()
  17. k = 3
  18. n = 2^k
  19. omega = omega^(2^32 / n)
  20. assert omega^n == 1
  21. f = 6*X^7 + 7*X^5 + 3*X^2 + X
  22. def fft(F):
  23. print(f"fft({F})")
  24. # On the first invocation:
  25. #assert len(F) == n
  26. N = len(F)
  27. if N == 1:
  28. print(" returning 1")
  29. return F
  30. omega_prime = omega^(n/N)
  31. assert omega_prime^(n - 1) != 1
  32. assert omega_prime^N == 1
  33. # Split into even and odd powers of X
  34. F_e = [a for a in F[::2]]
  35. print(" Evens:", F_e)
  36. F_o = [a for a in F[1::2]]
  37. print(" Odds:", F_o)
  38. y_e, y_o = fft(F_e), fft(F_o)
  39. print(f"y_e = {y_e}, y_o = {y_o}")
  40. y = [0] * N
  41. for j in range(N / 2):
  42. y[j] = y_e[j] + omega_prime^j * y_o[j]
  43. y[j + N / 2] = y_e[j] - omega_prime^j * y_o[j]
  44. print(f" returning y = {y}")
  45. return y
  46. print("f =", f)
  47. evals = fft(list(f))
  48. print("evals =", evals)
  49. print("{omega^i : i in {0, 1, ..., n - 1}} =", [omega^i for i in range(n)])
  50. evals2 = [f(omega^i) for i in range(n)]
  51. print("{f(omega^i) for all omega^i} =", evals2)
  52. assert evals == evals2