-- |
--
-- Module      : Raaz.Core.Primitive
-- Copyright   : (c) Piyush P Kurur, 2019
-- License     : Apache-2.0 OR BSD-3-Clause
-- Maintainer  : Piyush P Kurur <ppk@iitpkd.ac.in>
-- Stability   : experimental
--

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

module Raaz.Core.Primitive
       ( -- * Cryptographic Primtives
         Primitive(..), Key, Nounce, Block, BlockPtr, AlignedBlockPtr
       , BlockCount(..), blocksOf
       ) where

import Data.Vector.Unboxed (Unbox)
import GHC.TypeLits
import Foreign.Storable ( Storable )
import Raaz.Core.Prelude
import Raaz.Core.Types.Endian
import Raaz.Core.Types.Pointer
import Raaz.Core.Types.Tuple

----------------------- A primitive ------------------------------------


-- | Cryptographic primitives that process bulk data (like ciphers,
-- cryptographic hashes) process data in blocks. For data that is not
-- a multiple of the block size they may have some padding
-- strategy. The type class that captures an abstract block
-- cryptographic primitive.
--

class ( Unbox (WordType p)
      , EndianStore (WordType p)
      , KnownNat (WordsPerBlock p)
      ) => Primitive p where

  -- | The block which is the smallest unit of data that the primitive
  -- processes, is typically considered as an array of a particular
  -- word which is captured by the following associated type.
  type WordType p :: Type

  -- | The size of the array that forms the block. In particular, the
  -- block can be seen as an array of size `BlockArraySize p` of type
  -- `WORD p`.
  type WordsPerBlock p :: Nat

-- | The type family that captures the key of a keyed primitive.
data family Key p :: Type

-- | In addition to keys, certain primitives require nounces that can
-- be public but needs to be distinct across different uses when
-- sharing the key. The type family that captures the nounce for a
-- primitive (if it requires one).
data family Nounce p :: Type

-- | A block of the primitive.
type Block p   = Tuple (WordsPerBlock p) (WordType p)

-- | Pointer to a block of the primitive.
type BlockPtr p = Ptr (Block p)

-- | Aligned version of block pointers.

type AlignedBlockPtr n p = AlignedPtr n (Block p)


------------------- Type safe lengths in units of block ----------------

