{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies               #-}

-- |
--
-- Module      : Raaz.Primitive.Poly1305.Internal
-- Description : Internals of the poly1305 message authenticator.
-- Copyright   : (c) Piyush P Kurur, 2019
-- License     : Apache-2.0 OR BSD-3-Clause
-- Maintainer  : Piyush P Kurur <ppk@iitpkd.ac.in>
-- Stability   : experimental
--

module Raaz.Primitive.Poly1305.Internal
       ( -- * The Poly1305 MAC
         -- $poly1305$
         Poly1305(..), R(..), S(..), WORD, Key(..)
       ) where

import Foreign.Storable( Storable )
import Raaz.Core

-- $poly1305$
--
-- This module exposes the types required to implement the the
-- poly1305 message authenticator. The poly1305 is a function that
-- takes two parameters `r` and `s` and for an input message `m`
-- computes the function.
--
-- Poly1305(m, r,s) = (M(r) mod 2^130 - 5) + s mod 2^128
--
--  In the original publication, `r` is selected pseudo-randomly and
-- `s` is generated by encrypting (using AES) a nonce `n` with a
-- secret key k, i.e. r = random; s = AES(k,n).  The secret that needs
-- to be shared by the two parties is `r` and the key `k`. Actual
-- protocols should never repeat the nonce `n` for otherwise there
-- will be compromise in the security.  The RFC7539 uses a variant
-- that uses the chacha20 cipher instead of AES.
--
-- As can be seen from the above discussion the actual mechanism for
-- selecting the `r` and `s` differs depending on the
-- situation. Hence, this module only provide the "raw" Poly1305
-- implementation leaving out the details of the selection of `r` and
-- `s` for some latter stage. Thus this module is not of direct use
-- but is used by actual protocols to implement message
-- authentication.

-- | A Poly1305 word is a 128-bit numbers in little-endian.
type WORD = Tuple 2 (LE Word64)

-- | The datatype that captures the Poly1305 authenticator tag.
newtype Poly1305 = Poly1305 WORD deriving (Ptr Poly1305 -> IO Poly1305
Ptr Poly1305 -> Int -> IO Poly1305
Ptr Poly1305 -> Int -> Poly1305 -> IO ()
Ptr Poly1305 -> Poly1305 -> IO ()
Poly1305 -> Int
(Poly1305 -> Int)
-> (Poly1305 -> Int)
-> (Ptr Poly1305 -> Int -> IO Poly1305)
-> (Ptr Poly1305 -> Int -> Poly1305 -> IO ())
-> (forall b. Ptr b -> Int -> IO Poly1305)
-> (forall b. Ptr b -> Int -> Poly1305 -> IO ())
-> (Ptr Poly1305 -> IO Poly1305)
-> (Ptr Poly1305 -> Poly1305 -> IO ())
-> Storable Poly1305
forall b. Ptr b -> Int -> IO Poly1305
forall b. Ptr b -> Int -> Poly1305 -> IO ()
forall a.
(a -> Int)
-> (a -> Int)
-> (Ptr a -> Int -> IO a)
-> (Ptr a -> Int -> a -> IO ())
-> (forall b. Ptr b -> Int -> IO a)
-> (forall b. Ptr b -> Int -> a -> IO ())
-> (Ptr a -> IO a)
-> (Ptr a -> a -> IO ())
-> Storable a
$csizeOf :: Poly1305 -> Int
sizeOf :: Poly1305 -> Int
$calignment :: Poly1305 -> Int
alignment :: Poly1305 -> Int
$cpeekElemOff :: Ptr Poly1305 -> Int -> IO Poly1305
peekElemOff :: Ptr Poly1305 -> Int -> IO Poly1305
$cpokeElemOff :: Ptr Poly1305 -> Int -> Poly1305 -> IO ()
pokeElemOff :: Ptr Poly1305 -> Int -> Poly1305 -> IO ()
$cpeekByteOff :: forall b. Ptr b -> Int -> IO Poly1305
peekByteOff :: forall b. Ptr b -> Int -> IO Poly1305
$cpokeByteOff :: forall b. Ptr b -> Int -> Poly1305 -> IO ()
pokeByteOff :: forall b. Ptr b -> Int -> Poly1305 -> IO ()
$cpeek :: Ptr Poly1305 -> IO Poly1305
peek :: Ptr Poly1305 -> IO Poly1305
$cpoke :: Ptr Poly1305 -> Poly1305 -> IO ()
poke :: Ptr Poly1305 -> Poly1305 -> IO ()
Storable, Storable Poly1305
Ptr Poly1305 -> IO Poly1305
Ptr Poly1305 -> Int -> IO ()
Ptr Poly1305 -> Poly1305 -> IO ()
Storable Poly1305 =>
(Ptr Poly1305 -> Poly1305 -> IO ())
-> (Ptr Poly1305 -> IO Poly1305)
-> (Ptr Poly1305 -> Int -> IO ())
-> EndianStore Poly1305
forall w.
Storable w =>
(Ptr w -> w -> IO ())
-> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
$cstore :: Ptr Poly1305 -> Poly1305 -> IO ()
store :: Ptr Poly1305 -> Poly1305 -> IO ()
$cload :: Ptr Poly1305 -> IO Poly1305
load :: Ptr Poly1305 -> IO Poly1305
$cadjustEndian :: Ptr Poly1305 -> Int -> IO ()
adjustEndian :: Ptr Poly1305 -> Int -> IO ()
EndianStore, Poly1305 -> Poly1305 -> Result
(Poly1305 -> Poly1305 -> Result) -> Equality Poly1305
forall a. (a -> a -> Result) -> Equality a
$ceq :: Poly1305 -> Poly1305 -> Result
eq :: Poly1305 -> Poly1305 -> Result
Equality, Poly1305 -> Poly1305 -> Bool
(Poly1305 -> Poly1305 -> Bool)
-> (Poly1305 -> Poly1305 -> Bool) -> Eq Poly1305
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Poly1305 -> Poly1305 -> Bool
== :: Poly1305 -> Poly1305 -> Bool
$c/= :: Poly1305 -> Poly1305 -> Bool
/= :: Poly1305 -> Poly1305 -> Bool
Eq)

-- | The `r` component of the secret.
newtype R        = R WORD deriving (Ptr R -> IO R
Ptr R -> Int -> IO R
Ptr R -> Int -> R -> IO ()
Ptr R -> R -> IO ()
R -> Int
(R -> Int)
-> (R -> Int)
-> (Ptr R -> Int -> IO R)
-> (Ptr R -> Int -> R -> IO ())
-> (forall b. Ptr b -> Int -> IO R)
-> (forall b. Ptr b -> Int -> R -> IO ())
-> (Ptr R -> IO R)
-> (Ptr R -> R -> IO ())
-> Storable R
forall b. Ptr b -> Int -> IO R
forall b. Ptr b -> Int -> R -> IO ()
forall a.
(a -> Int)
-> (a -> Int)
-> (Ptr a -> Int -> IO a)
-> (Ptr a -> Int -> a -> IO ())
-> (forall b. Ptr b -> Int -> IO a)
-> (forall b. Ptr b -> Int -> a -> IO ())
-> (Ptr a -> IO a)
-> (Ptr a -> a -> IO ())
-> Storable a
$csizeOf :: R -> Int
sizeOf :: R -> Int
$calignment :: R -> Int
alignment :: R -> Int
$cpeekElemOff :: Ptr R -> Int -> IO R
peekElemOff :: Ptr R -> Int -> IO R
$cpokeElemOff :: Ptr R -> Int -> R -> IO ()
pokeElemOff :: Ptr R -> Int -> R -> IO ()
$cpeekByteOff :: forall b. Ptr b -> Int -> IO R
peekByteOff :: forall b. Ptr b -> Int -> IO R
$cpokeByteOff :: forall b. Ptr b -> Int -> R -> IO ()
pokeByteOff :: forall b. Ptr b -> Int -> R -> IO ()
$cpeek :: Ptr R -> IO R
peek :: Ptr R -> IO R
$cpoke :: Ptr R -> R -> IO ()
poke :: Ptr R -> R -> IO ()
Storable, Storable R
Ptr R -> IO R
Ptr R -> Int -> IO ()
Ptr R -> R -> IO ()
Storable R =>
(Ptr R -> R -> IO ())
-> (Ptr R -> IO R) -> (Ptr R -> Int -> IO ()) -> EndianStore R
forall w.
Storable w =>
(Ptr w -> w -> IO ())
-> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
$cstore :: Ptr R -> R -> IO ()
store :: Ptr R -> R -> IO ()
$cload :: Ptr R -> IO R
load :: Ptr R -> IO R
$cadjustEndian :: Ptr R -> Int -> IO ()
adjustEndian :: Ptr R -> Int -> IO ()
EndianStore, R -> R -> Result
(R -> R -> Result) -> Equality R
forall a. (a -> a -> Result) -> Equality a
$ceq :: R -> R -> Result
eq :: R -> R -> Result
Equality, R -> R -> Bool
(R -> R -> Bool) -> (R -> R -> Bool) -> Eq R
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: R -> R -> Bool
== :: R -> R -> Bool
$c/= :: R -> R -> Bool
/= :: R -> R -> Bool
Eq)

-- | The `s` component of the secret.
newtype S        = S WORD deriving (Ptr S -> IO S
Ptr S -> Int -> IO S
Ptr S -> Int -> S -> IO ()
Ptr S -> S -> IO ()
S -> Int
(S -> Int)
-> (S -> Int)
-> (Ptr S -> Int -> IO S)
-> (Ptr S -> Int -> S -> IO ())
-> (forall b. Ptr b -> Int -> IO S)
-> (forall b. Ptr b -> Int -> S -> IO ())
-> (Ptr S -> IO S)
-> (Ptr S -> S -> IO ())
-> Storable S
forall b. Ptr b -> Int -> IO S
forall b. Ptr b -> Int -> S -> IO ()
forall a.
(a -> Int)
-> (a -> Int)
-> (Ptr a -> Int -> IO a)
-> (Ptr a -> Int -> a -> IO ())
-> (forall b. Ptr b -> Int -> IO a)
-> (forall b. Ptr b -> Int -> a -> IO ())
-> (Ptr a -> IO a)
-> (Ptr a -> a -> IO ())
-> Storable a
$csizeOf :: S -> Int
sizeOf :: S -> Int
$calignment :: S -> Int
alignment :: S -> Int
$cpeekElemOff :: Ptr S -> Int -> IO S
peekElemOff :: Ptr S -> Int -> IO S
$cpokeElemOff :: Ptr S -> Int -> S -> IO ()
pokeElemOff :: Ptr S -> Int -> S -> IO ()
$cpeekByteOff :: forall b. Ptr b -> Int -> IO S
peekByteOff :: forall b. Ptr b -> Int -> IO S
$cpokeByteOff :: forall b. Ptr b -> Int -> S -> IO ()
pokeByteOff :: forall b. Ptr b -> Int -> S -> IO ()
$cpeek :: Ptr S -> IO S
peek :: Ptr S -> IO S
$cpoke :: Ptr S -> S -> IO ()
poke :: Ptr S -> S -> IO ()
Storable, Storable S
Ptr S -> IO S
Ptr S -> Int -> IO ()
Ptr S -> S -> IO ()
Storable S =>
(Ptr S -> S -> IO ())
-> (Ptr S -> IO S) -> (Ptr S -> Int -> IO ()) -> EndianStore S
forall w.
Storable w =>
(Ptr w -> w -> IO ())
-> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
$cstore :: Ptr S -> S -> IO ()
store :: Ptr S -> S -> IO ()
$cload :: Ptr S -> IO S
load :: Ptr S -> IO S
$cadjustEndian :: Ptr S -> Int -> IO ()
adjustEndian :: Ptr S -> Int -> IO ()
EndianStore, S -> S -> Result
(S -> S -> Result) -> Equality S
forall a. (a -> a -> Result) -> Equality a
$ceq :: S -> S -> Result
eq :: S -> S -> Result
Equality, S -> S -> Bool
(S -> S -> Bool) -> (S -> S -> Bool) -> Eq S
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: S -> S -> Bool
== :: S -> S -> Bool
$c/= :: S -> S -> Bool
/= :: S -> S -> Bool
Eq)

instance Encodable Poly1305
instance Encodable R
instance Encodable S

instance IsString Poly1305 where
  fromString :: String -> Poly1305
fromString = String -> Poly1305
forall a. Encodable a => String -> a
fromBase16

instance IsString R where
  fromString :: String -> R
fromString = String -> R
forall a. Encodable a => String -> a
fromBase16

instance IsString S where
  fromString :: String -> S
fromString = String -> S
forall a. Encodable a => String -> a
fromBase16

instance Show Poly1305 where
  show :: Poly1305 -> String
show = Poly1305 -> String
forall a. Encodable a => a -> String
showBase16

instance Show R where
  show :: R -> String
show = R -> String
forall a. Encodable a => a -> String
showBase16

instance Show S where
  show :: S -> String
show = S -> String
forall a. Encodable a => a -> String
showBase16

instance Primitive Poly1305 where
  type WordType      Poly1305  = Word8
  type WordsPerBlock Poly1305  = 16

data instance Key Poly1305  = Key R S deriving Int -> Key Poly1305 -> ShowS
[Key Poly1305] -> ShowS
Key Poly1305 -> String
(Int -> Key Poly1305 -> ShowS)
-> (Key Poly1305 -> String)
-> ([Key Poly1305] -> ShowS)
-> Show (Key Poly1305)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Key Poly1305 -> ShowS
showsPrec :: Int -> Key Poly1305 -> ShowS
$cshow :: Key Poly1305 -> String
show :: Key Poly1305 -> String
$cshowList :: [Key Poly1305] -> ShowS
showList :: [Key Poly1305] -> ShowS
Show