fft3.sage 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. p = 199
  2. n = 4
  3. assert p.is_prime()
  4. def find_ext_order(p, n):
  5. N = 1
  6. while True:
  7. pNx_order = p^N - 1
  8. # Does n divide the group order 𝔽_{p^N}^×?
  9. if pNx_order % n == 0:
  10. return N
  11. N += 1
  12. def find_nth_root_unity(K, n):
  13. # It cannot be a quadratic residue if n is odd
  14. #assert n % 2 == 1
  15. # So there is an nth root of unity in p^N. Now we have to find it.
  16. pNx_order = p^N - 1
  17. ω = K.multiplicative_generator()
  18. ω = ω^(pNx_order/n)
  19. assert ω^n == 1
  20. assert ω^(n - 1) != 1
  21. return ω
  22. N = find_ext_order(p, n)
  23. print(f"p = {p}")
  24. print(f"n = {n}")
  25. print(f"N = {N}")
  26. print(f"p^N = {p^N}")
  27. K.<a> = GF(p^N, repr="int")
  28. ω = find_nth_root_unity(K, n)
  29. print(f"ω = {ω}")
  30. print()
  31. L.<X> = K[]
  32. f = 10*X + 110
  33. f = X^3 + 10*X + 110
  34. #assert f.degree() < n/2
  35. print(f"f = {f}")
  36. print()
  37. def vectorify(f):
  38. assert f.degree() < n
  39. fT = vector([f[i] for i in range(f.degree() + 1)] +
  40. # Zero padding
  41. [0 for _ in range(n - f.degree() - 1)])
  42. assert len(fT) == n
  43. # Just check decomposed polynomial is in the correct order
  44. assert sum([fT[i]*X^i for i in range(n)]) == f
  45. return fT
  46. def dot(a, b):
  47. assert len(a) == len(b)
  48. return [a_i*b_i for a_i, b_i in zip(a, b)]
  49. assert n == 2^2
  50. m = 4
  51. print(f"m = {m}")
  52. ω_powers = vector(ω^i for i in range(m/2))
  53. print(f"ω^i = {ω_powers}")
  54. fT = vectorify(f)
  55. print(f"fT = {fT}")
  56. # Rewrite f(X) = g(X) + X^(n/2) h(X)
  57. f_g, f_h = vector(fT[:m/2]), vector(fT[m/2:])
  58. print(f" = {f_g}, {f_h}")
  59. r8 = f_g + f_h
  60. s8 = dot((f_g - f_h), ω_powers)
  61. assert len(r8) == len(s8) == m/2
  62. print(f"r8 = {r8}")
  63. print(f"s8 = {s8}")
  64. print()
  65. m = 2
  66. ω_powers = vector(ω_i for ω_i in ω_powers[::2])
  67. assert len(ω_powers) == m/2
  68. print(f"m = {m}")
  69. # Corresponds to r_4
  70. r4_g, r4_h = vector(r8[:m/2]), vector(r8[m/2:])
  71. print(f"r4_g, r4_h = {r4_g}, {r4_h}")
  72. r4_r2 = r4_g + r4_h
  73. r4_s2 = dot((r4_g - r4_h), ω_powers)
  74. print(f"r4_r2 = {r4_r2}")
  75. print(f"r4_s2 = {r4_s2}")
  76. print()
  77. # Corresponds to s_4
  78. s4_g, s4_h = vector(s8[:m/2]), vector(s8[m/2:])
  79. print(f"s4_g, s4_h = {s4_g}, {s4_h}")
  80. s4_r2 = s4_g + s4_h
  81. s4_s2 = dot((s4_g - s4_h), ω_powers)
  82. print(f"s4_r2 = {s4_r2}")
  83. print(f"s4_s2 = {s4_s2}")
  84. print()
  85. # Final step
  86. m = 1
  87. print(f"m = {m}")
  88. print("STOP")
  89. # Just return the values directly
  90. print()
  91. f_evals = [f(X=ω^i) for i in range(n)]
  92. print(f"f(ω^i) = {f_evals}")