Search code examples
haskellmathencryptionfunctional-programmingrsa

variables in haskell change without logic when I repeat them


Hello everybody this is my first question here. I just going crazy because of this and not found any information about it...

This is an example of the original code to simulate the problem:

module Code where
import Data.List

list e = [e, e*2 .. 10000]

exp1 z e = (((elemIndices 0 (map (`mod` e) (map (+1) (list z))))!!0 +1)*z +1) `div` e

prub v1 v2 e l = map (`mod` (v1*v2)) (map (product) (map (replicate (exp1 ((v1-1)*(v2-1)) e)) l))

this code with the following variables (31 11 7 [235,302,210,123,255]) returns this list: [106,70,246,160,277]. But this isn't what I looking for.

But if I change the (v1*v2) for 341 which is the product of v1*v2 (11*31 in the example) the output is the following list [20,15,12,30,19]. This it's what I want.

prub v1 v2 e l = map (`mod` 341) (map (product) (map (replicate (exp1 ((v1-1)*(v2-1)) e)) l))

So why exist different returns with the EXACT SAME values?

Sorry for my english. If you want to know what I want to make is a RSA encryption in haskell

Edit: forgive me for the mistakes in code, I edit the text and put a reproducible code.


Solution

  • The problem is a difference in the inferred type for prub in the two versions. The "wrong" version uses Int, which overflows, while the "right" version uses Integer, which doesn't overflow.

    In your original version (that uses v1*v2), the function exp1 has inferred type Int -> Int -> Int. This is because the elemIndices call has return type [Int], which results in the types of the arguments and return value being similarly inferred as Int. Because you have:

    exp1 :: Int -> Int -> Int
    

    the call to exp1 in prub with its first argument ((v1-1)*(v2-1)) causes both v1 and v2 to be assigned type Int. When you take a mod by v1*v2, this causes the type of l to be inferred as [Int].

    In contrast, when you replace v1*v2 with 341, even though the types of v1 and v2 are still inferred as Int, the type of 341 is inferred as an unspecified Integral. The resulting type for prub is:

    prub :: Integral b => Int -> Int -> Int -> [b] -> [b]
    

    When you call prub in your test case using 341 in place of v1*v2:

    prub 31 11 7 [235,302,210,123,255]
    

    the type of the final argument defaults to [Integer] avoiding the overflow.

    To fix it, you should provide a means to perform the necessary calculations on Integer instead of Int. I guess I'd recommend explicit type signatures and a fromIntegral call to convert between Int and Integer where necessary:

    list :: Int -> [Int]
    list e = [e, e*2 .. 10000]
    
    exp1 :: Int -> Int -> Int
    exp1 z e = (((elemIndices 0 (map (`mod` e) (map (+1) (list z))))!!0 +1)*z +1) `div` e
    
    prub :: Int -> Int -> Int -> [Integer] -> [Integer]
    prub v1 v2 e l = map (`mod` fromIntegral (v1*v2)) (map (product) (map (replicate (exp1 ((v1-1)*(v2-1)) e)) l))