# Roots of unity & FFTs ### Notation Say we have a finite field $\mathbb{F}$ of order $p$. We write $p-1 = 2^k * t$ for some $t$ and $k$ * $\mathbb{F}$ has **two** subgroups of order $2^k$ and $t$ Denote a generator $\alpha$ of the $n = 2^k$ order subgroup $\mathbb{G}$: * $|\mathbb{G}| = n$ (number of points in the subgroup) * $\mathbb{G} = \{1,\alpha,\alpha^2,\dots, \alpha^{n-1}\}$ ### Roots of unity A nth-root of unity is a number $x$ such that $x^n \equiv 1 (\textrm{mod } p)$ In this case, regardless of the which element $a$ of $G$ you take, you always get $a^n \equiv 1$ because $a = \alpha^{i}$ so $a^n = (\alpha^{n})^i = (1)^i = 1$ since $ord(\alpha) = n$ so by definition $\alpha^n = 1$ (from Little Fermat Theorem). ### Primitive Roots of unity $\omega$ is a nth primitive root of unity when $\omega$ is * a nth-root of unity * $w^i \not\equiv 1$ for all $j >0$ and $j|n$ and $j \neq n$ It is called primitive because $\{w^i\}$ with $i>0$ generates the set of all nth-roots of unity. #### Properties The following two properties are useful when computing with the polynomials during the arithmetization: * **Negation**: $\omega^{n/2 + i} = -\omega^i$ * **Halving**: $(\omega^{n/2 + i})^2 = (\omega^i)^2$ * This means that squaring all roots of unity: $(\omega^i)^2$ only gives back _half_ of these roots. * $(\omega^3)^2 = (\omega^{n/2 + 3})^3$ - both elements are equal * This "half" is actually the set of $n/2$-roots of unity since each of the $n/2$ roots of unity can be expressed as $w^i$ for $i:0 \rightarrow n/2$, so we have the following relationship: $$ (w^i)^{n/2} = w^{in/2} = (w^n)^{i/2} = 1 $$ Therefore, each such $w^i$ element is a $n/2$ root of unity. ### Example in $\mathbb{F_7}$ **3rd-roots of unity**: `[print(f"{i} -> {i**3 % 7}") for i in range(0,7)]` 0 -> 0^3 = 0 1 -> 1^3 = 1 --> **YES** 2 -> 2^3 = 1 --> **YES** 3 -> 3^3 = 6 4 -> 4^3 = 1 --> **YES** 5 -> 5^3 = 6 6 -> 6^3 = 6 The set $\{1,2,4\}$ is the set of all 3rd roots of unity. **Primitive 3rd-roots of unity**: We try to find if 2 is a 3rd primitive roots of unity, i.e. for all $i | n$, we compute $2^{(n/i)}$ and look if result is $\neq 1$. * 2^(3/1) = 2 -> 1 is a primitive root of unity but it doesn't "count" really * 2^(3/2) -> 2 doesn't divide 3 We stop here since we only do the$2^{(n/i)}$ operations where $i$ is a _divisor_ of 3. ### Code example Code to find all roots of unity and primitive roots of unity ```python #!/usr/bin/python def is_roots_of_unity(q,n,a): return a**n % q == 1 def is_primitive(q,n,a): if not is_roots_of_unity(q,n,a): return False for i in range(1,n): # only start from 1 since i > 0 if i % n != 0: continue # i must be a divisor of n wi = a**(n/i) % n print(f"{i}: {a}^{n/i} mod {q} = {wi}") if wi == 1: # primitive must be different than 1 at all times return False return True field = 7 roots = 3 for a in range(1,7): print(f"is {a} a primitive {roots}-roots of unity {is_primitive(field,roots,a)}") ``` Example output: ``` is 1 a primitive 3-roots of unity True is 2 a primitive 3-roots of unity True is 3 a primitive 3-roots of unity False is 4 a primitive 3-roots of unity True is 5 a primitive 3-roots of unity False is 6 a primitive 3-roots of unity False ``` ## FFT To multiply two polynomials $A(x)$ $B(x)$ together, we can either: * multiply using **the coefficients** which takes $O(n^2)$ * multiply using the **evaluations points** which takes $O(n)$, **much better** To use the second method the overall strategy is: 1. Convert the polynomials to evaluation points + $A = \{(x_1,A(x_1)),\dots,(x_n,A(x_n))\}$ + $B = \{(x_1,B(x_1)),\dots,(x_n,B(x_n))\}$ 2. Multiply the points together + $C = \{(x_1,A(x_,1)*B(x_1)),\dots,(x_n,A(x_n)*B(x_n))\}$ 3. Revert back to the coefficients forms + $C = c_0 + c_1 * x + \dots + c_{n-1} * x^{n-1}$ FFTs enables us to do the first step in $O(nlog(n))$ instead of $O(n^2)$ ### 1. Divide and conquer Let's express $A$ into a sum of even and odds powers polynomials: * $A(x) = A_1(x) + x * A_2(x)$ * ex: $1 + 3x + 8x^2 + 2x^3 = (1 + 8x^2) + x*(3 + 2x^2)$ * **Equivalent form** $A(x) = A_e(x^2) + x * A_o(x^2)$ ### 2. Using roots of unity As the evaluation points, we will be using the roots of unity! So each input is a power of the primitive root of unity $w$: $$ A(w^i) = A_e((w^i)^2) + w^i*A_o((w^i)^2) $$ We want to evaluate $A$ on all $n$th roots of unity which is a set of size $n$. By using the **negation rule** of the primitive root of unity, we can express the "upper" half of the powers ($w^i$ for $i:n/2 \rightarrow n$) as a combination of the evaluation of the "lower" part of the set. For $i: 0 \rightarrow n/2$, we have: $$ A(w^{i+n/2}) = A_e((-w^{i+n/2})^2) + w^{i+n/2}*A_o(-(w^{i+n/2})^2)=\\ A_e((w^i)^2) - w^i*A_o((w^i)^2) $$ In short, by evaluating half of the points, we can compute the evaluation of the second half!. Here it suffices to compute $A_e((w^i)^2)$ and $A_o((w^i)^2)$. **We went from 1 polynomial evaluation of degree to 2 polynomial evaluation of degree n/2.** ### 3. Recurse We went from evaluating $n$ points to evaluating $n/2$ points. The idea here is to recurse. Using the same logic, we need a way to evaluate the $n/2$ roots of unity $w^i$ in terms of the $n/4$ roots of unity. Well, it turns out that squaring the first $n/2$ $n$-roots of unity gives us the $n/2$ roots of unity ! That means we can now recurse using the $n/2$ roots of unity: TO DO LEFT