-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Square Roots in Fields of Prime Power Order #573
Comments
I can reproduce this bug. import galois
GF = galois.GF(11**2)
x = GF.squares
print(x)
y = np.sqrt(x)
print(y)
print(y**2)
|
Thank you for identifying this bug and doing as much debug as you already have. From the textbook I referenced, it says Perhaps I didn't "straightforwardly" extend the algorithms to extension fields? Maybe there's a bug in my Python code? |
I've done some more reading and testing, and I believe I may have identified the issue. Luckily, I don't think it's as fundamental of a problem as I originally feared - the paper I link contends that the algorithms used here are not invalid in extension fields of even degree, just that they aren't "efficient" - I'm willing to wager that they're efficient enough for the purposes of this package, at least for the time being. But there was one other interesting thing in this paper that I believe identifies the bug in this code. In the notation of that paper, they consider fields GF(q) with q = p^k for some prime p. They give algorithms for the special cases where q is congruent to 3 modulo 4 or congruent to 5 modulo 8 (among others) which I believe line up with the algorithms implemented here. However, the implementation here applies those algorithms when p (rather than q) satisfies the relevant congruence. For an odd extension degree k, this does not present a problem, as the congruences for p and q = p^k are equivalent. But they are not equivalent for an even extension degree. As an example: 11 is congruent to 3 modulo 4, but 11^2 = 169 is congruent to 1 modulo 4. This means that in these cases, import numpy as np
import galois
GF = galois.GF(17**2)
squares = GF.squares
print(squares)
roots = np.sqrt(squares)
print(roots)
print(roots **2)
print(np.all(squares == roots**2))
As additional assurance, I wrote a quick rewrite of the code implemented in this library with the adjustments I believe are necessary. For this example, I also rewrote the function as a function which handles only one input, as I'm not experienced with wiring up numpy ufuncs. There's obviously no reason to do this in the actual implementation, I just did it to make the testing easier for myself. The code is as follows, and it indeed gives correct results for the case of GF(11^2) which presented the original issue. import numpy as np
import galois
def galois_sqrt(a):
if not a.is_square():
raise ArithmeticError(
f"{a} is not a square in {type(a).name}."
)
field = type(a)
p = field.characteristic
q = field.order
# Swapped p for q here
if q % 4 == 3:
roots = a ** ((q + 1) // 4)
# Swapped p for q here as well
elif q % 8 == 5:
d = a ** ((q - 1) // 4)
roots = field(0)
if d == 1:
roots = a ** ((q + 3) // 8)
elif d == p - 1:
roots = 2 * a * (4 * a) ** ((q - 5) // 8)
else:
# Find a non-square element `b`
while True:
b = field.Random(low=1)
if not b.is_square():
break
# Write p - 1 = 2^s * t
n = field.order - 1
s = 0
while n % 2 == 0:
n >>= 1
s += 1
t = n
assert q - 1 == 2**s * t
roots = field(0) # Roots will go here
# Compute a root `r` if a is nonzero
if a > 0: # Where a has a reciprocal
a_inv = np.reciprocal(a)
c = b**t
r = a ** ((t + 1) // 2)
for i in range(1, s):
d = (r**2 * a_inv) ** (2 ** (s - i - 1))
if d == p - 1:
r *= c
c = c**2
roots = r # Assign root if nonzero
roots = field._view(np.minimum(roots, -roots)) # Return only the smaller root
roots = field(roots)
return roots
GF = galois.GF(11**2)
squares = GF.squares
print(squares)
roots = GF([galois_sqrt(x) for x in squares])
print(roots)
print(roots**2)
print(np.all(squares == roots**2))
I tried out this same code on a few other finite fields of even extension degree, and it produced correct results there as well. So I believe the only change necessary may be a swap from galois/src/galois/_domains/_calculate.py Lines 775 to 799 in c945356
|
This was the first thing I tried, but apparently I didn't apply the idea correctly. I just re-tried, with your patch, and it does seem to work. Thanks for debugging this! I can submit a PR soon, or you can if interested. |
Done! See the PR here: #574 |
Greetings!
It appears the functionality with
np.sqrt
to compute square roots of elements is not properly implemented for extension fields of prime fields. I ran into this issue while trying to compute the square root of 6 in GF(11^2), which incorrectly returns a value of 1. I did a little more testing, and I found that the package computes the square root of all nonzero elements of GF(11^2) as 1. After some further investigation, it seems to be giving incorrect square root results consistently in fields GF(p^k) with odd characteristic p and even extension degree k.It makes sense that there are no issues in characteristic 2, as the square root method for binary fields uses a specific implementation that appears correct:
galois/src/galois/_domains/_calculate.py
Lines 758 to 768 in c945356
I believe the reason we have problems in the odd characteristic case is because the algorithms referenced here are designed for computing square roots modulo p, i.e. in the prime field, but not necessarily in extension fields:
galois/src/galois/_domains/_calculate.py
Lines 770 to 779 in c945356
It's interesting that these algorithms appear (under admittedly limited testing) to work in extension fields of odd degree. Ideally, it's probably worth verifying that this is a genuine mathematical property and not just a fluke due to the small amount of testing I've done to research this issue. But it appears a different technique is definitely required to handle extension fields of even extension degree. I've found a paper on the problem of square roots in finite fields of even extension degree which looks promising, but I haven't had the chance to fully investigate it myself.
Also, I just wanted to say that I really appreciate those who have worked on this package - it's been very helpful to me. I hope this can be used to improve it even more.
The text was updated successfully, but these errors were encountered: