packages feed

nettle-0.4: src/Crypto/Nettle/Poly1305.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

-----------------------------------------------------------------------------

-----------------------------------------------------------------------------

{- |
Module      :  Crypto.Nettle.Poly1305
Copyright   :  (c) 2026 Clint Adams
License     :  MIT-style (see the file COPYING)

Maintainer  :  clint@debian.org
Stability   :  experimental
Portability :  portable

This module exports the Poly1305-AES message authentication code supported
by nettle:
  <http://www.lysator.liu.se/~nisse/nettle/>

Poly1305-AES is the (deprecated) original construction by D. J. Bernstein,
where the one-time pad is generated with AES from a nonce.  The modern
Poly1305 construction used by ChaCha-Poly1305 (RFC 7539) is available via
'Crypto.Nettle.ChaChaPoly1305'.
-}
module Crypto.Nettle.Poly1305
    ( -- * Poly1305-AES
      poly1305AES
    , poly1305AESInit
    , poly1305AESUpdate
    , poly1305AESFinalize
    , Poly1305AES
    ) where

import qualified Data.ByteArray as BA
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B

import Crypto.Nettle.Hash.ForeignImports
import Nettle.Utils

-- internal functions are not camelCase on purpose
{-# ANN module "HLint: ignore Use camelCase" #-}

-- | Incremental state of a Poly1305-AES MAC computation.
newtype Poly1305AES = Poly1305AES AlignedContext

poly1305aesInit
    :: B.ByteString
    -- ^ @key@ (32 bytes: 16 byte \"r\", 16 byte \"s\")
    -> Poly1305AES
poly1305aesInit key = Poly1305AES $
    unsafeDupablePerformIO $
        alignedCtxCreate c_poly1305_aes_ctx_size $ \ctxptr ->
            BA.withByteArray key $ \keyptr ->
                if BA.length key /= 32
                    then error "Invalid key length"
                    else
                        c_poly1305_aes_set_key ctxptr keyptr

poly1305aesSetNonce :: Poly1305AES -> B.ByteString -> Poly1305AES
poly1305aesSetNonce (Poly1305AES c) nonce = Poly1305AES $
    unsafeDupablePerformIO $
        alignedCtxCopy c c_poly1305_aes_ctx_size $ \ctxptr ->
            BA.withByteArray nonce $ \nonceptr ->
                if BA.length nonce /= 16
                    then error "Invalid nonce length"
                    else
                        c_poly1305_aes_set_nonce ctxptr nonceptr

poly1305aesUpdate :: Poly1305AES -> B.ByteString -> Poly1305AES
poly1305aesUpdate (Poly1305AES c) msg = Poly1305AES $
    unsafeDupablePerformIO $
        alignedCtxCopy c c_poly1305_aes_ctx_size $ \ctxptr ->
            withByteStringPtr msg $ \msglen msgptr ->
                c_poly1305_aes_update ctxptr msglen msgptr

poly1305aesFinalize :: Poly1305AES -> B.ByteString
poly1305aesFinalize (Poly1305AES c) = unsafeDupablePerformIO $
    B.create c_poly1305_aes_digest_size $ \digestptr ->
        BA.withByteArray (alignedCtxBuffer c) $ \ctxptr ->
            callNettleHashDigest
                c_poly1305_aes_digest
                c_poly1305_aes_digest_size
                (ctxptr `plusPtr` alignedCtxOffset c)
                digestptr

{- |
Initialize a Poly1305-AES MAC computation with a @key@ (32 bytes) and @nonce@ (16 bytes).
-}
poly1305AESInit :: B.ByteString -> B.ByteString -> Poly1305AES
poly1305AESInit key nonce = poly1305aesSetNonce (poly1305aesInit key) nonce

{- |
Add more message data to a Poly1305-AES MAC computation.
-}
poly1305AESUpdate :: Poly1305AES -> B.ByteString -> Poly1305AES
poly1305AESUpdate = poly1305aesUpdate

{- |
Produce the final 16 byte (128 bit) tag of a Poly1305-AES MAC computation.
-}
poly1305AESFinalize :: Poly1305AES -> B.ByteString
poly1305AESFinalize = poly1305aesFinalize

{- |
One-shot Poly1305-AES MAC: calculate the 16 byte tag for a @key@ (32 bytes),
@nonce@ (16 bytes) and @msg@.
-}
poly1305AES
    :: B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString
poly1305AES key nonce msg =
    poly1305aesFinalize $
        poly1305aesUpdate
            (poly1305aesSetNonce (poly1305aesInit key) nonce)
            msg