-- RSA LAB

import Data.Char

type Message = [Int]

stringToMessage::String -> Message
stringToMessage = map ord

messageToString::Message -> String
messageToString = map chr

pad::Int -> Message -> Message
pad bsize msg = 
	let msgSize = length msg in
	let gap = mod msgSize bsize in
	let padding = bsize - gap in
	msg ++ [padding | _ <- [1..padding] ]

unpad::Message -> Message
unpad m = reverse $ subunpad (-1) [] m

-- First arg s
-- -1 > Travel until reaching end if 
-- 0 > Pad removed
-- n > Still n items to remove
subunpad::Int -> Message -> Message -> Message
subunpad _ [] [] = []
subunpad (-1) ys (s:[]) = subunpad (s - 1) ys []
subunpad (-1) ys (x:xs) = subunpad (-1) (x:ys) xs
subunpad 0 ys _ = ys
subunpad s (y:ys) _ = subunpad (s - 1) ys []

groupBytes::Message -> Int
groupBytes = subgroupBytes 1 0

-- First arg : pow > Contains 256^n where n is the number of recursive calls
-- Second arg : acc > contains the result of the block
subgroupBytes::Int -> Int -> Message -> Int
subgroupBytes _ acc [] = acc
subgroupBytes pow acc (c:msg) = subgroupBytes (pow * 256) (acc + c * pow) msg

ungroupBytes::Int -> Message
ungroupBytes 0 = []
ungroupBytes n = (mod n 256):ungroupBytes (div n 256)

groupN::Int -> Message -> [Message]
groupN _ [] = []
groupN bsize s = (take bsize s):groupN bsize (drop bsize s)

makeBlocks::Int -> Message -> Message
makeBlocks bsize msg = map groupBytes (groupN bsize msg)

splitBlocks::Message -> Message
splitBlocks msg = concat (map ungroupBytes msg)