|
#generate a list of small primes represented as a u64 array that fit into an OS page. |
|
#calculate their inverse mod u64 so we can test them without division |
|
|
|
import subprocess |
|
import os |
|
import math |
|
from typing import List, Tuple |
|
|
|
def get_page_size() -> int: |
|
"""Get the system's page size""" |
|
return os.sysconf("SC_PAGE_SIZE") |
|
|
|
def is_prime_using_factor(n: int) -> bool: |
|
"""Use GNU factor to check if a number is prime""" |
|
result = subprocess.run(['factor', str(n)], |
|
capture_output=True, |
|
text=True) |
|
# Parse output - format is "n: factors" |
|
factors = result.stdout.strip().split(': ')[1].split() |
|
# If there's only one factor and it equals n, it's prime |
|
return len(factors) == 1 and int(factors[0]) == n |
|
|
|
def extended_gcd(a: int, b: int) -> Tuple[int, int, int]: |
|
"""Extended Euclidean Algorithm""" |
|
if a == 0: |
|
return b, 0, 1 |
|
gcd, x1, y1 = extended_gcd(b % a, a) |
|
x = y1 - (b // a) * x1 |
|
y = x1 |
|
return gcd, x, y |
|
|
|
def mod_inverse(a: int, m: int) -> int: |
|
"""Calculate modular multiplicative inverse""" |
|
gcd, x, _ = extended_gcd(a, m) |
|
if gcd != 1: |
|
raise ValueError(f"Modular inverse does not exist for {a} mod {m}") |
|
return x % m |
|
|
|
def generate_primes_and_inverses(max_size: int) -> List[Tuple[int, int]]: |
|
"""Generate primes and their mod inverses up to max_size bytes""" |
|
UINT64_MAX = (1 << 64) - 1 |
|
|
|
primes_and_inverses = [] |
|
total_size = 0 |
|
n = 3 # Start with 3 as we want odd primes |
|
|
|
while total_size < max_size: |
|
if is_prime_using_factor(n): |
|
try: |
|
inv = mod_inverse(n, UINT64_MAX + 1) |
|
# Each tuple is 16 bytes (8 bytes for prime + 8 bytes for inverse) |
|
size_increase = 16 |
|
if total_size + size_increase <= max_size: |
|
primes_and_inverses.append((n, inv)) |
|
total_size += size_increase |
|
else: |
|
break |
|
except ValueError: |
|
pass # Skip if no modular inverse exists |
|
n += 2 # Check only odd numbers |
|
|
|
return primes_and_inverses |
|
|
|
def main(): |
|
page_size = get_page_size() |
|
print(f"System page size: {page_size} bytes") |
|
|
|
# Generate primes and inverses to fill one page |
|
primes_and_inverses = generate_primes_and_inverses(page_size) |
|
|
|
# Print results in a format suitable for use in systems programming |
|
print("\nPrime number table with modular inverses (u64):") |
|
print("const PRIME_INVERSES: [(u64, u64)] = [") |
|
for prime, inv in primes_and_inverses: |
|
print(f" ({prime}, {inv}),") |
|
print("];") |
|
|
|
print(f"\nGenerated {len(primes_and_inverses)} prime-inverse pairs") |
|
print(f"Total size: {len(primes_and_inverses) * 16} bytes") |
|
|
|
# Verify correctness |
|
print("\nVerifying correctness...") |
|
UINT64_MAX = (1 << 64) - 1 |
|
for prime, inv in primes_and_inverses: |
|
# Check if (prime * inverse) mod 2^64 ≡ 1 |
|
if (prime * inv) % (UINT64_MAX + 1) != 1: |
|
print(f"ERROR: Invalid inverse for prime {prime}") |
|
break |
|
else: |
|
print("All modular inverses verified correct!") |
|
|
|
if __name__ == "__main__": |
|
main() |