packages feed

xor (empty) → 0.0.1.0

raw patch · 6 files changed

+1202/−0 lines, 6 filesdep +QuickCheckdep +basedep +bytestring

Dependencies added: QuickCheck, base, bytestring, criterion, ghc-byteorder, tasty, tasty-hunit, tasty-quickcheck, xor

Files

+ LICENSE.GPLv2 view
@@ -0,0 +1,339 @@+              GNU GENERAL PUBLIC LICENSE+                 Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++                     Preamble++  The licenses for most software are designed to take away your+freedom to share and change it.  By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users.  This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it.  (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.)  You can apply it to+your programs, too.++  When we speak of free software, we are referring to freedom, not+price.  Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++  To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++  For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have.  You must make sure that they, too, receive or can get the+source code.  And you must show them these terms so they know their+rights.++  We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++  Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software.  If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++  Finally, any free program is threatened constantly by software+patents.  We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary.  To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++  The precise terms and conditions for copying, distribution and+modification follow.++             GNU GENERAL PUBLIC LICENSE+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++  0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License.  The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language.  (Hereinafter, translation is included without limitation in+the term "modification".)  Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope.  The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++  1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++  2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++    a) You must cause the modified files to carry prominent notices+    stating that you changed the files and the date of any change.++    b) You must cause any work that you distribute or publish, that in+    whole or in part contains or is derived from the Program or any+    part thereof, to be licensed as a whole at no charge to all third+    parties under the terms of this License.++    c) If the modified program normally reads commands interactively+    when run, you must cause it, when started running for such+    interactive use in the most ordinary way, to print or display an+    announcement including an appropriate copyright notice and a+    notice that there is no warranty (or else, saying that you provide+    a warranty) and that users may redistribute the program under+    these conditions, and telling the user how to view a copy of this+    License.  (Exception: if the Program itself is interactive but+    does not normally print such an announcement, your work based on+    the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole.  If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works.  But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++  3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++    a) Accompany it with the complete corresponding machine-readable+    source code, which must be distributed under the terms of Sections+    1 and 2 above on a medium customarily used for software interchange; or,++    b) Accompany it with a written offer, valid for at least three+    years, to give any third party, for a charge no more than your+    cost of physically performing source distribution, a complete+    machine-readable copy of the corresponding source code, to be+    distributed under the terms of Sections 1 and 2 above on a medium+    customarily used for software interchange; or,++    c) Accompany it with the information you received as to the offer+    to distribute corresponding source code.  (This alternative is+    allowed only for noncommercial distribution and only if you+    received the program in object code or executable form with such+    an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it.  For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable.  However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++  4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License.  Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++  5. You are not required to accept this License, since you have not+signed it.  However, nothing else grants you permission to modify or+distribute the Program or its derivative works.  These actions are+prohibited by law if you do not accept this License.  Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++  6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions.  You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++  7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License.  If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all.  For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices.  Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++  8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded.  In such case, this License incorporates+the limitation as if written in the body of this License.++  9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time.  Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number.  If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation.  If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++  10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission.  For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this.  Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++                     NO WARRANTY++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++              END OF TERMS AND CONDITIONS++     How to Apply These Terms to Your New Programs++  If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++  To do so, attach the following notices to the program.  It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++    <one line to give the program's name and a brief idea of what it does.>+    Copyright (C) <year>  <name of author>++    This program is free software; you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation; either version 2 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License along+    with this program; if not, write to the Free Software Foundation, Inc.,+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++    Gnomovision version 69, Copyright (C) year name of author+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+    This is free software, and you are welcome to redistribute it+    under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License.  Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary.  Here is a sample; alter the names:++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program+  `Gnomovision' (which makes passes at compilers) written by James Hacker.++  <signature of Ty Coon>, 1 April 1989+  Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs.  If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library.  If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ src-bench/Main.hs view
@@ -0,0 +1,167 @@+{-# LANGUAGE BangPatterns      #-}+{-# LANGUAGE OverloadedStrings #-}++{-# LANGUAGE CApiFFI           #-}++{-# OPTIONS_GHC -Wall  #-}++-- |+-- Copyright: © 2020  Herbert Valerio Riedel+-- SPDX-License-Identifier: GPL-2.0-or-later+--+module Main+    ( main+    , xor32ByteString'ref+    , xor32ByteString'v3+    , xor32ByteString'v4+    ) where++import           Control.Exception        (assert)+import           Control.Monad+import           Criterion.Main+import           Data.Bits+import qualified Data.ByteString          as BS+import           Data.ByteString.Internal as BS+import qualified Data.ByteString.Short    as SBS+import           Data.Word                (Word32, Word8)+import           Foreign.ForeignPtr+import           Foreign.Ptr+import           Foreign.Storable+import           GHC.ByteOrder            (ByteOrder (..), targetByteOrder)++import qualified Data.XOR                 as IUT++main :: IO ()+main = defaultMain benches++benches :: [Benchmark]+benches =+    [ doGroup "4k"   bs4k+    , doGroup "4k1"  bs4k1+    , doGroup "4k2"  bs4k2+    , doGroup "4k3"  bs4k3+    , doGroup "32k"  bs32k+    , doGroup "256k" bs256k+    ]+  where+    doGroup label bs = let sbs = SBS.toShort bs in bgroup label+      [ bench "REF"      $ whnf (xor32ByteString'ref msk)       bs+      , bench "IUT"      $ whnf (IUT.xor32StrictByteString msk) bs+      , bench "IUT/SBS"  $ whnf (IUT.xor32ShortByteString msk) sbs+      , bench "v3"       $ whnf (xor32ByteString'v3 msk)        bs+      , bench "v4"       $ whnf (xor32ByteString'v4 msk)        bs+      , bench "REF 8bit" $ whnf (xor8StrictByteString'ref msk8) bs+      , bench "IUT 8bit" $ whnf (IUT.xor8StrictByteString msk8) bs+      ]++    {-# NOINLINE bs32k #-}+    !bs4k = BS.replicate (4*1024) 0x55+    !bs4k1 = BS.replicate (4*1024+1) 0x55+    !bs4k2 = BS.replicate (4*1024+2) 0x55+    !bs4k3 = BS.replicate (4*1024+3) 0x55+    !bs32k = BS.replicate (32*1024) 0x55+    !bs256k = BS.replicate (256*1024) 0x55++    {-# NOINLINE msk #-}+    msk = 0x12345678++    msk8 = 0x42++----------------------------------------------------------------------------++-- reference impl++{-# NOINLINE xor32ByteString'ref #-}+xor32ByteString'ref :: Word32 -> BS.ByteString -> BS.ByteString+xor32ByteString'ref 0    = id+xor32ByteString'ref msk0 = snd . BS.mapAccumL go msk0+  where+    go :: Word32 -> Word8 -> (Word32,Word8)+    go msk b = let b'   = fromIntegral msk' `xor` b+                   msk' = rotateL msk 8+               in b' `seq` (msk',b')+++{-# NOINLINE xor8StrictByteString'ref #-}+xor8StrictByteString'ref :: Word8 -> BS.ByteString -> BS.ByteString+xor8StrictByteString'ref 0    = id+xor8StrictByteString'ref msk0 = BS.map (xor msk0)++-- {-# NOINLINE xor32ByteString'v2 #-}+-- xor32ByteString'v2 :: Word32 -> BS.ByteString -> BS.ByteString+-- xor32ByteString'v2 msk0 = snd . BS.mapAccumL go mskstr+--   where+--     mskstr :: [Word8]+--     mskstr = cycle (map fromIntegral (tail (take 5 (iterate rotl8 msk0))))+--+--     rotl8 :: Word32 -> Word32+--     rotl8 = flip rotateL 8+--+--     go (x:xs) b = let !b' = xor x b in (xs,b')++{-# NOINLINE xor32ByteString'v3 #-}+xor32ByteString'v3 :: Word32 -> BS.ByteString -> BS.ByteString+xor32ByteString'v3 0 bs = bs+xor32ByteString'v3 _ bs | BS.null bs = bs+xor32ByteString'v3 msk0 (BS.PS x s l)+    = unsafeCreate l $ \p8 ->+        withForeignPtr x $ \f -> do+          memcpy p8 (f `plusPtr` s) (fromIntegral l)+          let p32 = castPtr p8 :: Ptr Word32+              l32 = l `quot` 4+              p32end = p32 `plusPtr` (l32*4)+          unless (alignPtr p32 4 == p32) $ fail "bytestring allocation not aligned"+          xor32PtrAligned msk0 p32 (l32*4)+          _ <- xor32PtrNonAligned msk0 (castPtr p32end) (l - (l32*4))+          return ()++{-# NOINLINE xor32ByteString'v4 #-}+xor32ByteString'v4 :: Word32 -> BS.ByteString -> BS.ByteString+xor32ByteString'v4  0 bs = bs+xor32ByteString'v4  _ bs | BS.null bs = bs+xor32ByteString'v4 msk0 (BS.PS x s l)+    = unsafeCreate l $ \p8 ->+        withForeignPtr x $ \f -> do+          memcpy p8 (f `plusPtr` s) (fromIntegral l)+          _ <- IUT.xor32CStringLen msk0 (castPtr p8,l)+          return ()++{-# INLINE xor32PtrNonAligned #-}+xor32PtrNonAligned :: Word32 -> Ptr Word8 -> Int -> IO Word32+xor32PtrNonAligned mask0 _ 0 = return mask0+xor32PtrNonAligned mask0 p0 n = go mask0 p0+  where+    p' = p0 `plusPtr` n+    go m p+      | p == p'   = return m+      | otherwise = do+          let m' = rotateL m 8+          xor8Ptr1 (fromIntegral m') p+          go m' (p `plusPtr` 1)++{-# INLINE xor32PtrAligned #-}+xor32PtrAligned :: Word32 -> Ptr Word32 -> Int -> IO ()+xor32PtrAligned _ _ 0 = return ()+xor32PtrAligned mask0be p0 n+  = assert (p0 == alignPtr p0 4 && n `rem` 4 == 0) $ go p0+  where+    p' = p0 `plusPtr` n+    go p+      | p == p'   = return ()+      | otherwise = do { xor32Ptr1 mask0 p; go (p `plusPtr` 4) }++    mask0 = case targetByteOrder of+              LittleEndian -> {- byteSwap32 -} mask0be+              BigEndian    -> mask0be++----------------------------------------------------------------------------++xor8Ptr1 :: Word8 -> Ptr Word8 -> IO ()+xor8Ptr1 msk ptr  = do { x <- peek ptr; poke ptr (xor msk x) }++-- xor16Ptr1 :: Word16 -> Ptr Word16 -> IO ()+-- xor16Ptr1 msk ptr = do { x <- peek ptr; poke ptr (xor msk x) }++xor32Ptr1 :: Word32 -> Ptr Word32 -> IO ()+xor32Ptr1 msk ptr = do { x <- peek ptr; poke ptr (xor msk x) }+
+ src-test/Main.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE Haskell2010       #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Copyright: © 2019-2020  Herbert Valerio Riedel+-- SPDX-License-Identifier: GPL-2.0-or-later+--+module Main (main)  where++import           Control.Monad+import           Data.Bits+import           Data.Int+import           Data.Monoid             (mempty)+import           Data.Word+import qualified Foreign.Marshal         as F+import qualified Foreign.Ptr             as F+import           Text.Printf             (printf)++import qualified Data.ByteString         as BS+import qualified Data.ByteString.Lazy    as BL+import qualified Data.ByteString.Short   as SBS++import qualified Test.QuickCheck.Monadic as QCM+import           Test.Tasty+import           Test.Tasty.HUnit+import           Test.Tasty.QuickCheck   as QC++import qualified Data.XOR                as IUT++main :: IO ()+main = defaultMain tests++tests :: TestTree+tests = testGroup "Tests"+  [ testGroup "hello"+    [ testCase "REF"             $ xor32StrictByteString'ref  0x37fa213d "\x7f\x9f\x4d\x51\x58" @?= "Hello"+    , testCase "S.ByteString"    $ IUT.xor32StrictByteString' 0x37fa213d "\x7f\x9f\x4d\x51\x58" @?= (0xfa213d37,"Hello")+    , testCase "L.ByteString"    $ IUT.xor32LazyByteString    0x37fa213d "\x7f\x9f\x4d\x51\x58" @?= "Hello"+    , testCase "ShortByteString" $ IUT.xor32ShortByteString   0x37fa213d "\x7f\x9f\x4d\x51\x58" @?= "Hello"+    ]++  , testGroup "empty"+    [ testProperty "S.ByteString"    $ \msk -> IUT.xor32StrictByteString msk mempty === Data.Monoid.mempty+    , testProperty "L.ByteString"    $ \msk -> IUT.xor32LazyByteString   msk mempty === mempty+    , testProperty "ShortByteString" $ \msk -> IUT.xor32ShortByteString  msk mempty === mempty+    ]++  , testGroup "zero-xor"+    [ testProperty "S.ByteString" $ \xs -> let bs = BS.pack xs in IUT.xor32StrictByteString 0 bs === bs+    , testProperty "L.ByteString" $ \xs -> let bs = BL.fromChunks (map BS.pack xs) in IUT.xor32LazyByteString 0 bs === BL.fromChunks [BS.pack (concat xs)]+    , testProperty "ShortByteString" $ \xs -> let bs = SBS.pack xs in IUT.xor32ShortByteString 0 bs === bs+    ]++  , testProperty "xor32Ptr" $ \msk lb len8 -> QCM.monadicIO $ do+       let bufsize, ofs, len :: Int+           bufsize = 2048+           ofs     = 512 + fromIntegral (lb :: Int8)+           len     = fromIntegral (len8 :: Word8)++       QCM.run $ F.allocaBytes bufsize $ \bufptr -> do++         origbuf <- BS.packCStringLen (bufptr, bufsize)++         let (origbufPre, tmp) = BS.splitAt ofs origbuf+             (origbufMid, origbufPost) = BS.splitAt len tmp++         _ <- IUT.xor32CStringLen msk (F.castPtr bufptr `F.plusPtr` ofs,len)+         newbufIut <- BS.packCStringLen (bufptr, bufsize)++         let newbufRef = BS.concat [origbufPre, xor32StrictByteString'ref msk origbufMid, origbufPost]++         unless (BS.length newbufRef == bufsize) $ fail "internal error"++         unless (newbufRef == newbufIut) $ do+           putStrLn $ show (msk,bufsize, ofs, len)+           putStrLn $ "orig " ++ concatMap (printf "%02x") (BS.unpack origbuf)+           putStrLn $ "ref  " ++ concatMap (printf "%02x") (BS.unpack newbufRef)+           putStrLn $ "iut  " ++ concatMap (printf "%02x") (BS.unpack newbufIut)++           forM_ (zip3 [0..] (BS.unpack newbufRef) (BS.unpack newbufIut)) $ \(j,ref8,iut8) ->+             unless (ref8 == iut8) $+               printf "%d (%d): %02x %02x\n" (j::Int) (j-ofs) ref8 iut8++         return $! newbufRef == newbufIut++  , testGroup "ref-vs-iut 32-bit"+    [ testProperty "S.ByteString" $ \xs msk ->+        let bs = BS.pack xs+        in IUT.xor32StrictByteString msk bs === xor32StrictByteString'ref msk bs+    , testProperty "L.ByteString" $ \xs msk ->+        let bs  = BL.fromChunks (map BS.pack xs)+            bs' = BS.pack (concat xs)+        in IUT.xor32LazyByteString msk bs === BL.fromStrict (xor32StrictByteString'ref msk bs')+    , testProperty "ShortByteString" $ \xs msk ->+        let bs = SBS.pack xs+        in IUT.xor32ShortByteString msk bs === xor32ShortByteString'ref msk bs+    ]++  , testGroup "ref-vs-iut 8-bit"+    [ testProperty "S.ByteString" $ \xs msk ->+        let bs = BS.pack xs+        in IUT.xor8StrictByteString msk bs === xor8StrictByteString'ref msk bs+    , testProperty "L.ByteString" $ \xs msk ->+        let bs  = BL.fromChunks (map BS.pack xs)+        in IUT.xor8LazyByteString msk bs === xor8LazyByteString'ref msk bs+    , testProperty "ShortByteString" $ \xs msk ->+        let bs = SBS.pack xs+        in IUT.xor8ShortByteString msk bs === xor8ShortByteString'ref msk bs+    ]++  , testGroup "self-inverse"+    [ testProperty "S.ByteString" $ \xs msk ->+        let bs = BS.pack xs+        in IUT.xor32StrictByteString msk (IUT.xor32StrictByteString msk bs) === bs+    , testProperty "L.ByteString" $ \xs msk ->+        let bs  = BL.fromChunks (map BS.pack xs)+            bs' = BL.fromChunks [BS.pack (concat xs)]+        in IUT.xor32LazyByteString msk (IUT.xor32LazyByteString msk bs) === bs'+    , testProperty "ShortByteString" $ \xs msk ->+        let bs = SBS.pack xs+        in IUT.xor32ShortByteString msk (IUT.xor32ShortByteString msk bs) === bs+    ]+  ]++xor32StrictByteString'ref :: Word32 -> BS.ByteString -> BS.ByteString+xor32StrictByteString'ref 0    = id+xor32StrictByteString'ref msk0 = snd . BS.mapAccumL go msk0+  where+    go :: Word32 -> Word8 -> (Word32,Word8)+    go msk b = let b'   = fromIntegral msk' `xor` b+                   msk' = rotateL msk 8+               in b' `seq` (msk',b')++xor8StrictByteString'ref :: Word8 -> BS.ByteString -> BS.ByteString+xor8StrictByteString'ref 0    = id+xor8StrictByteString'ref msk0 = BS.map (xor msk0)++liftSBS :: (t -> BS.ByteString -> BS.ByteString) -> t -> SBS.ShortByteString -> SBS.ShortByteString+liftSBS op = \msk -> SBS.toShort . op msk . SBS.fromShort++liftBL :: (t -> BS.ByteString -> BS.ByteString) -> t -> BL.ByteString -> BL.ByteString+liftBL op = \msk -> BL.fromStrict . op msk . BL.toStrict++xor32ShortByteString'ref :: Word32 -> SBS.ShortByteString -> SBS.ShortByteString+xor32ShortByteString'ref = liftSBS xor32StrictByteString'ref++xor8ShortByteString'ref :: Word8 -> SBS.ShortByteString -> SBS.ShortByteString+xor8ShortByteString'ref = liftSBS xor8StrictByteString'ref++xor8LazyByteString'ref :: Word8 -> BL.ByteString -> BL.ByteString+xor8LazyByteString'ref = liftBL xor8StrictByteString'ref
+ src/Data/XOR.hs view
@@ -0,0 +1,373 @@+{-# LANGUAGE BangPatterns  #-}+{-# LANGUAGE Haskell2010   #-}+{-# LANGUAGE MagicHash     #-}+{-# LANGUAGE UnboxedTuples #-}++{-# LANGUAGE Trustworthy   #-}++-- |+-- Copyright: © 2020  Herbert Valerio Riedel+-- SPDX-License-Identifier: GPL-2.0-or-later+--+-- Apply XOR-masks to 'BS.ByteString's and memory regions.+--+module Data.XOR+    ( -- * Apply 32-bit XOR mask+      xor32StrictByteString+    , xor32StrictByteString'+    , xor32LazyByteString+    , xor32ShortByteString+    , xor32CStringLen++      -- * Apply 8-bit XOR mask+    , xor8StrictByteString+    , xor8LazyByteString+    , xor8ShortByteString+    , xor8CStringLen++    ) where++-- base+import           Control.Exception              (assert)+import           Control.Monad                  (void)+import           Control.Monad.ST               (ST, runST)+import           Data.Bits+import           Data.Tuple                     (swap)+import           Endianness                     (ByteOrder (..), Word32, Word8, byteSwap32,+                                                 targetByteOrder)+import           Foreign.C                      (CStringLen)+import           Foreign.ForeignPtr             (withForeignPtr)+import           Foreign.Ptr                    (Ptr, alignPtr, castPtr, minusPtr, plusPtr)+import           Foreign.Storable               (peek, poke)+import           System.IO.Unsafe               (unsafeDupablePerformIO)++import qualified GHC.Exts                       as X+import qualified GHC.ST                         as X+import qualified GHC.Word                       as X++-- bytestring+import qualified Data.ByteString                as BS+import           Data.ByteString.Internal       (mallocByteString, memcpy)+import qualified Data.ByteString.Internal       as BS (ByteString (..))+import qualified Data.ByteString.Lazy.Internal  as BL (ByteString (..))+import qualified Data.ByteString.Short          as SBS+import           Data.ByteString.Short.Internal (ShortByteString (SBS))++----------------------------------------------------------------------------++{- high-level reference impl++-- about 6-7 times slower+xor32StrictByteString'ref :: Word32 -> BS.ByteString -> BS.ByteString+xor32StrictByteString'ref 0    = id+xor32StrictByteString'ref msk0 = snd . BS.mapAccumL go msk0+  where+    go :: Word32 -> Word8 -> (Word32,Word8)+    go msk b = let b'   = fromIntegral msk' `xor` b+                   msk' = rotateL msk 8+               in b' `seq` (msk',b')++-- about 3 times slower+xor8StrictByteString'ref :: Word8 -> BS.ByteString -> BS.ByteString+xor8StrictByteString'ref 0    = id+xor8StrictByteString'ref msk0 = BS.map (xor msk0)++-}++-- | Apply 32-bit XOR mask (considered as four octets in big-endian order) to 'BS.ByteString'.+--+-- >>> xor32StrictByteString 0x37fa213d "\x7f\x9f\x4d\x51\x58"+-- "Hello"+--+-- In other words, the 32-bit word @0x37fa213d@ is taken as the infinite series of octets @('cycle' [0x37,0xfa,0x21,0x3d])@ and 'xor'ed with the respective octets from the input 'BS.ByteString'.+--+-- The 'xor' laws give rise to the following laws:+--+-- prop> xor32StrictByteString m (xor32StrictByteString m x) == x+--+-- prop> xor32StrictByteString 0 x == x+--+-- prop> xor32StrictByteString m (xor32StrictByteString n x) == xor32StrictByteString (m `xor` n) x+--+-- This function is semantically equivalent to the (less efficient) implementation shown below+--+-- > xor32StrictByteString'ref :: Word32 -> BS.ByteString -> BS.ByteString+-- > xor32StrictByteString'ref 0    = id+-- > xor32StrictByteString'ref msk0 = snd . BS.mapAccumL go msk0+-- >   where+-- >     go :: Word32 -> Word8 -> (Word32,Word8)+-- >     go msk b = let b'   = fromIntegral (msk' .&. 0xff) `xor` b+-- >                    msk' = rotateL msk 8+-- >                in (msk',b')+--+-- The 'xor32StrictByteString' implementation is about 6-7 times faster than the naive implementation above.+xor32StrictByteString :: Word32 -> BS.ByteString -> BS.ByteString+xor32StrictByteString 0 bs   = bs+xor32StrictByteString _ bs   | BS.null bs = bs+xor32StrictByteString msk bs = fst (xor32StrictByteString'' msk bs)++-- | Convenience version of 'xor32StrictByteString' which also returns the rotated XOR-mask useful for chained masking.+--+-- >>> xor32StrictByteString' 0x37fa213d "\x7f\x9f\x4d\x51\x58"+-- (0xfa213d37,"Hello")+--+xor32StrictByteString' :: Word32 -> BS.ByteString -> (Word32,BS.ByteString)+xor32StrictByteString' 0 bs   = (0,bs)+xor32StrictByteString' msk bs | BS.null bs = (msk,bs)+xor32StrictByteString' msk bs = swap (xor32StrictByteString'' msk bs)++-- | Variant of 'xor32StrictByteString' for masking lazy 'BL.ByteString's.+--+-- >>> xor32LazyByteString 0x37fa213d "\x7f\x9f\x4d\x51\x58"+-- "Hello"+--+xor32LazyByteString :: Word32 -> BL.ByteString -> BL.ByteString+xor32LazyByteString 0 = id+xor32LazyByteString msk0 = go msk0+  where+    go _ BL.Empty = BL.Empty+    go msk (BL.Chunk x xs) = BL.Chunk x' (go msk' xs)+      where+        (x',msk') = xor32StrictByteString'' msk x++{-# INLINE xor32StrictByteString'' #-}+-- internal+xor32StrictByteString'' :: Word32 -> BS.ByteString -> (BS.ByteString,Word32)+xor32StrictByteString'' msk0 (BS.PS x s l)+    = unsafeCreate' l $ \p8 ->+        withForeignPtr x $ \f -> do+          memcpy p8 (f `plusPtr` s) (fromIntegral l)++          case remPtr p8 4 of+            0 -> do+              let trailer = l `rem` 4+                  lbytes = l - trailer+              xor32PtrAligned msk0 (castPtr p8) lbytes+              xor32PtrNonAligned msk0 (p8 `plusPtr` lbytes) trailer+            _ ->+              -- misaligned bytestring...+              --+              -- This should not happen, as newly allocated+              -- bytestrings ought to be word-aligned; but if the+              -- impossible does happen we have a semantically sound+              -- codepath to jump to...+              xor32Ptr msk0 p8 l++++-- | Apply 32-bit XOR mask (considered as four octets in big-endian order) to 'SBS.ShortByteString'. See also 'xor32StrictByteString'.+--+-- >>> xor32ShortByteString 0x37fa213d "\x7f\x9f\x4d\x51\x58"+-- "Hello"+--+xor32ShortByteString :: Word32 -> SBS.ShortByteString -> SBS.ShortByteString+xor32ShortByteString 0 sbs = sbs+xor32ShortByteString _ sbs | SBS.null sbs = sbs+xor32ShortByteString mask0be sbs = runST $ do+    tmp <- newSBS len++    let loop4 i+          | i == len4  = return ()+          | otherwise  = writeWord32Array tmp i (indexWord32Array sbs i `xor` mask0) >> loop4 (i+1)++    loop4 0++    let writeXor8 ofs msk8 = writeWord8Array tmp ofs (indexWord8Array sbs ofs `xor` msk8)++    case len1 of+      0 -> return ()+      1 -> do+        writeXor8 (len-1) (fromIntegral (shiftR mask0be 24))+      2 -> do+        writeXor8 (len-2) (fromIntegral (shiftR mask0be 24))+        writeXor8 (len-1) (fromIntegral (shiftR mask0be 16))+      3 -> do+        writeXor8 (len-3) (fromIntegral (shiftR mask0be 24))+        writeXor8 (len-2) (fromIntegral (shiftR mask0be 16))+        writeXor8 (len-1) (fromIntegral (shiftR mask0be  8))+      _ -> undefined -- impossible++    unsafeFreezeSBS tmp+  where+    len = SBS.length sbs+    (len4,len1) = quotRem len 4++    mask0 = case targetByteOrder of+              LittleEndian -> byteSwap32 mask0be+              BigEndian    -> mask0be+++{-# INLINEABLE xor32CStringLen #-}+-- | Apply 32-bit XOR mask (considered as four octets in big-endian order) to memory region expressed as base-pointer and size. The returned value is the input mask rotated by the word-size remained of the memory region size (useful for chained xor-masking of multiple memory-fragments).+xor32CStringLen :: Word32 -> CStringLen -> IO Word32+xor32CStringLen m (p,l) = xor32Ptr m (castPtr p) l++{-# INLINEABLE xor32Ptr #-}+xor32Ptr :: Word32 -> Ptr Word8 -> Int -> IO Word32+xor32Ptr 0      !_  !_ = return 0+xor32Ptr !mask0 !_   0 = return mask0+xor32Ptr !mask0 !p0 !n+  | n < 4 = xor32PtrNonAligned mask0 p0 n+  | n < 0 = fail "xor32Ptr: negative size argument not supported"+xor32Ptr !mask0 !p0 !n+  | assert (p0 <= p1 && p1 <= p2 && p2 <= p3 && n0 < 4 && n2 < 4) False = undefined -- assert invariants+  | n1 == 0 = xor32PtrNonAligned mask0 p0 n+  | n0 == 0 = do+      xor32PtrAligned    mask0 p1 n1+      xor32PtrNonAligned mask0 p2 n2+  | otherwise = do+      mask1 <- xor32PtrNonAligned mask0 p0 n0+      xor32PtrAligned    mask1 p1 n1+      xor32PtrNonAligned mask1 p2 n2+  where+    -- Invariants: p0 <= p1 <= p2 <= p3+    --             0  <= n0  < 4+    --             0  <= n1+    --             0  <= n2  < 4+    --             n  == n0+n1+n2 >= 4+    p1 = castPtr (alignPtr p0 d)+    p2 = alignPtrDown p3 d+    p3 = plusPtr p0 n+    d  = 4++    n0 = p1 `minusPtr` p0+    n1 = p2 `minusPtr` p1+    n2 = p3 `minusPtr` p2++-- internal+xor32PtrNonAligned :: Word32 -> Ptr Word8 -> Int -> IO Word32+xor32PtrNonAligned mask0 _ 0 = return mask0+xor32PtrNonAligned mask0 p 1 = do+  let mask1 = rotateL mask0 8+  xor8Ptr1 (fromIntegral mask1) p+  return mask1+xor32PtrNonAligned mask0 p 2 = do+  xor8Ptr1 (fromIntegral (mask0 `shiftR` 24)) p+  let mask1 = mask0 `rotateL` 16+  xor8Ptr1 (fromIntegral mask1) (p `plusPtr` 1)+  return mask1+xor32PtrNonAligned mask0 p 3 = do+  xor8Ptr1 (fromIntegral (mask0 `shiftR` 24)) p+  xor8Ptr1 (fromIntegral (mask0 `shiftR` 16)) (p `plusPtr` 1)+  let mask1 = mask0 `rotateL` 24+  xor8Ptr1 (fromIntegral mask1) (p `plusPtr` 2)+  return mask1+xor32PtrNonAligned mask0 p0 n = go mask0 p0+  where+    p' = p0 `plusPtr` n+    go m p+      | p == p'   = return m+      | otherwise = do+          let m' = rotateL m 8+          xor8Ptr1 (fromIntegral m') p+          go m' (p `plusPtr` 1)++-- internal+xor32PtrAligned :: Word32 -> Ptr Word32 -> Int -> IO ()+xor32PtrAligned _ _ 0 = return ()+xor32PtrAligned mask0be p0 n+  = assert (p0 `remPtr` 4 == 0 && n `rem` 4 == 0) $ go p0+  where+    p' = p0 `plusPtr` n+    go p+      | p == p'   = return ()+      | otherwise = do { xor32Ptr1 mask0 p; go (p `plusPtr` 4) }++    mask0 = case targetByteOrder of+              LittleEndian -> byteSwap32 mask0be+              BigEndian    -> mask0be++----------------------------------------------------------------------------++remPtr :: Ptr a -> Int -> Int+remPtr (X.Ptr x) (X.I# d) = X.I# (X.remAddr# x d)++alignPtrDown :: Ptr a -> Int -> Ptr a+alignPtrDown p i+  = case remPtr p i of+      0 -> p+      n -> plusPtr p (negate n)++xor8Ptr1 :: Word8 -> Ptr Word8 -> IO ()+xor8Ptr1 msk ptr  = do { x <- peek ptr; poke ptr (xor msk x) }++-- xor16Ptr1 :: Word16 -> Ptr Word16 -> IO ()+-- xor16Ptr1 msk ptr = do { x <- peek ptr; poke ptr (xor msk x) }++xor32Ptr1 :: Word32 -> Ptr Word32 -> IO ()+xor32Ptr1 msk ptr = do { x <- peek ptr; poke ptr (xor msk x) }++{-# INLINE unsafeCreate' #-}+unsafeCreate' :: Int -> (Ptr Word8 -> IO a) -> (BS.ByteString, a)+unsafeCreate' l0 f0 = unsafeDupablePerformIO (create' l0 f0)+  where+    {-# INLINE create' #-}+    create' :: Int -> (Ptr Word8 -> IO a) -> IO (BS.ByteString, a)+    create' l f = do+        fp <- mallocByteString l+        res <- withForeignPtr fp $ \p -> f p+        return (BS.PS fp 0 l, res)++----------------------------------------------------------------------------+-- single octet masks -- trivially mapped to 32-bit versions++expandW8ToW32 :: Word8 -> Word32+expandW8ToW32 x = x' .|. (x' `shiftL` 16)+  where+    x' = fromIntegral x .|. (fromIntegral x `shiftL` 8)+++-- | Apply 8-bit XOR mask to each octet of a 'BS.ByteString'.+--+-- >>> xor8StrictByteString 0x20 "Hello"+-- "hELLO"+--+-- This function is a faster implementation of the semantically equivalent function shown below:+--+-- > xor8StrictByteString'ref :: Word8 -> BS.ByteString -> BS.ByteString+-- > xor8StrictByteString'ref 0    = id+-- > xor8StrictByteString'ref msk0 = BS.map (xor msk0)+--+xor8StrictByteString :: Word8 -> BS.ByteString -> BS.ByteString+xor8StrictByteString x = xor32StrictByteString (expandW8ToW32 x)++-- | Apply 8-bit XOR mask to each octet of a lazy 'BL.ByteString'.+--+-- See also 'xor8StrictByteString'+xor8LazyByteString :: Word8 -> BL.ByteString -> BL.ByteString+xor8LazyByteString x = xor32LazyByteString (expandW8ToW32 x)++-- | Apply 8-bit XOR mask to each octet of a 'SBS.ShortByteString'.+--+-- See also 'xor8StrictByteString'+xor8ShortByteString :: Word8 -> SBS.ShortByteString -> SBS.ShortByteString+xor8ShortByteString x = xor32ShortByteString (expandW8ToW32 x)++-- | Apply 8-bit XOR mask to each octet of a memory region expressed as start address and length in bytes.+--+-- See also 'xor8StrictByteString'+xor8CStringLen :: Word8 -> CStringLen -> IO ()+xor8CStringLen x (p,l) = void (xor32Ptr (expandW8ToW32 x) (castPtr p) l)++----------------------------------------------------------------------------+-- The missing mutable ShortByteString abstraction++data MShortByteString s = MSBS (X.MutableByteArray# s)++newSBS :: Int -> ST s (MShortByteString s)+newSBS (X.I# len#) = X.ST $ \s0 -> case X.newByteArray# len# s0 of (# s, mba# #) -> (# s, MSBS mba# #)++indexWord8Array :: ShortByteString -> Int -> Word8+indexWord8Array (SBS ba#) (X.I# i#) = X.W8# (X.indexWord8Array# ba# i#)++writeWord8Array :: MShortByteString s -> Int -> Word8 -> ST s ()+writeWord8Array (MSBS mba#) (X.I# i#) (X.W8# w#) = X.ST $ \s0 -> case X.writeWord8Array# mba# i# w# s0 of s -> (# s, () #)++indexWord32Array :: ShortByteString -> Int -> Word32+indexWord32Array (SBS ba#) (X.I# i#) = X.W32# (X.indexWord32Array# ba# i#)++writeWord32Array :: MShortByteString s -> Int -> Word32 -> ST s ()+writeWord32Array (MSBS mba#) (X.I# i#) (X.W32# w#) = X.ST $ \s0 -> case X.writeWord32Array# mba# i# w# s0 of s -> (# s, () #)++unsafeFreezeSBS :: MShortByteString s -> ST s ShortByteString+unsafeFreezeSBS (MSBS mba#) = X.ST $ \s0 -> case X.unsafeFreezeByteArray# mba# s0 of (# s, ba# #) -> (# s, SBS ba# #)
+ src/Endianness.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE CPP         #-}+{-# LANGUAGE Haskell2010 #-}++-- |+-- Copyright: © 2019-2020  Herbert Valerio Riedel+-- SPDX-License-Identifier: GPL-2.0-or-later+--+module Endianness+    ( Word8, Word16, Word32, Word64+    , ByteOrder(LittleEndian,BigEndian), targetByteOrder++    , byteSwap16+    , byteSwap32+    , byteSwap64++    , pokeWord16be+    , pokeWord32be+    , pokeWord64be+    , peekWord16be+    , peekWord32be+    , peekWord64be++    ) where++import           Data.Word        (Word16, Word32, Word64, Word8)+import           Foreign.Ptr+import           Foreign.Storable+import           GHC.ByteOrder    (ByteOrder (..), targetByteOrder)++#if MIN_VERSION_base(4,7,0)+import           Data.Word        (byteSwap16, byteSwap32, byteSwap64)+#else+import           Data.Bits++-- supply missing byteSwap operations++byteSwap16 :: Word16 -> Word16+byteSwap16 = (`rotateL` 8)++byteSwap32 :: Word32 -> Word32+byteSwap32 x+  = (x                  `shiftR` 24)  .|.+    ((x .&. 0x00ff0000) `shiftR`  8)  .|.+    ((x .&. 0x0000ff00) `shiftL`  8)  .|.+    (x                  `shiftL` 24)++byteSwap64 :: Word64 -> Word64+byteSwap64 x = xh .|. (xl `shiftL` 32)+  where+    xl = fromIntegral (byteSwap32 (fromIntegral x))+    xh = fromIntegral (byteSwap32 (fromIntegral (x `shiftR` 32)))+#endif++pokeWord16be :: Ptr Word16 -> Word16 -> IO ()+pokeWord16be = case targetByteOrder of+  BigEndian    -> poke+  LittleEndian -> \p w -> poke p (byteSwap16 w)++pokeWord32be :: Ptr Word32 -> Word32 -> IO ()+pokeWord32be = case targetByteOrder of+  BigEndian    -> poke+  LittleEndian -> \p w -> poke p (byteSwap32 w)++pokeWord64be :: Ptr Word64 -> Word64 -> IO ()+pokeWord64be = case targetByteOrder of+  BigEndian    -> poke+  LittleEndian -> \p w -> poke p (byteSwap64 w)+++peekWord16be :: Ptr Word16 -> IO Word16+peekWord16be = case targetByteOrder of+  BigEndian    -> peek+  LittleEndian -> \p -> fmap byteSwap16 (peek p)++peekWord32be :: Ptr Word32 -> IO Word32+peekWord32be = case targetByteOrder of+  BigEndian    -> peek+  LittleEndian -> \p -> fmap byteSwap32 (peek p)++peekWord64be :: Ptr Word64 -> IO Word64+peekWord64be = case targetByteOrder of+  BigEndian    -> peek+  LittleEndian -> \p -> fmap byteSwap64 (peek p)
+ xor.cabal view
@@ -0,0 +1,89 @@+cabal-version:       2.2+name:                xor+version:             0.0.1.0++category:            Data, Codec+author:              Herbert Valerio Riedel+maintainer:          hvr@gnu.org+bug-reports:         https://github.com/hvr/xor/issues++copyright:           © 2020  Herbert Valerio Riedel+license:             GPL-2.0-or-later+license-file:        LICENSE.GPLv2++synopsis: Efficient XOR masking+description:+  This package provides efficient implementations of routines for applying <https://en.wikipedia.org/wiki/Bitwise_operation#XOR bitwise XOR> masks to binary data.+  .+  The currently supported operations (see "Data.XOR" API documentation for more details) are applying+  .+  * 8-bit  wide XOR masks or+  * 32-bit wide XOR masks+  .+  to binary data represented by+  .+  * Strict @ByteString@s,+  * Lazy @ByteString@s,+  * @ShortByteString@s (i.e. @ByteArray#@s), or+  * @CStringLen@ (i.e. @Ptr@s).+  .+  The performance is comparable to portable ISO C99 implementations but this library is implemented as pure Haskell and is thereby compatible with compile targets such as <https://github.com/ghcjs/ghcjs GHCJS>.++source-repository head+  type:     git+  location: https://github.com/hvr/xor.git++common defaults+  default-language:    Haskell2010+  other-extensions:    CPP+                       BangPatterns+                       UnboxedTuples+                       MagicHash++  build-depends:+    , base            >= 4.5 && < 4.15+    , bytestring     ^>= 0.10.4+    , ghc-byteorder  ^>= 4.11.0.0++  ghc-options: -Wall++library+  import: defaults++  hs-source-dirs: src+  exposed-modules:+    Data.XOR++  other-modules:+    Endianness++benchmark bench+  import: defaults++  type: exitcode-stdio-1.0++  hs-source-dirs:      src-bench+  main-is:             Main.hs++  build-depends:+    , xor+      -- dependencies specific to this component+    , criterion ^>= 1.5.6++test-suite test+  import: defaults++  type: exitcode-stdio-1.0++  hs-source-dirs:      src-test+  main-is:             Main.hs++  build-depends:++  build-depends:+    , xor+      -- dependencies specific to this component+    , tasty            ^>= 1.2.3+    , tasty-hunit      ^>= 0.10+    , tasty-quickcheck ^>= 0.10+    , QuickCheck       ^>= 2.14