From 6689ff8ae292786fe4900df89385087f61edca8d Mon Sep 17 00:00:00 2001 From: Sam HADOW Date: Sun, 11 Jan 2026 17:58:36 +0100 Subject: [PATCH] CLI interface + restructuration + precision fixes Fermat Factorization --- README.md | 5 +-- app/FactorizationUI.hs | 36 ++++++++++++++++++++ app/Main.hs | 16 +++++++-- {src => app}/Utils.hs | 12 ++++++- haskell-math.cabal | 11 +++++- src/Factorization.hs | 4 +++ src/Factorization/FermatFactorization.hs | 31 +++++++++++++++++ src/Factorization/PollardPminus1.hs | 23 +++---------- src/Factorization/fermat-factorization.hs | 24 ------------- src/ModularSquareRoot.hs | 3 ++ src/{ => ModularSquareRoot}/TonelliShanks.hs | 2 +- 11 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 app/FactorizationUI.hs rename {src => app}/Utils.hs (53%) create mode 100644 src/Factorization.hs create mode 100644 src/Factorization/FermatFactorization.hs delete mode 100644 src/Factorization/fermat-factorization.hs create mode 100644 src/ModularSquareRoot.hs rename src/{ => ModularSquareRoot}/TonelliShanks.hs (95%) diff --git a/README.md b/README.md index 63836e4..42c9405 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ ## running project from CLI ``` -$ ghci -i./src -ghci> :load HaskellMath.hs +$ cabal update +$ cabal build +$ cabal run ``` ## algorithms diff --git a/app/FactorizationUI.hs b/app/FactorizationUI.hs new file mode 100644 index 0000000..40a1f81 --- /dev/null +++ b/app/FactorizationUI.hs @@ -0,0 +1,36 @@ +module FactorizationUI (run) where + +import Utils (askChoice, askNumber) +import Factorization (fermatFactorization, pollardPminus1) + +run :: IO () +run = do + putStrLn "Factorization" + putStrLn "1) Fermat factorization" + putStrLn "2) Pollard p-1" + + choice <- askChoice 2 + + case choice of + 1 -> fermatUI + 2 -> pollardUI + _ -> error "Impossible" + +fermatUI :: IO () +fermatUI = do + n <- askNumber "Enter an integer n > 1:" + let (p, q) = fermatFactorization n + putStrLn ("n = " ++ show n) + putStrLn ("p = " ++ show p) + putStrLn ("q = " ++ show q) + +pollardUI :: IO () +pollardUI = do + n <- askNumber "Enter an integer n > 1:" + b <- askNumber "Enter the bound B:" + case pollardPminus1 n b of + Just factor -> do + putStrLn ("Found factor: " ++ show factor) + putStrLn ("Other factor: " ++ show (n `div` factor)) + Nothing -> + putStrLn "Failed to find a factor (try a different B or method)." diff --git a/app/Main.hs b/app/Main.hs index 3f9f99b..aaf8df9 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,7 +1,19 @@ module Main where -import qualified Primes () +import Utils (askChoice) +import qualified FactorizationUI main :: IO () main = do - putStrLn "unimplemented" + putStrLn "Haskell Math Toolkit" + putStrLn "1) Factorization" + putStrLn "2) Modular square root (not yet implemented)" + putStrLn "3) Primality test (not yet implemented)" + + choice <- askChoice 3 + + case choice of + 1 -> FactorizationUI.run + 2 -> putStrLn "Modular square root: not implemented yet." + 3 -> putStrLn "Primality test: not implemented yet." + _ -> error "Impossible" diff --git a/src/Utils.hs b/app/Utils.hs similarity index 53% rename from src/Utils.hs rename to app/Utils.hs index dd8feb5..5ceafef 100644 --- a/src/Utils.hs +++ b/app/Utils.hs @@ -1,4 +1,4 @@ -module Utils (askNumber) where +module Utils (askNumber, askChoice) where import Text.Read (readMaybe) import System.Exit (exitSuccess) @@ -13,3 +13,13 @@ askNumber s = do _ -> do putStrLn "Not a valid integer" exitSuccess + +askChoice :: Int -> IO Int +askChoice maxChoice = do + putStrLn "Enter your choice:" + input <- getLine + case readMaybe input of + Just n | n >= 1 && n <= maxChoice -> return n + _ -> do + putStrLn "Invalid choice" + exitSuccess diff --git a/haskell-math.cabal b/haskell-math.cabal index 3320aa0..8e7bb03 100644 --- a/haskell-math.cabal +++ b/haskell-math.cabal @@ -20,10 +20,16 @@ library import: warnings exposed-modules: Primes + Factorization + ModularSquareRoot + ModularArithmeticUtils other-modules: + Primes.FermatPrimeTest Primes.MillerRabin Primes.SolovayStrassen - ModularArithmeticUtils + Factorization.FermatFactorization + Factorization.PollardPminus1 + ModularSquareRoot.TonelliShanks build-depends: base ^>=4.18.2.1, random ^>=1.2 @@ -33,6 +39,9 @@ library executable haskell-math import: warnings main-is: Main.hs + other-modules: + FactorizationUI + Utils build-depends: base ^>=4.18.2.1, haskell-math diff --git a/src/Factorization.hs b/src/Factorization.hs new file mode 100644 index 0000000..8419b0d --- /dev/null +++ b/src/Factorization.hs @@ -0,0 +1,4 @@ +module Factorization ( fermatFactorization, pollardPminus1) where + +import Factorization.FermatFactorization +import Factorization.PollardPminus1 diff --git a/src/Factorization/FermatFactorization.hs b/src/Factorization/FermatFactorization.hs new file mode 100644 index 0000000..9c9ef0f --- /dev/null +++ b/src/Factorization/FermatFactorization.hs @@ -0,0 +1,31 @@ +module Factorization.FermatFactorization (fermatFactorization) where + +fermatFactorization :: Integer -> (Integer, Integer) +fermatFactorization n + | n <= 0 = error "n must be positive" + | even n = (2, n `div` 2) + | otherwise = (p, q) + where + (d, root) = findIntegerSqrt n + p = root + d + q = root - d + +-- Find the smallest integer d >= 0 such that sqrt(n + d^2) is an integer +findIntegerSqrt :: Integer -> (Integer, Integer) +findIntegerSqrt n = go 0 + where + go d = + let val = n + d*d + root = isqrt val + in if root * root == val + then (d, root) + else go (d + 1) + +isqrt :: Integer -> Integer +isqrt 0 = 0 +isqrt 1 = 1 +isqrt n = iterateSqrt n + where + iterateSqrt x = + let y = (x + n `div` x) `div` 2 + in if y >= x then x else iterateSqrt y diff --git a/src/Factorization/PollardPminus1.hs b/src/Factorization/PollardPminus1.hs index 30a7728..db0ef76 100644 --- a/src/Factorization/PollardPminus1.hs +++ b/src/Factorization/PollardPminus1.hs @@ -1,25 +1,10 @@ -import Text.Read (readMaybe) -import System.Exit (exitSuccess) -import Utils (askNumber) +module Factorization.PollardPminus1 (pollardPminus1) where + import ModularArithmeticUtils (modExp) -main :: IO () -main = do - n <- askNumber "Enter an integer n>1 to factor:" - b <- askNumber "Enter the bound B:" - putStrLn ("n = " ++ show n) - - case pollardP1 n b of - Just factor -> do - putStrLn ("Found factor: " ++ show factor) - let otherFactor = n `div` factor - putStrLn ("Other factor: " ++ show otherFactor) - Nothing -> do - putStrLn "Failed to find a factor using Pollard p-1 method. n could be prime or different parameters needed." - -- Pollard p-1 factorization algorithm -pollardP1 :: Integer -> Integer -> Maybe Integer -pollardP1 n b = tryBases [2..5] +pollardPminus1 :: Integer -> Integer -> Maybe Integer +pollardPminus1 n b = tryBases [2..5] where tryBases [] = Nothing tryBases (a:as) = diff --git a/src/Factorization/fermat-factorization.hs b/src/Factorization/fermat-factorization.hs deleted file mode 100644 index 3028e8e..0000000 --- a/src/Factorization/fermat-factorization.hs +++ /dev/null @@ -1,24 +0,0 @@ -import Text.Read (readMaybe) -import System.Exit (exitSuccess) -import Utils (askNumber) - -main :: IO () -main = do - n <- askNumber "Enter an integer:" - let (d, root) = findIntegerSqrt n - q = (root - d) - p = (root + d) - putStrLn ("n = " ++ show n) - putStrLn ("Found d = " ++ show d ++ ", sqrt(n + d^2) = " ++ show root) - putStrLn ("q = " ++ show q ++ ", p = " ++ show p) - --- Find the smallest integer d >= 0 such that sqrt(n + d^2) is an integer -findIntegerSqrt :: Integer -> (Integer, Integer) -findIntegerSqrt n = go 0 - where - go d = - let val = n + d*d - root = floor (sqrt (fromIntegral val)) - in if root * root == val - then (d, root) - else go (d + 1) diff --git a/src/ModularSquareRoot.hs b/src/ModularSquareRoot.hs new file mode 100644 index 0000000..8170c33 --- /dev/null +++ b/src/ModularSquareRoot.hs @@ -0,0 +1,3 @@ +module ModularSquareRoot (tonelliShanks) where + +import ModularSquareRoot.TonelliShanks diff --git a/src/TonelliShanks.hs b/src/ModularSquareRoot/TonelliShanks.hs similarity index 95% rename from src/TonelliShanks.hs rename to src/ModularSquareRoot/TonelliShanks.hs index e4fd7fa..8711e30 100644 --- a/src/TonelliShanks.hs +++ b/src/ModularSquareRoot/TonelliShanks.hs @@ -1,4 +1,4 @@ -module TonelliShanks (tonelliShanks) where +module ModularSquareRoot.TonelliShanks (tonelliShanks) where import ModularArithmeticUtils (modExp, modMul, legendre, factorOutTwos)