packages feed

pvss-0.2.0: test/Spec.hs

module Main where

import           Control.Monad
import           Crypto.Random
import qualified Crypto.PVSS as PVSS
import qualified Crypto.SCRAPE as SCRAPE
import           Test.Tasty
import           Test.Tasty.QuickCheck

newtype Threshold = Threshold PVSS.Threshold
    deriving (Show,Eq)

newtype Participants = Participants Integer
    deriving (Show,Eq)

data KofN = KofN PVSS.Threshold Integer
    deriving (Show,Eq)

instance Arbitrary Threshold where
    arbitrary = Threshold <$> choose (1,5)
instance Arbitrary Participants where
    arbitrary = Participants <$> choose (2,10)

instance Arbitrary KofN where
    arbitrary = do
        n <- choose (3,20)
        t <- choose (1,8)
        pure $ if t >= n then KofN t (t+1)
                         else KofN t n

instance Show ChaChaDRG where
    show _ = "chachaDRG"
instance Arbitrary ChaChaDRG where
    arbitrary = arbitrary >>= \n -> return $ drgNewTest (0,0,0,0,n)

toPk :: PVSS.KeyPair -> PVSS.PublicKey
toPk = PVSS.toPublicKey

testEncryptVerify :: Threshold -> Participants -> ChaChaDRG -> Property
testEncryptVerify (Threshold threshold) (Participants nOrig) rng =
    map (PVSS.verifyEncryptedShare egen commitments) (zip eshares (map toPk participants)) === map (const True) eshares
  where
    n :: Integer
    n = max (threshold) nOrig

    (participants, rng2) = withDRG rng $ replicateM (fromIntegral n) PVSS.keyPairGenerate

    ((egen, sec, _, commitments, eshares), rng3) = withDRG rng2 $
        PVSS.escrow threshold (map toPk participants)

testDecryptVerify :: Threshold -> Participants -> ChaChaDRG -> Property
testDecryptVerify (Threshold threshold) (Participants nOrig) rng =
        map (PVSS.verifyDecryptedShare) (zip3 eshares (map toPk participants) decryptedShares)
    === map (const True) eshares
  where
    n :: Integer
    n = max (threshold) nOrig

    (participants, rng2) = withDRG rng $ replicateM (fromIntegral n) PVSS.keyPairGenerate

    ((egen, sec, _, commitments, eshares), rng3) = withDRG rng2 $
        PVSS.escrow threshold (map toPk participants)

    (decryptedShares, _) = withDRG rng3 $ do
        mapM (\(kp,eshare) -> PVSS.shareDecrypt kp eshare) (zip participants eshares)

testSecretVerify :: Threshold -> Participants -> ChaChaDRG -> Property
testSecretVerify (Threshold threshold) (Participants nOrig) rng =
    PVSS.verifySecret egen commitments sec secProof === True
  where
    n :: Integer
    n = max (threshold) nOrig

    (participants, rng2) = withDRG rng $ replicateM (fromIntegral n) PVSS.keyPairGenerate

    ((egen, sec, secProof, commitments, _), rng3) = withDRG rng2 $
        PVSS.escrow threshold (map toPk participants)

testRecovery :: Threshold -> Participants -> ChaChaDRG -> Property
testRecovery (Threshold threshold) (Participants nOrig) rng =

    let recovered = PVSS.recover $ take (fromIntegral (threshold+1)) $ decryptedShares
     in recovered === sec

  where
    n :: Integer
    n = max (threshold) nOrig

    (participants, rng2) = withDRG rng $ replicateM (fromIntegral n) PVSS.keyPairGenerate

    ((egen, sec, _, commitments, eshares), rng3) = withDRG rng2 $
        PVSS.escrow threshold (map toPk participants)

    (decryptedShares, _) = withDRG rng3 $ do
        mapM (\(kp,eshare) -> PVSS.shareDecrypt kp eshare) (zip participants eshares)

-----------------------------------------------
-- SCRAPE test

scrapeEncryptVerify :: KofN -> ChaChaDRG -> Property
scrapeEncryptVerify (KofN threshold nOrig) rng =
    let (r, _) = withDRG rng3 $ SCRAPE.verifyEncryptedShares egen threshold commitments proofs eshares participants
     in r === True
  where
    n :: Integer
    n = max (threshold) nOrig

    (participantAll, rng2) = withDRG rng $ replicateM (fromIntegral n) PVSS.keyPairGenerate
    participants = SCRAPE.Participants $ map toPk participantAll

    ((egen, sec, eshares, commitments, proof, proofs), rng3) = withDRG rng2 $
        SCRAPE.escrow threshold participants

scrapeDecryptVerify :: KofN -> ChaChaDRG -> Property
scrapeDecryptVerify (KofN threshold nOrig) rng =
        map (SCRAPE.verifyDecryptedShare) (zip3 eshares (map toPk participantAll) decryptedShares)
    === map (const True) eshares
  where
    n :: Integer
    n = max (threshold) nOrig

    (participantAll, rng2) = withDRG rng $ replicateM (fromIntegral n) SCRAPE.keyPairGenerate
    participants = SCRAPE.Participants $ map toPk participantAll

    ((egen, sec, eshares, commitments, proof, proofs), rng3) = withDRG rng2 $
        SCRAPE.escrow threshold participants
    (decryptedShares, _) = withDRG rng3 $ do
        mapM (\(kp,eshare) -> SCRAPE.shareDecrypt kp eshare) (zip participantAll eshares)

scrapeSecretVerify :: KofN -> ChaChaDRG -> Property
scrapeSecretVerify (KofN threshold nOrig) rng =
    SCRAPE.verifySecret egen threshold commitments sec secProof === True
  where
    n :: Integer
    n = max (threshold) nOrig

    (participantAll, rng2) = withDRG rng $ replicateM (fromIntegral n) SCRAPE.keyPairGenerate
    participants = SCRAPE.Participants $ map toPk participantAll

    ((egen, sec, eshares, commitments, secProof, proofs), rng3) = withDRG rng2 $
        SCRAPE.escrow threshold participants

scrapeRecovery :: KofN -> ChaChaDRG -> Property
scrapeRecovery (KofN threshold nOrig) rng =

    let recovered = SCRAPE.recover $ take (fromIntegral (threshold+1)) $ zip [1..] decryptedShares
     in recovered === sec

  where
    n :: Integer
    n = max (threshold) nOrig

    (participants, rng2) = withDRG rng $ replicateM (fromIntegral n) SCRAPE.keyPairGenerate

    ((egen, sec, eshares, commitments, proof, proofs), rng3) = withDRG rng2 $
        SCRAPE.escrow threshold (SCRAPE.Participants $ map toPk participants)

    (decryptedShares, _) = withDRG rng3 $ do
        mapM (\(kp,eshare) -> SCRAPE.shareDecrypt kp eshare) (zip participants eshares)

main :: IO ()
main = defaultMain $ testGroup "PVSS"
    [ testGroup "schoenmaker"
        [ testProperty "encrypted-verified" testEncryptVerify
        , testProperty "decrypted-verified" testDecryptVerify
        , testProperty "secret-verified" testSecretVerify
        , testProperty "recovery" testRecovery ]
    , testGroup "scrape"
        [ testProperty "encrypted-verified" scrapeEncryptVerify
        , testProperty "decrypted-verified" scrapeDecryptVerify
        , testProperty "secret-verified" scrapeSecretVerify
        , testProperty "recovery" scrapeRecovery ]
    ]