content: {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# OPTIONS_GHC -fno-warn-orphans #-}
  module Util where
  
  import           Crypto.Saltine.Class
  
  import           Control.Monad           (replicateM)
  import qualified Data.ByteString       as S
  import           Data.Monoid
  import           Data.Semigroup          (Semigroup)
  import           Data.Word (Word8)
  import           Data.Bits (xor)
  import           Test.QuickCheck
  import           GHC.Exts (IsList(..))
  
  instance IsEncoding S.ByteString where
      encode x = x
      decode x = Just x
  
  perturb :: IsEncoding a => a -> Perturb -> a
  perturb a (Perturb p) =
      let bytes = encode a
          len   = S.length bytes
          plen  = length p
          fullP = p <> replicate (len - plen) 0
          newBytes = S.pack $ zipWith xor fullP (S.unpack bytes)
      in case decode newBytes of
          Nothing -> error "Invalid use of perturb on picky encoding."
          Just x  -> x
  
  newtype Perturb = Perturb [Word8]
      deriving (Show,Semigroup,Monoid)
  
  instance IsList Perturb where
      type Item Perturb = Word8
      fromList = Perturb
      toList (Perturb x) = x
  
  instance Arbitrary Perturb where
      arbitrary =
          do bs <- arbitrary
             if all (==0) bs
              then pure (Perturb (1:bs))
              else pure (Perturb bs)
  
  newtype ByteString32 = ByteString32 S.ByteString deriving (Eq,Show)
  
  instance Arbitrary ByteString32 where
    arbitrary = ByteString32 . S.pack <$> replicateM 32 arbitrary
  
  newtype Message = Message S.ByteString deriving (Show)
  
  instance Arbitrary Message where
    arbitrary = Message . S.pack <$> arbitrary
  