module Protocol.Credential where
import Control.Monad (Monad(..), replicateM)
+import Data.Bits
import Data.Bool
import Data.Char (Char)
-import Data.Eq (Eq(..))
import Data.Either (Either(..))
+import Data.Eq (Eq(..))
import Data.Function (($))
import Data.Functor ((<$>))
import Data.Int (Int)
import Data.Maybe (maybe)
+import Data.Ord (Ord(..))
import Data.Text (Text)
-import Prelude (Integral(..), fromIntegral)
+import Numeric.Natural (Natural)
+import Prelude (Integral(..), fromIntegral, div)
import Text.Show (Show)
import qualified Control.Monad.Trans.State.Strict as S
+import qualified Crypto.KDF.PBKDF2 as Crypto
+import qualified Data.ByteArray as ByteArray
+import qualified Data.ByteString as BS
import qualified Data.Char as Char
import qualified Data.List as List
import qualified Data.Text as Text
+import qualified Data.Text.Encoding as Text
import qualified System.Random as Random
import Protocol.Arithmetic
| CredentialError_Checksum
| CredentialError_Length
deriving (Eq, Show)
+
+-- ** Type 'UUID'
+newtype UUID = UUID Text
+ deriving (Eq,Ord,Show)
+
+-- | @'randomUUID'@ generates a random 'UUID'.
+randomUUID ::
+ Monad m =>
+ Random.RandomGen r =>
+ S.StateT r m UUID
+randomUUID = do
+ rs <- replicateM tokenLength (randomR (fromIntegral tokenBase))
+ let (tot, cs) = List.foldl' (\(acc,ds) d ->
+ ( acc * tokenBase + d
+ , charOfDigit d : ds )
+ ) (zero::Int, []) rs
+ return $ UUID $ Text.reverse $ Text.pack cs
+ where
+ charOfDigit = (credentialAlphabet List.!!)
+
+-- ** Type 'SecretKey'
+type SecretKey = E
+
+-- | @('secretKey' uuid cred)@ returns the 'SecretKey'
+-- derived from given 'uuid' and 'cred'
+-- using 'Crypto.fastPBKDF2_SHA256'.
+secretKey :: SubGroup q => UUID -> Credential -> SecretKey q
+secretKey (UUID uuid) (Credential cred) =
+ inE $ BS.foldl'
+ (\acc b -> acc`shiftL`3 + fromIntegral b)
+ (0::Natural)
+ (ByteArray.convert deriv)
+ where
+ deriv :: BS.ByteString
+ deriv =
+ Crypto.fastPBKDF2_SHA256
+ Crypto.Parameters
+ { Crypto.iterCounts = 1000
+ , Crypto.outputLength = 256 `div` 8
+ }
+ (Text.encodeUtf8 cred)
+ (Text.encodeUtf8 uuid)
+
+-- ** Type 'PublicKey'
+type PublicKey = G
+
+-- | @('publicKey' secKey)@ returns the 'PublicKey'
+-- derived from given 'SecretKey' in @('SubGroup' q)@.
+publicKey :: SubGroup q => SecretKey q -> PublicKey q
+publicKey = (groupGen ^)
import Data.String (IsString(..))
import Data.Text (Text)
import Data.Tuple (fst, snd, uncurry)
+import Numeric.Natural (Natural)
import GHC.TypeNats
import Text.Show (Show(..))
import qualified Control.Monad.Trans.State.Strict as S
import qualified Data.List as List
import Protocol.Arithmetic
+import Protocol.Credential
import Utils.MeasuredList as ML
import qualified Utils.Natural as Nat
import qualified Utils.Constraint as Constraint
(encryption_nonce x * encryption_nonce y)
(encryption_vault x * encryption_vault y)
--- ** Type 'PublicKey'
-type PublicKey = G
--- ** Type 'SecretKey'
-type SecretKey = E
-- *** Type 'SecretNonce'
type SecretNonce = E
-- ** Type 'ZKP'
, election_hash :: Hash
} deriving (Eq,Show)
--- ** Type 'UUID'
-newtype UUID = UUID Text
- deriving (Eq,Ord,Show)
-
-- ** Type 'Hash'
newtype Hash = Hash Text
deriving (Eq,Ord,Show)
{-# LANGUAGE OverloadedStrings #-}
module HUnit.Credential where
+import Control.Applicative (Applicative(..))
import qualified Control.Monad.Trans.State.Strict as S
import qualified System.Random as Random
+import Protocol.Arithmetic
import Protocol.Credential
import HUnit.Utils
S.evalState randomCredential (Random.mkStdGen 0) @?=
Credential "xLcs7ev6Jy6FHHE"
]
+ , testGroup "randomUUID"
+ [ testCase "0" $
+ S.evalState randomUUID (Random.mkStdGen 0) @?=
+ UUID "xLcs7ev6Jy6FHH"
+ ]
, testGroup "readCredential" $
let (==>) inp exp =
testCase (show inp) $ readCredential inp @?= exp in
, "xLcs7ev6Jy6FHHF" ==> Left CredentialError_Checksum
, "xLcs7ev6Jy6FHHE" ==> Right (Credential "xLcs7ev6Jy6FHHE")
]
+ , testGroup "secretKey" $
+ [ testSecretKey @WeakParams 0 $ E (F 122)
+ , testSecretKey @WeakParams 1 $ E (F 35)
+ , testSecretKey @BeleniosParams 0 $ E (F 2317630607062989137269685509390)
+ , testSecretKey @BeleniosParams 1 $ E (F 1968146140481358915910346867611)
+ ]
]
+
+testSecretKey :: forall q. SubGroup q => Int -> E q -> TestTree
+testSecretKey seed exp =
+ let (uuid@(UUID u), cred@(Credential c)) =
+ (`S.evalState` Random.mkStdGen seed) $
+ (,) <$> randomUUID <*> randomCredential in
+ testCase (show (u,c)) $
+ secretKey @q uuid cred @?= exp