-- | Type safe message length in units of blocks of the primitive.
-- When dealing with buffer lengths for a primitive, it is often
-- better to use the type safe units `BlockCount`. Functions in the raaz
-- package that take lengths usually allow any type safe length as
-- long as they can be converted to bytes. This can avoid a lot of
-- tedious and error prone length calculations.
newtype BlockCount p = BlockCount {BlockCount p -> Int
unBlockCount :: Int}
                     deriving (Int -> BlockCount p -> ShowS
[BlockCount p] -> ShowS
BlockCount p -> String
(Int -> BlockCount p -> ShowS)
-> (BlockCount p -> String)
-> ([BlockCount p] -> ShowS)
-> Show (BlockCount p)
forall p. Int -> BlockCount p -> ShowS
forall p. [BlockCount p] -> ShowS
forall p. BlockCount p -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BlockCount p] -> ShowS
$cshowList :: forall p. [BlockCount p] -> ShowS
show :: BlockCount p -> String
$cshow :: forall p. BlockCount p -> String
showsPrec :: Int -> BlockCount p -> ShowS
$cshowsPrec :: forall p. Int -> BlockCount p -> ShowS
Show, BlockCount p -> BlockCount p -> Bool
(BlockCount p -> BlockCount p -> Bool)
-> (BlockCount p -> BlockCount p -> Bool) -> Eq (BlockCount p)
forall p. BlockCount p -> BlockCount p -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BlockCount p -> BlockCount p -> Bool
$c/= :: forall p. BlockCount p -> BlockCount p -> Bool
== :: BlockCount p -> BlockCount p -> Bool
$c== :: forall p. BlockCount p -> BlockCount p -> Bool
Eq, Eq (BlockCount p)
Eq (BlockCount p)
-> (BlockCount p -> BlockCount p -> Ordering)
-> (BlockCount p -> BlockCount p -> Bool)
-> (BlockCount p -> BlockCount p -> Bool)
-> (BlockCount p -> BlockCount p -> Bool)
-> (BlockCount p -> BlockCount p -> Bool)
-> (BlockCount p -> BlockCount p -> BlockCount p)
-> (BlockCount p -> BlockCount p -> BlockCount p)
-> Ord (BlockCount p)
BlockCount p -> BlockCount p -> Bool
BlockCount p -> BlockCount p -> Ordering
BlockCount p -> BlockCount p -> BlockCount p
forall p. Eq (BlockCount p)
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall p. BlockCount p -> BlockCount p -> Bool
forall p. BlockCount p -> BlockCount p -> Ordering
forall p. BlockCount p -> BlockCount p -> BlockCount p
min :: BlockCount p -> BlockCount p -> BlockCount p
$cmin :: forall p. BlockCount p -> BlockCount p -> BlockCount p
max :: BlockCount p -> BlockCount p -> BlockCount p
$cmax :: forall p. BlockCount p -> BlockCount p -> BlockCount p
>= :: BlockCount p -> BlockCount p -> Bool
$c>= :: forall p. BlockCount p -> BlockCount p -> Bool
> :: BlockCount p -> BlockCount p -> Bool
$c> :: forall p. BlockCount p -> BlockCount p -> Bool
<= :: BlockCount p -> BlockCount p -> Bool
$c<= :: forall p. BlockCount p -> BlockCount p -> Bool
< :: BlockCount p -> BlockCount p -> Bool
$c< :: forall p. BlockCount p -> BlockCount p -> Bool
compare :: BlockCount p -> BlockCount p -> Ordering
$ccompare :: forall p. BlockCount p -> BlockCount p -> Ordering
$cp1Ord :: forall p. Eq (BlockCount p)
Ord, Int -> BlockCount p
BlockCount p -> Int
BlockCount p -> [BlockCount p]
BlockCount p -> BlockCount p
BlockCount p -> BlockCount p -> [BlockCount p]
BlockCount p -> BlockCount p -> BlockCount p -> [BlockCount p]
(BlockCount p -> BlockCount p)
-> (BlockCount p -> BlockCount p)
-> (Int -> BlockCount p)
-> (BlockCount p -> Int)
-> (BlockCount p -> [BlockCount p])
-> (BlockCount p -> BlockCount p -> [BlockCount p])
-> (BlockCount p -> BlockCount p -> [BlockCount p])
-> (BlockCount p -> BlockCount p -> BlockCount p -> [BlockCount p])
-> Enum (BlockCount p)
forall p. Int -> BlockCount p
forall p. BlockCount p -> Int
forall p. BlockCount p -> [BlockCount p]
forall p. BlockCount p -> BlockCount p
forall p. BlockCount p -> BlockCount p -> [BlockCount p]
forall p.
BlockCount p -> BlockCount p -> BlockCount p -> [BlockCount p]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: BlockCount p -> BlockCount p -> BlockCount p -> [BlockCount p]
$cenumFromThenTo :: forall p.
BlockCount p -> BlockCount p -> BlockCount p -> [BlockCount p]
enumFromTo :: BlockCount p -> BlockCount p -> [BlockCount p]
$cenumFromTo :: forall p. BlockCount p -> BlockCount p -> [BlockCount p]
enumFromThen :: BlockCount p -> BlockCount p -> [BlockCount p]
$cenumFromThen :: forall p. BlockCount p -> BlockCount p -> [BlockCount p]
enumFrom :: BlockCount p -> [BlockCount p]
$cenumFrom :: forall p. BlockCount p -> [BlockCount p]
fromEnum :: BlockCount p -> Int
$cfromEnum :: forall p. BlockCount p -> Int
toEnum :: Int -> BlockCount p
$ctoEnum :: forall p. Int -> BlockCount p
pred :: BlockCount p -> BlockCount p
$cpred :: forall p. BlockCount p -> BlockCount p
succ :: BlockCount p -> BlockCount p
$csucc :: forall p. BlockCount p -> BlockCount p
Enum, Ptr b -> Int -> IO (BlockCount p)
Ptr b -> Int -> BlockCount p -> IO ()
Ptr (BlockCount p) -> IO (BlockCount p)
Ptr (BlockCount p) -> Int -> IO (BlockCount p)
Ptr (BlockCount p) -> Int -> BlockCount p -> IO ()
Ptr (BlockCount p) -> BlockCount p -> IO ()
BlockCount p -> Int
(BlockCount p -> Int)
-> (BlockCount p -> Int)
-> (Ptr (BlockCount p) -> Int -> IO (BlockCount p))
-> (Ptr (BlockCount p) -> Int -> BlockCount p -> IO ())
-> (forall b. Ptr b -> Int -> IO (BlockCount p))
-> (forall b. Ptr b -> Int -> BlockCount p -> IO ())
-> (Ptr (BlockCount p) -> IO (BlockCount p))
-> (Ptr (BlockCount p) -> BlockCount p -> IO ())
-> Storable (BlockCount p)
forall b. Ptr b -> Int -> IO (BlockCount p)
forall b. Ptr b -> Int -> BlockCount p -> IO ()
forall p. Ptr (BlockCount p) -> IO (BlockCount p)
forall p. Ptr (BlockCount p) -> Int -> IO (BlockCount p)
forall p. Ptr (BlockCount p) -> Int -> BlockCount p -> IO ()
forall p. Ptr (BlockCount p) -> BlockCount p -> IO ()
forall p. BlockCount p -> Int
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
forall p b. Ptr b -> Int -> IO (BlockCount p)
forall p b. Ptr b -> Int -> BlockCount p -> IO ()
poke :: Ptr (BlockCount p) -> BlockCount p -> IO ()
$cpoke :: forall p. Ptr (BlockCount p) -> BlockCount p -> IO ()
peek :: Ptr (BlockCount p) -> IO (BlockCount p)
$cpeek :: forall p. Ptr (BlockCount p) -> IO (BlockCount p)
pokeByteOff :: Ptr b -> Int -> BlockCount p -> IO ()
$cpokeByteOff :: forall p b. Ptr b -> Int -> BlockCount p -> IO ()
peekByteOff :: Ptr b -> Int -> IO (BlockCount p)
$cpeekByteOff :: forall p b. Ptr b -> Int -> IO (BlockCount p)
pokeElemOff :: Ptr (BlockCount p) -> Int -> BlockCount p -> IO ()
$cpokeElemOff :: forall p. Ptr (BlockCount p) -> Int -> BlockCount p -> IO ()
peekElemOff :: Ptr (BlockCount p) -> Int -> IO (BlockCount p)
$cpeekElemOff :: forall p. Ptr (BlockCount p) -> Int -> IO (BlockCount p)
alignment :: BlockCount p -> Int
$calignment :: forall p. BlockCount p -> Int
sizeOf :: BlockCount p -> Int
$csizeOf :: forall p. BlockCount p -> Int
Storable)

