packages feed

ppad-poly1305 (empty) → 0.1.0

raw patch · 6 files changed

+227/−0 lines, 6 filesdep +basedep +bytestringdep +criterion

Dependencies added: base, bytestring, criterion, ppad-base16, ppad-poly1305, primitive, tasty, tasty-hunit

Files

+ CHANGELOG view
@@ -0,0 +1,5 @@+# Changelog++- 0.1.0 (2025-03-09)+  * Initial release, supporting the Poly1305 MAC.+
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2025 Jared Tobin++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ bench/Main.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Criterion.Main+import qualified Crypto.MAC.Poly1305 as Poly1305+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base16 as B16+import Data.Maybe (fromJust)++main :: IO ()+main = defaultMain [+    suite+  ]++msg :: BS.ByteString+msg = fromJust . B16.decode $+  "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e"++key :: BS.ByteString+key = fromJust . B16.decode $+  "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"++suite :: Benchmark+suite =+  bgroup "ppad-poly1305" [+    bench "mac" $ nf (Poly1305.mac key) msg+  ]+
+ lib/Crypto/MAC/Poly1305.hs view
@@ -0,0 +1,80 @@+{-# OPTIONS_HADDOCK prune #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ViewPatterns #-}++-- |+-- Module: Crypto.MAC.Poly1305+-- Copyright: (c) 2025 Jared Tobin+-- License: MIT+-- Maintainer: Jared Tobin <jared@ppad.tech>+--+-- A pure Poly1305 MAC implementation, as specified by+-- [RFC 8439](https://datatracker.ietf.org/doc/html/rfc8439).++module Crypto.MAC.Poly1305 (+    -- * Poly1305 message authentication code+    mac+  ) where++import Data.Bits ((.&.), (.|.), (.<<.), (.>>.))+import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BI++fi :: (Integral a, Num b) => a -> b+fi = fromIntegral+{-# INLINE fi #-}++-- arbitrary-size little-endian bytestring decoding+roll :: BS.ByteString -> Integer+roll = BS.foldr alg 0 where+  alg (fi -> !b) !a = (a .<<. 8) .|. b+{-# INLINE roll #-}++-- little-endian bytestring encoding+unroll :: Integer -> BS.ByteString+unroll i = case i of+    0 -> BS.singleton 0+    _ -> BS.unfoldr coalg i+  where+    coalg = \case+      0 -> Nothing+      m -> Just $! (fi m, m .>>. 8)+{-# INLINE unroll #-}++clamp :: Integer -> Integer+clamp r = r .&. 0x0ffffffc0ffffffc0ffffffc0fffffff+{-# INLINE clamp #-}++-- | Produce a Poly1305 MAC for the provided message, given the provided+--   key.+--+--   Per RFC8439: the key, which is essentially a /one-time/ key, should+--   be unique, and MUST be unpredictable for each invocation.+--+--   The key must be exactly 256 bits in length. Providing an invalid+--   key will cause the function to throw an ErrorCall exception.+--+--   >>> mac "i'll never use this key again!!!" "a message needing authentication"+--   "O'\231Z\224\149\148\246\203[}\210\203\b\200\207"+mac+  :: BS.ByteString -- ^ 256-bit one-time key+  -> BS.ByteString -- ^ arbitrary-length message+  -> BS.ByteString -- ^ 128-bit message authentication code+mac key@(BI.PS _ _ kl) msg+    | kl /= 32  = error "ppad-poly1305 (mac): invalid key"+    | otherwise =+        let (clamp . roll -> r, roll -> s) = BS.splitAt 16 key++            loop !acc !bs = case BS.splitAt 16 bs of+              (chunk@(BI.PS _ _ l), etc)+                | l == 0 -> BS.take 16 (unroll (acc + s))+                | otherwise ->+                    let !n = roll chunk .|. (0x01 .<<. (8 * l))+                        !nacc = r * (acc + n) `rem` p+                    in  loop nacc etc++        in  loop 0 msg+  where+    p = 1361129467683753853853498429727072845819 -- (1 << 130) - 5+
+ ppad-poly1305.cabal view
@@ -0,0 +1,65 @@+cabal-version:      3.0+name:               ppad-poly1305+version:            0.1.0+synopsis:           A pure Poly1305 MAC+license:            MIT+license-file:       LICENSE+author:             Jared Tobin+maintainer:         jared@ppad.tech+category:           Cryptography+build-type:         Simple+tested-with:        GHC == 9.8.1+extra-doc-files:    CHANGELOG+description:+  A pure Poly1305 message authentication code, per+  [RFC8439](https://datatracker.ietf.org/doc/html/rfc8439).++source-repository head+  type:     git+  location: git.ppad.tech/poly1305.git++library+  default-language: Haskell2010+  hs-source-dirs:   lib+  ghc-options:+      -Wall+  exposed-modules:+      Crypto.MAC.Poly1305+  build-depends:+      base >= 4.9 && < 5+    , bytestring >= 0.9 && < 0.13++test-suite poly1305-tests+  type:                exitcode-stdio-1.0+  default-language:    Haskell2010+  hs-source-dirs:      test+  main-is:             Main.hs++  ghc-options:+    -rtsopts -Wall -O2++  build-depends:+      base+    , bytestring+    , ppad-base16+    , ppad-poly1305+    , primitive+    , tasty+    , tasty-hunit++benchmark poly1305-bench+  type:                exitcode-stdio-1.0+  default-language:    Haskell2010+  hs-source-dirs:      bench+  main-is:             Main.hs++  ghc-options:+    -rtsopts -O2 -Wall++  build-depends:+      base+    , bytestring+    , criterion+    , ppad-base16+    , ppad-poly1305+
+ test/Main.hs view
@@ -0,0 +1,27 @@+{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}++module Main where++import qualified Crypto.MAC.Poly1305 as Poly1305+import qualified Data.ByteString.Base16 as B16+import Test.Tasty+import qualified Test.Tasty.HUnit as H++main :: IO ()+main = defaultMain $ testGroup "ppad-poly1305" [+    mac+  ]++mac :: TestTree+mac = H.testCase "mac" $ do+  let Just key = B16.decode+        "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"+      msg = "Cryptographic Forum Research Group"++      Just e = B16.decode "a8061dc1305136c6c22b8baf0c0127a9"++      o = Poly1305.mac key msg+  H.assertEqual mempty e o+