pvss-0.2.0: app/Main.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
module Main where
import System.Environment
import Control.Monad
import Control.Exception
import Control.DeepSeq
import qualified Crypto.PVSS as PVSS
import qualified Crypto.SCRAPE as SCRAPE
import Data.List
import Time.Types
import Time.System
import Data.Hourglass (timeDiffP)
import Text.Printf (printf)
#ifdef VERSION_mcl
import qualified Crypto.SCRAPE.BDS as SCRAPE_BDS
import qualified Data.Vector as V
#endif
showTimeDiff :: (Seconds, NanoSeconds) -> String
showTimeDiff (Seconds s, NanoSeconds n) =
if s > 10
then printf "%d.%03d seconds" s (n `div` 1000000)
else printf "%d.%06d seconds" s (n `div` 1000)
timing :: NFData t => IO t -> IO (t, (Seconds, NanoSeconds))
timing f = do
t1 <- timeCurrentP
a <- f
t2 <- a `deepseq` timeCurrentP
return (a, t2 `timeDiffP` t1)
timingP :: NFData b => String -> IO b -> IO b
timingP n f = do
(!a, t) <- timing f
putStrLn (n ++ ": " ++ showTimeDiff t)
return a
timingPureP :: NFData b => String -> b -> IO b
timingPureP n f = do
t1 <- timeCurrentP
!a <- evaluate f
t2 <- a `deepseq` timeCurrentP
putStrLn (n ++ ": " ++ showTimeDiff (t2 `timeDiffP` t1))
return a
chunk :: Int -> [t] -> [[t]]
chunk _ [] = []
chunk n l =
let (l1,l2) = splitAt n l
in l1 : chunk n l2
go :: PVSS.Threshold -> Int -> IO ()
go t n = do
participants <- replicateM n $ PVSS.keyPairGenerate
(e, commitments, eshares) <-
timingP "escrow" $ do
!xe <- {-timingP "escrow-new" $-} PVSS.escrowNew t
!xcommitments <- {-timingP "commitments" $-} return $ PVSS.createCommitments xe
!xesharesChunks <- {-timingP "shares" $-} forM (chunk 200 $ zip [1..] (map PVSS.toPublicKey participants)) $ \c ->
{-timingP (" chunk-" ++ show (fst $ head c)) $ -}forM c $ uncurry (PVSS.shareCreate xe xcommitments)
let eshares = mconcat xesharesChunks
return (xe, xcommitments, eshares)
!validated <- timingP "validating" $ forM (chunk 200 $ zip eshares (map PVSS.toPublicKey participants)) $ \c ->
{-timingP (" vchunk") $ -} forM c $ return . PVSS.verifyEncryptedShare (PVSS.escrowExtraGen e) commitments
putStrLn (show $ and $ concat validated)
!decryptedShares <- timingP "decrypting" $ mapM (\(kp,eshare) -> do
p <- PVSS.shareDecrypt kp eshare
return $! p
) (zip participants eshares)
!verifiedShares <- timingPureP "verifying" $
PVSS.getValidRecoveryShares t (zip3 eshares (map PVSS.toPublicKey participants) decryptedShares)
putStrLn (show $ t == fromIntegral (length verifiedShares))
recovered <- timingPureP "recovering" $ PVSS.recover $ take (fromIntegral t+1) $ decryptedShares
putStrLn $ show $ PVSS.escrowSecret e
putStrLn $ show recovered
goScrapeDDH :: SCRAPE.Threshold -> Int -> IO ()
goScrapeDDH t n = do
keypairParticipants <- {-timingP "keypair"-} (replicateM n $ PVSS.keyPairGenerate)
() <- deepseq keypairParticipants (return ())
let participantsPublicKeys = map PVSS.toPublicKey keypairParticipants
participants = SCRAPE.Participants participantsPublicKeys
(extraGen, sec, esis, commitments, _proof, parallelProofs) <- timingP "escrow" $ SCRAPE.escrow t participants
!_validated <- timingP "validating" $ SCRAPE.verifyEncryptedShares extraGen t commitments parallelProofs esis participants
--putStrLn ("encrypted validated: " ++ show validated)
!decryptedShares <- timingP "decrypting" $ mapM (\(kp,eshare) -> do
p <- SCRAPE.shareDecrypt kp eshare
return $! p
) (zip keypairParticipants esis)
let select = take $ fromIntegral t
!v <- timingPureP "verifying-decrypted" $
and $ map (SCRAPE.verifyDecryptedShare) $ select $ zip3 esis participantsPublicKeys decryptedShares
putStrLn $ show v
recovered <- timingPureP "recovering" $ SCRAPE.recover $ zip [1..] $ select decryptedShares
putStrLn $ "secret : " ++ show sec
putStrLn $ "recovered: " ++ show recovered
#ifdef VERSION_mcl
goScrapeBDS :: Int -> Int -> IO ()
goScrapeBDS t n = do
(dp, parties) <- timingP "setup" $ SCRAPE_BDS.setup n
(secret, encryptedShares, commitments) <- timingP "distribution" $
SCRAPE_BDS.distribution dp parties t
timingP "verification" $
SCRAPE_BDS.verification dp t parties encryptedShares commitments
recoveredSecret <- timingP "reconstruction" $
SCRAPE_BDS.reconstruction dp (V.take t) parties encryptedShares commitments
unless (secret == recoveredSecret) $ do
fail $ "secret and recoveredSecret do not match: secret = "
++ show secret ++ ", recoveredSecret = " ++ show recoveredSecret
putStrLn $ "secret: " ++ show recoveredSecret
#endif
main :: IO ()
main = do
args <- getArgs
case args of
#ifdef VERSION_mcl
["scrape-bds", tS, nS] -> goScrapeBDS (read tS) (read nS)
#endif
["scrape-ddh", tS, nS] -> goScrapeDDH (read tS) (read nS)
["pvss", tS, nS] -> go (read tS) (read nS)
_ -> error $ "error: pvss [" ++ scrapeVersions ++ "] <threshold> <number>"
where
scrapeVersions = intercalate "|"
[ "scrape-ddh"
#ifdef VERSION_mcl
, "scrape-bds"
#endif
, "pvss"
]