module Crypto.Paillier where
import Data.Maybe
import Crypto.Random
import Crypto.Number.Prime
import Crypto.Number.Generate (generateOfSize, generateBetween)
import Crypto.Number.ModArithmetic
#if 0
import System.IO
#endif
type PlainText = Integer
type CipherText = Integer
data PubKey = PubKey{ bits :: Int
, n_modulo :: Integer
, generator :: Integer
, n_square :: Integer
} deriving (Show)
data PrvKey = PrvKey{ lambda :: Integer
, x :: Integer
} deriving (Show)
genKey :: Int -> IO (PubKey, PrvKey)
genKey nBits = do
pool <- createEntropyPool
let rng = cprgCreate pool :: SystemRNG
let (p, rng1) = generatePrime rng (nBits `div` 2)
let (q, rng2) = generatePrime rng1 (nBits `div` 2)
let modulo = p*q
let g = modulo+1
let square = modulo*modulo
let phi_n = lcm (p1) (q1)
let maybeU = inverse (((expSafe g phi_n square) 1) `div` modulo) modulo
if isNothing maybeU then
error "genKey failed."
else
return (PubKey{bits=nBits, n_modulo=modulo, generator=g, n_square=square}
,PrvKey{lambda=phi_n, x=(fromJust maybeU)})
_encrypt :: PubKey -> PlainText -> Integer -> CipherText
_encrypt pubKey plaintext r =
result
where result = (g_m*r_n) `mod` n_2
n_2 = n_square pubKey
g_m = expSafe (generator pubKey) plaintext n_2
r_n = expSafe r (n_modulo pubKey) n_2
generateR :: SystemRNG -> PubKey -> Integer -> Integer
generateR rng pubKey guess =
if guess >= (n_modulo pubKey) || ((gcd (n_modulo pubKey) guess) > 1) then
generateR nextRng pubKey nextGuess
else
guess
where (nextGuess, nextRng) = generateBetween rng 1 ((n_modulo pubKey) 1)
encrypt :: PubKey -> PlainText -> IO CipherText
encrypt pubKey plaintext = do
pool <- createEntropyPool
let rng = cprgCreate pool :: SystemRNG
#if 0
hSetBuffering stdout NoBuffering
putStrLn "get r..."
#endif
let r = generateR rng pubKey (n_modulo pubKey)
#if 0
putStrLn $ "r=" ++ (show r)
#endif
return $ _encrypt pubKey plaintext r
decrypt :: PrvKey -> PubKey -> CipherText -> PlainText
decrypt prvKey pubKey ciphertext =
let c_lambda = expSafe ciphertext (lambda prvKey) (n_square pubKey)
l_c_lamdba = (c_lambda 1) `div` (n_modulo pubKey)
in (l_c_lamdba) * (x prvKey) `mod` (n_modulo pubKey)
cipherMul :: PubKey -> CipherText -> CipherText -> CipherText
cipherMul pubKey c1 c2 = (c1*c2) `mod` (n_square pubKey)
cipherExp :: PubKey -> CipherText -> PlainText -> CipherText
cipherExp pubKey c1 p1 = expSafe c1 p1 (n_square pubKey)