import Control.Arrow (first)
import Control.DeepSeq (NFData)
import Control.Monad (Monad(..), unless)
-import Data.Aeson (ToJSON(..),FromJSON(..),(.:),(.:?),(.=))
+import Data.Aeson (ToJSON(..), FromJSON(..), (.:), (.:?), (.=))
import Data.Bool
import Data.Either (Either(..))
import Data.Eq (Eq(..))
import Data.Monoid (Monoid(..))
import Data.Ord (Ord(..))
import Data.Proxy (Proxy(..))
-import Data.Reflection (Reifies(..))
+import Data.Reflection (Reifies(..), reify)
import Data.Semigroup (Semigroup(..))
import Data.Text (Text)
import GHC.Generics (Generic)
import qualified Data.Text.Encoding as Text
import qualified System.Random as Random
-import Voting.Protocol.Arith
+import Voting.Protocol.Arithmetic
+import Voting.Protocol.Cryptography
import Voting.Protocol.Credential
-- * Type 'FFC'
--- | Mutiplicative Sub-Group of a Finite Prime Field.
+-- | Mutiplicative subgroup of a Finite Prime Field.
--
-- NOTE: an 'FFC' term-value is brought into the context of many functions
-- through a type-variable @c@ whose 'Reifies' constraint enables to 'reflect'
-- is encoded at the type-level by including @c@
-- as a phantom type of 'F', 'G' and 'E'.
data FFC = FFC
- { ffc_name :: Text
+ { ffc_name :: !Text
, ffc_fieldCharac :: !Natural
-- ^ The prime number characteristic of a Finite Prime Field.
--
-- ElGamal's hardness to decrypt requires a large prime number
- -- to form the 'Multiplicative' subgroup.
+ -- to form the multiplicative subgroup.
, ffc_groupGen :: !Natural
- -- ^ A generator of the 'Multiplicative' subgroup of the Finite Prime Field.
+ -- ^ A generator of the multiplicative subgroup of the Finite Prime Field.
--
-- NOTE: since 'ffc_fieldCharac' is prime,
- -- the 'Multiplicative' subgroup is cyclic,
+ -- the multiplicative subgroup is cyclic,
-- and there are phi('fieldCharac'-1) many choices for the generator of the group,
-- where phi is the Euler totient function.
, ffc_groupOrder :: !Natural
unless (fromJust (ffc_fieldCharac`minusNaturalMaybe`one) `rem` ffc_groupOrder == 0) $
JSON.typeMismatch "FFC: groupOrder does not divide fieldCharac-1" (JSON.Object o)
return FFC{..}
-instance Group FFC where
- groupGen :: forall c. Reifies c FFC => G FFC c
+instance Reifies c FFC => CryptoParams FFC c where
groupGen = G $ ffc_groupGen $ reflect (Proxy::Proxy c)
- groupOrder :: forall c. Reifies c FFC => Proxy c -> Natural
groupOrder c = ffc_groupOrder $ reflect c
+instance ReifyCrypto FFC where
+ reifyCrypto = reify
+instance Key FFC where
+ cryptoType _ = "FFC"
+ cryptoName = ffc_name
+ randomSecretKey = random
+ credentialSecretKey (UUID uuid) (Credential cred) =
+ fromNatural $ decodeBigEndian $
+ Crypto.fastPBKDF2_SHA256
+ Crypto.Parameters
+ { Crypto.iterCounts = 1000
+ , Crypto.outputLength = 32 -- bytes, ie. 256 bits
+ }
+ (Text.encodeUtf8 cred)
+ (Text.encodeUtf8 uuid)
+ publicKey = (groupGen @FFC ^)
fieldCharac :: forall c. Reifies c FFC => Natural
fieldCharac = ffc_fieldCharac $ reflect (Proxy::Proxy c)
-- | Parameters used in Belenios.
-- A 2048-bit 'fieldCharac' of a Finite Prime Field,
--- with a 256-bit 'groupOrder' for a 'Multiplicative' subgroup
+-- with a 256-bit 'groupOrder' for a multiplicative subgroup
-- generated by 'groupGen'.
beleniosFFC :: FFC
beleniosFFC = FFC
-- A field must satisfy the following properties:
--
-- * @(f, ('+'), 'zero')@ forms an abelian group,
--- called the 'Additive' group of 'f'.
+-- called the additive group of 'f'.
--
-- * @('NonNull' f, ('*'), 'one')@ forms an abelian group,
--- called the 'Multiplicative' group of 'f'.
+-- called the multiplicative group of 'f'.
--
-- * ('*') is associative:
-- @(a'*'b)'*'c == a'*'(b'*'c)@ and
instance Reifies c FFC => Additive (G FFC c) where
zero = G 0
G x + G y = G $ (x + y) `mod` fieldCharac @c
-instance Reifies c FFC => Negable (G FFC c) where
- neg (G x)
- | x == 0 = zero
- | otherwise = G $ fromJust $ nat (fieldCharac @c)`minusNaturalMaybe`x
-instance Reifies c FFC => Multiplicative (G FFC c) where
+instance Reifies c FFC => Semiring (G FFC c) where
one = G 1
G x * G y = G $ (x * y) `mod` fieldCharac @c
+instance Reifies c FFC => Ring (G FFC c) where
+ negate (G x)
+ | x == 0 = zero
+ | otherwise = G $ fromJust $ nat (fieldCharac @c)`minusNaturalMaybe`x
+instance Reifies c FFC => EuclideanRing (G FFC c) where
+ -- | NOTE: add 'groupOrder' so the exponent given to (^) is positive.
+ inverse = (^ E (fromJust $ groupOrder @FFC (Proxy @c)`minusNaturalMaybe`1))
instance Reifies c FFC => Random.Random (G FFC c) where
randomR (G lo, G hi) =
first (G . fromIntegral) .
random =
first (G . fromIntegral) .
Random.randomR (0, toInteger (fieldCharac @c) - 1)
-instance Reifies c FFC => Invertible (G FFC c) where
- -- | NOTE: add 'groupOrder' so the exponent given to (^) is positive.
- inv = (^ E (fromJust $ groupOrder @FFC (Proxy @c)`minusNaturalMaybe`1))
-
--- * Conversions
-
-instance Key FFC where
- cryptoType _ = "FFC"
- cryptoName = ffc_name
- randomSecretKey = random
- credentialSecretKey (UUID uuid) (Credential cred) =
- fromNatural $ decodeBigEndian $
- Crypto.fastPBKDF2_SHA256
- Crypto.Parameters
- { Crypto.iterCounts = 1000
- , Crypto.outputLength = 32 -- bytes, ie. 256 bits
- }
- (Text.encodeUtf8 cred)
- (Text.encodeUtf8 uuid)
- publicKey = (groupGen @FFC ^)