instance Semigroup (BlockCount p) where
  <> :: BlockCount p -> BlockCount p -> BlockCount p
(<>) BlockCount p
x BlockCount p
y = Int -> BlockCount p
forall p. Int -> BlockCount p
BlockCount (Int -> BlockCount p) -> Int -> BlockCount p
forall a b. (a -> b) -> a -> b
$ BlockCount p -> Int
forall p. BlockCount p -> Int
unBlockCount BlockCount p
x Int -> Int -> Int
forall a. Num a => a -> a -> a
+ BlockCount p -> Int
forall p. BlockCount p -> Int
unBlockCount BlockCount p
y
instance Monoid (BlockCount p) where
  mempty :: BlockCount p
mempty   = Int -> BlockCount p
forall p. Int -> BlockCount p
BlockCount Int
0
  mappend :: BlockCount p -> BlockCount p -> BlockCount p
mappend  = BlockCount p -> BlockCount p -> BlockCount p
forall a. Semigroup a => a -> a -> a
(<>)


instance Primitive p => LengthUnit (BlockCount p) where
  inBytes :: BlockCount p -> BYTES Int
inBytes p :: BlockCount p
p@(BlockCount Int
x) = Int -> BYTES Int
forall a. Enum a => Int -> a
toEnum Int
x BYTES Int -> BYTES Int -> BYTES Int
forall a. Num a => a -> a -> a
* BlockCount p -> BYTES Int
nWords BlockCount p
p BYTES Int -> BYTES Int -> BYTES Int
forall a. Num a => a -> a -> a
* BlockCount p -> BYTES Int
wordSize BlockCount p
p
    where wordSize :: BlockCount p -> BYTES Int
wordSize = Proxy (WordType p) -> BYTES Int
forall a. Storable a => Proxy a -> BYTES Int
sizeOf (Proxy (WordType p) -> BYTES Int)
-> (BlockCount p -> Proxy (WordType p))
-> BlockCount p
-> BYTES Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlockCount p -> Proxy (WordType p)
forall p. Primitive p => BlockCount p -> Proxy (WordType p)
proxyWT
          nWords :: BlockCount p -> BYTES Int
nWords   = Int -> BYTES Int
forall a. Enum a => Int -> a
toEnum (Int -> BYTES Int)
-> (BlockCount p -> Int) -> BlockCount p -> BYTES Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int
forall a. Enum a => a -> Int
fromEnum (Integer -> Int)
-> (BlockCount p -> Integer) -> BlockCount p -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Proxy (WordsPerBlock p) -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy (WordsPerBlock p) -> Integer)
-> (BlockCount p -> Proxy (WordsPerBlock p))
-> BlockCount p
-> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlockCount p -> Proxy (WordsPerBlock p)
forall p. Primitive p => BlockCount p -> Proxy (WordsPerBlock p)
proxyWPB
          proxyWT :: Primitive p => BlockCount p -> Proxy (WordType p)
          proxyWT :: BlockCount p -> Proxy (WordType p)
proxyWT  = Proxy (WordType p) -> BlockCount p -> Proxy (WordType p)
forall a b. a -> b -> a
const Proxy (WordType p)
forall k (t :: k). Proxy t
Proxy
          proxyWPB   :: Primitive p => BlockCount p -> Proxy (WordsPerBlock p)
          proxyWPB :: BlockCount p -> Proxy (WordsPerBlock p)
proxyWPB = Proxy (WordsPerBlock p) -> BlockCount p -> Proxy (WordsPerBlock p)
forall a b. a -> b -> a
const Proxy (WordsPerBlock p)
forall k (t :: k). Proxy t
Proxy


-- | The expression @n `blocksOf` primProxy@ specifies the message
-- lengths in units of the block length of the primitive whose proxy
-- is @primProxy@. This expression is sometimes required to make the
-- type checker happy.
blocksOf :: Int -> Proxy p -> BlockCount p
blocksOf :: Int -> Proxy p -> BlockCount p
blocksOf Int
n Proxy p
_ = Int -> BlockCount p
forall p. Int -> BlockCount p
BlockCount Int
n