-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add irreducible polynomials for GF(2^m)
- New script to create a irreducible polynomials database - Add irreducible polynomials for GF(2^m for 2<=m<=10_000) using Gadiel Seroussi's table - New IrreduciblePolyDatabase class to handle access to the database
- Loading branch information
Showing
5 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
""" | ||
A script to create a database of irreducible polynomials | ||
Sources: | ||
- Gadiel Seroussi. Table of Low-Weight Binary Irreducible Polynomials (1998): https://www.hpl.hp.com/techreports/98/HPL-98-135.html | ||
""" | ||
from __future__ import annotations | ||
|
||
import os | ||
import sqlite3 | ||
from pathlib import Path | ||
|
||
import requests | ||
import hashlib | ||
from pdfminer.high_level import extract_text | ||
|
||
|
||
def main(): | ||
""" | ||
The main routine to create a database of irreducible polynomials | ||
""" | ||
|
||
database_file = Path(__file__).parent.parent / "src" / "galois" / "_databases" / "irreducible_polys.db" | ||
conn, cursor = create_database(database_file) | ||
|
||
_add_hpl_1998(conn, cursor) | ||
|
||
conn.close() | ||
|
||
|
||
def create_database(file: Path) -> tuple[sqlite3.Connection, sqlite3.Cursor]: | ||
""" | ||
Deletes the old database, makes a new one, and returns the database connection. | ||
""" | ||
if file.exists(): | ||
os.remove(file) | ||
|
||
conn = sqlite3.connect(file) | ||
cursor = conn.cursor() | ||
create_table(conn, cursor) | ||
|
||
return conn, cursor | ||
|
||
|
||
def create_table(conn: sqlite3.Connection, cursor: sqlite3.Cursor): | ||
""" | ||
Creates an empty 'polys' table. | ||
""" | ||
cursor.execute( | ||
""" | ||
CREATE TABLE polys ( | ||
characteristic INTEGER NOT NULL, | ||
degree INTEGER NOT NULL, | ||
nonzero_degrees TEXT NOT NULL, | ||
nonzero_coeffs TEXT NOT NULL, | ||
PRIMARY KEY (characteristic, degree) | ||
) | ||
""" | ||
) | ||
conn.commit() | ||
|
||
|
||
def add_to_database(cursor: sqlite3.Cursor, characteristic: str, degree: str, nonzero_degrees: str, nonzero_coeffs: str): | ||
""" | ||
Adds the given irreducible polynomial to the database. | ||
""" | ||
cursor.execute( | ||
""" | ||
INSERT INTO polys (characteristic, degree, nonzero_degrees, nonzero_coeffs) | ||
VALUES (?,?,?,?) | ||
""", | ||
(int(characteristic), int(degree), nonzero_degrees, nonzero_coeffs), | ||
) | ||
|
||
|
||
def _add_hpl_1998(conn, cursor): | ||
""" | ||
Add Gadiel Seroussi's table to the database. | ||
GF(2^m) for 2 <= m <= 10_000 | ||
""" | ||
url = "https://www.hpl.hp.com/techreports/98/HPL-98-135.pdf" | ||
# There is an issue with the SSL certificate using CURL_CA_BUNDLE | ||
# We don't validate https, but we do check the PDF's checksum | ||
pdf = requests.get(url, stream=True, verify=False).content | ||
sha256 = hashlib.sha256() | ||
sha256.update(pdf) | ||
assert sha256.hexdigest() == "78f02d84a0957ad261c53a0d1107adb2ff9d72f52ba5e10ea77eaa8cf766a0ee" | ||
|
||
coefficients = [] | ||
print("Parsing Table of Low-Weight Binary Irreducible Polynomials (1998)...") | ||
for page in range(3, 16): | ||
text = extract_text(Path(__file__).parent / "HPL-98-135.pdf", page_numbers=[page]) | ||
# Tabs are parsed as \n\n, except when the irreducible poly is a pentanomial. | ||
# In that case, there is only a space. First replace takes care of that. | ||
# Second replace unifies tabs and changes of lines. | ||
# Every page ends with the page number and the form feed \x0c, hence the [:-2]. | ||
coefficients += text.replace(" ", "\n").replace("\n\n", "\n").split("\n")[:-2] | ||
|
||
for coeffs in coefficients: | ||
degree = coeffs.split(",")[0] | ||
nonzero_degrees = coeffs + ",0" | ||
nonzero_coeffs = ("1," * len(nonzero_degrees.split(",")))[:-1] | ||
print(f"Irreducible polynomial for GF(2^{degree})") | ||
add_to_database(cursor, "2", str(degree), nonzero_degrees, nonzero_coeffs) | ||
|
||
conn.commit() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
""" | ||
A module that handles accessing the database of irreducible polynomials. | ||
""" | ||
import os | ||
import sqlite3 | ||
|
||
DATABASE = None # Database singleton class | ||
DATABASE_FILE = os.path.join(os.path.dirname(__file__), "irreducible_polys.db") | ||
|
||
|
||
class IrreduciblePolyDatabase: | ||
""" | ||
Class to interface with the irreducible polynomials database. | ||
""" | ||
|
||
def __new__(cls): | ||
global DATABASE | ||
if DATABASE is None: | ||
DATABASE = super().__new__(cls) | ||
return DATABASE | ||
|
||
def __init__(self): | ||
self.conn = sqlite3.connect(DATABASE_FILE) | ||
self.cursor = self.conn.cursor() | ||
|
||
def fetch(self, characteristic, degree): | ||
self.cursor.execute( | ||
""" | ||
SELECT nonzero_degrees,nonzero_coeffs | ||
FROM polys | ||
WHERE characteristic=? AND degree=?""", | ||
(int(characteristic), int(degree)), | ||
) | ||
result = self.cursor.fetchone() | ||
|
||
if result is None: | ||
raise LookupError( | ||
f"The irreducible polynomials database does not contain an entry for GF({characteristic}^{degree}).\n\n" | ||
"Alternatively, you can construct irreducible polynomials with `galois.irreducible_poly(p, m)` " | ||
"or primitive polynomials with `galois.primitive_poly(p, m)`." | ||
) | ||
|
||
nonzero_degrees = [int(_) for _ in result[0].split(",")] | ||
nonzero_coeffs = [int(_) for _ in result[1].split(",")] | ||
|
||
return nonzero_degrees, nonzero_coeffs |
Binary file not shown.