packages feed

raaz-0.3.11: implementation/Poly1305/CPortable.hs

{-# LANGUAGE DataKinds                  #-}

-- | The portable C-implementation of Poly1305.
module Poly1305.CPortable
       ( name, description
       , Prim, Internals, BufferAlignment
       , BufferPtr
       , additionalBlocks
       , processBlocks
       , processLast
       , Key(..)
       ) where

import Raaz.Core
import Raaz.Core.Transfer.Unsafe
import Raaz.Primitive.Poly1305.Internal
import Poly1305.Memory

import Raaz.Verse.Poly1305.C.Portable

name :: String
name = "poly1305-libverse-c"

description :: String
description = "Poly1305 Implementation in C exposed by libverse"

type Prim                    = Poly1305
type Internals               = Mem
type BufferAlignment         = 32
type BufferPtr               = AlignedBlockPtr BufferAlignment Prim

additionalBlocks :: BlockCount Poly1305
additionalBlocks = blocksOf 1 Proxy


-- | Incrementally process poly1305 blocks.
processBlocks :: BufferPtr
              -> BlockCount Poly1305
              -> Internals
              -> IO ()
processBlocks buf blks = withAccumR $ runWithBlocks verse_poly1305_c_portable_incremental buf blks

-- | Process a message that is exactly a multiple of the blocks.
blocksMac :: BufferPtr
          -> BlockCount Poly1305
          -> Internals
          -> IO ()
blocksMac buf blks = withAccumRS $ runWithBlocks verse_poly1305_c_portable_blockmac buf blks

-- | Run an IO action with the pointers to the element, r and s cells.
withAccumRS :: ( Ptr Element ->
                 Ptr (Tuple 2 Word64) ->
                 Ptr (Tuple 2 Word64) ->
                 a
               )
            -> Internals
            -> a
withAccumRS func mem = withAccumR func mem $ sKeyPtr mem

withAccumR :: ( Ptr Element ->
                Ptr (Tuple 2 Word64) ->
                a
              )
           -> Internals
           -> a
withAccumR func mem = func (accumPtr mem) $ rKeyPtr mem

runWithBlocks :: ( Ptr a ->
                   Word64 ->
                   b
                 )
              -> BufferPtr
              -> BlockCount Poly1305
              -> b
runWithBlocks func buf = unsafeWithPointerCast func buf . toEnum . fromEnum

-- | Process a message that has its last block incomplete. The total
-- blocks argument here is the greatest multiple of the block that is
-- less that the message length.
partialBlockMac :: BufferPtr
                -> BlockCount Poly1305
                -> Internals
                -> IO ()
partialBlockMac buf blks mem = do
  processBlocks buf blks mem
  withAccumRS (unsafeWithPointerCast partialMac buf) mem
  where partialMac bufPtr = verse_poly1305_c_portable_partialmac (bufPtr `movePtr` blks)

-- | Process the last bytes.
processLast :: BufferPtr
            -> BYTES Int
            -> Internals
            -> IO ()
processLast buf nBytes mem
  | blksC == blksF = blocksMac buf blksC mem
  | otherwise      = do
      unsafeTransfer pad (forgetAlignment buf)
      partialBlockMac buf blksF mem
  where blksC = atLeast nBytes :: BlockCount Poly1305
        blksF = atMost  nBytes :: BlockCount Poly1305
        pad   = padding nBytes

-- | Poly1305 padding. Call this padding function if and only if the
-- message is not a multiple of the block length.
padding :: BYTES Int    -- Data in buffer.
        -> WriteTo
padding mLen = padWrite 0 boundary $ skip mLen `mappend` one
  where one         = writeStorable (1::Word8)
        boundary    = blocksOf 1 (Proxy :: Proxy Poly1305)