commit 1ecbfd7ddc3731a9ff532bfe181b104d4490061d
parent 46cb61870a875f2c4e1633bc4d2cba1ddffa461d
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 31 Oct 2026 14:25:37 +0400
test: compare the dispatching and pure implementations
Export '_cipher' for testing, and check that 'cipher' agrees with it
for every input length from 0 to 640 bytes, under two keys and two
starting counters. One counter puts the final block of a 640-byte
input at the maximum counter value, so any native path that handles
several blocks at once is checked at the counter boundary.
Diffstat:
2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/lib/Crypto/Cipher/ChaCha20.hs b/lib/Crypto/Cipher/ChaCha20.hs
@@ -27,6 +27,7 @@ module Crypto.Cipher.ChaCha20 (
-- testing
, ChaCha(..)
, _chacha
+ , _cipher
, _parse_key
, _parse_nonce
, _quarter
diff --git a/test/Main.hs b/test/Main.hs
@@ -6,6 +6,7 @@
module Main where
+import Control.Monad.ST (runST)
import qualified Crypto.Cipher.ChaCha20 as ChaCha
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as B16
@@ -28,6 +29,7 @@ main = defaultMain $ testGroup "ppad-chacha" [
, crypt3
, counter_boundary
, counter_overflow
+ , dispatch
]
quarter :: TestTree
@@ -188,3 +190,24 @@ counter_overflow = H.testCase "chacha20 encrypt (counter overflow)" $ do
plain = BS.replicate 129 0
out = ChaCha.cipher overflow_key con overflow_non plain
H.assertEqual mempty (Left ChaCha.CounterOverflow) out
+
+-- dispatching vs pure
+
+-- the dispatching 'cipher' agrees with the pure Haskell implementation
+-- for every input length from 0 to 640 bytes, covering partial blocks,
+-- short tails, and any multi-block paths. the second counter puts the
+-- final block of a 640-byte input at the maximum counter value.
+dispatch :: TestTree
+dispatch = H.testCase "chacha20 encrypt (dispatch vs pure)" $
+ for_ keys $ \key ->
+ for_ [1, maxBound - 9] $ \con ->
+ for_ [0..640] $ \l -> do
+ let msg = BS.take l plain
+ Right out = ChaCha.cipher key con block_non msg
+ ref = runST $
+ ChaCha._cipher (ChaCha._parse_key key) con
+ (ChaCha._parse_nonce block_non) msg
+ H.assertEqual ("length " <> show l) ref out
+ where
+ keys = [block_key, BS.replicate 32 0xff]
+ plain = BS.pack [fromIntegral (i * 7 + 3) | i <- [0..639 :: Int]]