WringTwistree-0.0.1.0: src/Cryptography/Twistree.hs
module Cryptography.Twistree
( Twistree
, SBox -- reexported for use in Cryptanalysis.hs
, sboxes -- "
, sameBitcount -- "
, compress -- "
, linearSbox -- "
, linearTwistree -- Only for cryptanalysis and testing
, parListDeal
, keyedTwistree
, hash
) where
{-
This hash function uses a double-tree construction, as shown in this drawing:
2
-------------------+-------------------
----------------+--------------- |
--------+-------- -------+--------- |
----+---- ----+---- ----+---- ----+---- --+---
--+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- |
-+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- |
4 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
--+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- --+-- |
------+------ ------+------ ------+------ ------+------ |
------------------+------------------ -----+-----
---------------------+--------------------
3
2 3
-+-
H
* A block of the message to be hashed, including padding at the end.
4 Binary representation of exp(4). One is used in the binary tree and the
other in the ternary tree.
3 Output of the ternary tree
2 Output of the binary tree
H Final hash output
-}
import Cryptography.WringTwistree.Compress
import Cryptography.WringTwistree.Blockize
import Cryptography.WringTwistree.Sboxes
import Control.Parallel
import Control.Parallel.Strategies
import Data.List (transpose)
import Data.List.Split
import Data.Word
import Data.Bits
import Data.Array.Unboxed
import Data.Foldable (foldl')
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.Vector.Unboxed as V
data Twistree = Twistree
{ sbox :: SBox
} deriving Show
deal n = transpose . chunksOf n -- to be used as a parallel strategy
parListDeal :: Int -> Strategy a -> Strategy [a]
parListDeal n strat xs
| n <= 1 = evalList strat xs
| otherwise = concat `fmap` parList (evalList strat) (deal n xs)
compressPairs :: SBox -> [V.Vector Word8] -> [V.Vector Word8]
compressPairs _ [] = []
compressPairs _ [x] = [x]
compressPairs sbox (x:y:xs) = pseq (compress2 sbox x y 0) $
((compress2 sbox x y 0) : compressPairs sbox xs)
hashPairs :: SBox -> [V.Vector Word8] -> V.Vector Word8
hashPairs _ [] = undefined -- can't happen, there's always at least exp(4)
hashPairs _ [x] = x
hashPairs sbox x = par (compressPairs sbox x) $
hashPairs sbox (compressPairs sbox x)
compressTriples :: SBox -> [V.Vector Word8] -> [V.Vector Word8]
compressTriples _ [] = []
compressTriples _ [x] = [x]
compressTriples sbox [x,y] = [compress2 sbox x y 1]
compressTriples sbox (x:y:z:xs) = pseq (compress3 sbox x y z 1) $
((compress3 sbox x y z 1) : compressTriples sbox xs)
hashTriples :: SBox -> [V.Vector Word8] -> V.Vector Word8
hashTriples _ [] = undefined -- can't happen, there's always at least exp(4)
hashTriples _ [x] = x
hashTriples sbox x = par (compressTriples sbox x) $
hashTriples sbox (compressTriples sbox x)
-- | A `Twistree` with linear `SBox`. Used only for testing and cryptanalysis.
linearTwistree = Twistree linearSbox
-- | Creates a `Twistree` with the given key.
-- To convert a `String` to a `ByteString`, put @- utf8-string@ in your
-- package.yaml dependencies, @import Data.ByteString.UTF8@, and use
-- `fromString`.
keyedTwistree :: B.ByteString -> Twistree
keyedTwistree key = Twistree sbox where
sbox = sboxes key
hash
:: Twistree -- ^ The `Twistree` made with the key to hash with
-> BL.ByteString -- ^ The text to be hashed. It's a lazy `ByteString`,
-- so you can hash a file bigger than RAM.
-> V.Vector Word8 -- ^ The returned hash, 32 bytes.
hash twistree stream = par blocks $ par h2 $ par h3 $
compress2 (sbox twistree) h2 h3 2 where
blocks = blockize stream
h2 = hashPairs (sbox twistree) (exp4_2adic : blocks)
h3 = hashTriples (sbox twistree) (exp4_base2 : blocks)