-
Notifications
You must be signed in to change notification settings - Fork 40
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
Discrete log #130
Merged
Merged
Discrete log #130
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
df50d98
Add MultMod type
b-mehta e4f6fe7
Added PrimitiveRoot type and adjusted signatures
b-mehta 1747210
Amend import structure
b-mehta 73e79af
Adjusted tests to new types
b-mehta b81e174
Framework, test, bench for discrete logs
b-mehta 75f4371
Added baby-step giant-step algorithm
b-mehta 31abbf7
Removed redundant pragmas
b-mehta de81a94
MultMod stimes and improved error message
b-mehta d8e45bc
Import of Data.Semigroup for ghc>8.4 also
b-mehta ac3d84d
import Semigroup in DiscreteLog too
b-mehta 3d35432
Merge branch 'master' into dirichlet-characters
b-mehta 56b33ed
Additional tests for discrete logs [ci skip]
b-mehta 6423c6a
Cosmetic changes
b-mehta 8de36ca
More benchmarks for discrete logs
b-mehta e99b29c
Removed redundant comments and pragmas
b-mehta ec5fa71
Fix from review
b-mehta a6a1c1f
Basic refactoring of discrete log
b-mehta 04a85cc
Refactor further, use Natural internally
b-mehta 04119fe
Individual tests of large cases
b-mehta 6dffb74
Handle prime power case better
b-mehta 90102bb
Cosmetic changes and explicit import lists
b-mehta 938d74f
Merge branch 'master' into dirichlet-characters
b-mehta 0d78259
More careful imports to resolve cycle
b-mehta 72239de
Remove redundant tests
b-mehta 7251bf6
Remove redundant pragmas
b-mehta e77edcc
Cleaner benching output
b-mehta eaa5456
Fixed test suite
b-mehta b13f650
Cosmetic changes
b-mehta 36edecc
Bench ranges of larger values
b-mehta dbe983a
(WIP) Pollard's rho for logarithms
b-mehta 08d2481
Larger prime power benchmarks
b-mehta 6df55dd
Some refactoring based on review
b-mehta 6ec31ee
Merge remote-tracking branch 'upstream/master' into dirichlet-characters
b-mehta d9953ec
Changes from review
b-mehta 3942bcc
Use BSGS for small moduli and pollard otherwise
b-mehta ed77e91
Share computation of p^k
b-mehta 2ddd7e7
Probability of pollard failing is now much smaller
b-mehta f2386ab
Merge branch 'master' into dirichlet-characters
b-mehta ac1e46a
Changes from review
b-mehta 1393fdf
Added todo comments
b-mehta File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
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,119 @@ | ||
-- | | ||
-- Module: Math.NumberTheory.Moduli.DiscreteLogarithm | ||
-- Copyright: (c) 2018 Bhavik Mehta | ||
-- License: MIT | ||
-- Maintainer: Andrew Lelechenko <[email protected]> | ||
-- Stability: Provisional | ||
-- Portability: Non-portable | ||
-- | ||
|
||
{-# LANGUAGE ViewPatterns #-} | ||
{-# LANGUAGE BangPatterns #-} | ||
|
||
module Math.NumberTheory.Moduli.DiscreteLogarithm | ||
( discreteLogarithm | ||
) where | ||
|
||
import qualified Data.IntMap.Strict as M | ||
import Data.Maybe (maybeToList) | ||
import Numeric.Natural (Natural) | ||
import GHC.Integer.GMP.Internals (recipModInteger, powModInteger) | ||
|
||
import Math.NumberTheory.Moduli.Chinese (chineseRemainder2) | ||
import Math.NumberTheory.Moduli.Class (KnownNat, MultMod(..), Mod, getVal) | ||
import Math.NumberTheory.Moduli.Equations (solveLinear') | ||
import Math.NumberTheory.Moduli.PrimitiveRoot (PrimitiveRoot(..), CyclicGroup(..)) | ||
import Math.NumberTheory.Powers.Squares (integerSquareRoot) | ||
import Math.NumberTheory.UniqueFactorisation (unPrime) | ||
|
||
-- | Computes the discrete logarithm. Currently uses a combination of the baby-step | ||
-- giant-step method and Pollard's rho algorithm, with Bach reduction. | ||
discreteLogarithm :: KnownNat m => PrimitiveRoot m -> MultMod m -> Natural | ||
discreteLogarithm a b = discreteLogarithm' (getGroup a) (multElement $ unPrimitiveRoot a) (multElement b) | ||
|
||
discreteLogarithm' | ||
:: KnownNat m | ||
=> CyclicGroup Natural -- ^ group structure (must be the multiplicative group mod m) | ||
-> Mod m -- ^ a | ||
-> Mod m -- ^ b | ||
-> Natural -- ^ result | ||
discreteLogarithm' cg a b = | ||
case cg of | ||
CG2 -> 0 | ||
-- the only valid input was a=1, b=1 | ||
CG4 -> if b == 1 then 0 else 1 | ||
-- the only possible input here is a=3 with b = 1 or 3 | ||
CGOddPrimePower (unPrime -> p) k -> discreteLogarithmPP p k (getVal a) (getVal b) | ||
CGDoubleOddPrimePower (unPrime -> p) k -> discreteLogarithmPP p k (getVal a `rem` p^k) (getVal b `rem` p^k) | ||
-- we have the isomorphism t -> t `rem` p^k from (Z/2p^kZ)* -> (Z/p^kZ)* | ||
|
||
-- Implementation of Bach reduction (https://www2.eecs.berkeley.edu/Pubs/TechRpts/1984/CSD-84-186.pdf) | ||
{-# INLINE discreteLogarithmPP #-} | ||
discreteLogarithmPP :: Integer -> Word -> Integer -> Integer -> Natural | ||
discreteLogarithmPP p 1 a b = discreteLogarithmPrime p a b | ||
discreteLogarithmPP p k a b = fromInteger result | ||
where | ||
baseSol = toInteger $ discreteLogarithmPrime p (a `rem` p) (b `rem` p) | ||
thetaA = theta p pkMinusOne a | ||
thetaB = theta p pkMinusOne b | ||
pkMinusOne = p^(k-1) | ||
c = (recipModInteger thetaA pkMinusOne * thetaB) `rem` pkMinusOne | ||
result = chineseRemainder2 (baseSol, p-1) (c, pkMinusOne) | ||
|
||
-- compute the homomorphism theta given in https://math.stackexchange.com/a/1864495/418148 | ||
{-# INLINE theta #-} | ||
theta :: Integer -> Integer -> Integer -> Integer | ||
theta p pkMinusOne a = (numerator `quot` pk) `rem` pkMinusOne | ||
where | ||
pk = pkMinusOne * p | ||
p2kMinusOne = pkMinusOne * pk | ||
numerator = (powModInteger a (pk - pkMinusOne) p2kMinusOne - 1) `rem` p2kMinusOne | ||
|
||
-- TODO: Use Pollig-Hellman to reduce the problem further into groups of prime order. | ||
-- While Bach reduction simplifies the problem into groups of the form (Z/pZ)*, these | ||
-- have non-prime order, and the Pollig-Hellman algorithm can reduce the problem into | ||
-- smaller groups of prime order. | ||
-- In addition, the gcd check before solveLinear is applied in Pollard below will be | ||
-- made redundant, since n would be prime. | ||
discreteLogarithmPrime :: Integer -> Integer -> Integer -> Natural | ||
discreteLogarithmPrime p a b | ||
| p < 100000000 = fromIntegral $ discreteLogarithmPrimeBSGS (fromInteger p) (fromInteger a) (fromInteger b) | ||
| otherwise = discreteLogarithmPrimePollard p a b | ||
|
||
discreteLogarithmPrimeBSGS :: Int -> Int -> Int -> Int | ||
discreteLogarithmPrimeBSGS p a b = head [i*m + j | (v,i) <- zip giants [0..m-1], j <- maybeToList (M.lookup v table)] | ||
where | ||
m = integerSquareRoot (p - 2) + 1 -- simple way of ceiling (sqrt (p-1)) | ||
babies = iterate (.* a) 1 | ||
table = M.fromList (zip babies [0..m-1]) | ||
aInv = recipModInteger (toInteger a) (toInteger p) | ||
bigGiant = fromInteger $ powModInteger aInv (toInteger m) (toInteger p) | ||
giants = iterate (.* bigGiant) b | ||
x .* y = x * y `rem` p | ||
|
||
-- TODO: Use more advanced walks, in order to reduce divisions, cf | ||
-- https://maths-people.anu.edu.au/~brent/pd/rpb231.pdf | ||
-- This will slightly improve the expected time to collision, and can reduce the | ||
-- number of divisions performed. | ||
discreteLogarithmPrimePollard :: Integer -> Integer -> Integer -> Natural | ||
discreteLogarithmPrimePollard p a b = | ||
case concatMap runPollard [(x,y) | x <- [0..n], y <- [0..n]] of | ||
(t:_) -> fromInteger t | ||
[] -> error ("discreteLogarithm: pollard's rho failed, please report this as a bug. inputs " ++ show [p,a,b]) | ||
where | ||
n = p-1 -- order of the cyclic group | ||
halfN = n `quot` 2 | ||
mul2 m = if m < halfN then m * 2 else m * 2 - n | ||
sqrtN = integerSquareRoot n | ||
step (xi,!ai,!bi) = case xi `rem` 3 of | ||
0 -> (xi*xi `rem` p, mul2 ai, mul2 bi) | ||
1 -> ( a*xi `rem` p, ai+1, bi) | ||
_ -> ( b*xi `rem` p, ai, bi+1) | ||
initialise (x,y) = (powModInteger a x n * powModInteger b y n `rem` n, x, y) | ||
begin t = go (step t) (step (step t)) | ||
check t = powModInteger a t p == b | ||
go tort@(xi,ai,bi) hare@(x2i,a2i,b2i) | ||
| xi == x2i, gcd (bi - b2i) n < sqrtN = solveLinear' n (bi - b2i) (ai - a2i) | ||
| xi == x2i = [] | ||
| otherwise = go (step tort) (step (step hare)) | ||
runPollard = filter check . begin . initialise |
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 |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
|
||
module Math.NumberTheory.Moduli.Equations | ||
( solveLinear | ||
, solveLinear' | ||
, solveQuadratic | ||
) where | ||
|
||
|
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
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been never good with names :)
Maybe
MultGroupMod
?