Skip to content

Commit

Permalink
Add irreducible polynomials for GF(2^m)
Browse files Browse the repository at this point in the history
- 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
iyanmv committed Jan 18, 2023
1 parent 5e45744 commit c309aae
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 0 deletions.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ dev = [
"pytest-cov[toml]",
"pytest-xdist",
"pytest-benchmark >= 4.0.0",
"requests",
"pdfminer.six"
]

[project.urls]
Expand Down
111 changes: 111 additions & 0 deletions scripts/create_irreducible_polys_database.py
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()
1 change: 1 addition & 0 deletions src/galois/_databases/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
"""
from ._conway import ConwayPolyDatabase
from ._prime import PrimeFactorsDatabase
from ._irreducible import IrreduciblePolyDatabase
46 changes: 46 additions & 0 deletions src/galois/_databases/_irreducible.py
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 added src/galois/_databases/irreducible_polys.db
Binary file not shown.

0 comments on commit c309aae

Please sign in to comment.