module Cryptography.WringTwistree.Blockize
  ( exp4_2adic
  , exp4_base2
  , binaryStr
  , blockize
  ) where

{- This module is used in Twistree.
 - It splits a lazy ByteString into blocks of 32 bytes, padding the last one
 - with 0,1,2,... .
 -}

import Data.Bits
import Data.Word
import Data.Array.Unboxed
import Data.List.Split (chunksOf)
import qualified Data.ByteString.Lazy as BL
import Cryptography.WringTwistree.Compress
import Text.Printf
import qualified Data.Vector.Unboxed as V

{-
$ stack ghci --package padic
> import Math.NumberTheory.Padic
> :set -XDataKinds
> exp 4 :: Q' 2 280 -- add 24 extra bits so that bit 255 is correct
11011110 00010001 11110010
00001001 00010100 10010100 01111111 11111110 01011100 01101101 11001010
00110100 10010101 00111100 10100101 11101110 01000101 10110110 00010111
11100000 10011100 01111111 10100011 01111111 00001000 11100000 00011000
11101011 00111010 00011010 01110010 00111000 10001110 01000001 01001101.0
-}

-- e⁴, in two binary representations, is prepended to the
-- blocks being hashed, so that if the message is only one block,
-- two different compressed blocks are combined at the end.
exp4_2adic :: V.Vector Word8
exp4_2adic :: Vector Word8
exp4_2adic = Int -> [Word8] -> Vector Word8
forall a. Unbox a => Int -> [a] -> Vector a
V.fromListN Int
32
  [ Word8
0x4d, Word8
0x41, Word8
0x8e, Word8
0x38, Word8
0x72, Word8
0x1a, Word8
0x3a, Word8
0xeb
  , Word8
0x18, Word8
0xe0, Word8
0x08, Word8
0x7f, Word8
0xa3, Word8
0x7f, Word8
0x9c, Word8
0xe0
  , Word8
0x17, Word8
0xb6, Word8
0x45, Word8
0xee, Word8
0xa5, Word8
0x3c, Word8
0x95, Word8
0x34
  , Word8
0xca, Word8
0x6d, Word8
0x5c, Word8
0xfe, Word8
0x7f, Word8
0x94, Word8
0x14, Word8
0x09
  ]

exp4_base2 :: V.Vector Word8
exp4_base2 :: Vector Word8
exp4_base2 = Int -> [Word8] -> Vector Word8
forall a. Unbox a => Int -> [a] -> Vector a
V.fromListN Int
32
  [ Word8
0xe8, Word8
0xa7, Word8
0x66, Word8
0xce, Word8
0x5b, Word8
0x2e, Word8
0x8a, Word8
0x39
  , Word8
0x4b, Word8
0xb7, Word8
0x89, Word8
0x2e, Word8
0x0c, Word8
0xd5, Word8
0x94, Word8
0x05
  , Word8
0xda, Word8
0x72, Word8
0x7b, Word8
0x72, Word8
0xfb, Word8
0x77, Word8
0xda, Word8
0x1a
  , Word8
0xcf, Word8
0xb0, Word8
0x74, Word8
0x4e, Word8
0x5c, Word8
0x20, Word8
0x99, Word8
0x36
  ]

{-
                 01 =    1/1   = 01
                 04 =    4/1   = 04
                 08 =   16/2   = 08
...5555555555555560 =   64/6   = 0a.aaaaaaaaaaaaaa...
...5555555555555560 =  256/24  = 0a.aaaaaaaaaaaaaa...
...7777777777777780 = 1024/120 = 08.88888888888888...
...a4fa4fa4fa4fa500 = 4096/720 = 05.b05b05b05b05b0...
   ----------------      ...     -----------------
...eb3a1a72388e414d =  exp(4)  = 36.99205c4e74b0cf...
-}

binaryStr :: [Word8] -> String
binaryStr :: [Word8] -> [Char]
binaryStr [] = [Char]
""
binaryStr (Word8
a:[Word8]
as) = ([Char] -> Word8 -> [Char]
forall r. PrintfType r => [Char] -> r
printf [Char]
"%08b " Word8
a)[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++([Word8] -> [Char]
binaryStr [Word8]
as)

pad :: BL.ByteString -> [Word8]
pad :: ByteString -> [Word8]
pad ByteString
bs = (ByteString -> [Word8]
BL.unpack ByteString
bs) [Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ [Word8
0..(Word8
forall a. Integral a => a
blockSizeWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
1)]

-- Breaks into blocks of 32 bytes, padding the last one to 32 bytes.
-- If the last block is already 32 bytes, adds another block of 32 bytes.
blockize :: BL.ByteString -> [V.Vector Word8]
blockize :: ByteString -> [Vector Word8]
blockize ByteString
bs = ([Word8] -> Vector Word8) -> [[Word8]] -> [Vector Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [Word8] -> Vector Word8
forall a. Unbox a => Int -> [a] -> Vector a
V.fromListN Int
forall a. Integral a => a
blockSize) ([[Word8]] -> [Vector Word8]) -> [[Word8]] -> [Vector Word8]
forall a b. (a -> b) -> a -> b
$ ([Word8] -> Bool) -> [[Word8]] -> [[Word8]]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
forall a. Integral a => a
blockSize) (Int -> Bool) -> ([Word8] -> Int) -> [Word8] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length) ([[Word8]] -> [[Word8]]) -> [[Word8]] -> [[Word8]]
forall a b. (a -> b) -> a -> b
$
  Int -> [Word8] -> [[Word8]]
forall e. Int -> [e] -> [[e]]
chunksOf Int
forall a. Integral a => a
blockSize ([Word8] -> [[Word8]]) -> [Word8] -> [[Word8]]
forall a b. (a -> b) -> a -> b
$ ByteString -> [Word8]
pad ByteString
bs