Hash Tree implementation in Haskell
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

45 lines
1.4 KiB

12 years ago
module HashTrees where
import Data.Digest.Pure.SHA
import qualified Data.ByteString.Lazy as BL
import Control.Monad
import Data.List
data HashTree k a = Leaf | HashTree (Digest k) (HashTree k a) (HashTree k a) deriving (Show)
groupsOf _ ([]) = []
groupsOf n xs = case splitAt n xs of
(a, as) -> a : (groupsOf n as)
groupsOf2 xs = map (\(x:y:[]) -> (x,y)) $ groupsOf 2 xs
hashCatInner (h1, h2) = sha1 $ BL.concat [(bytestringDigest h1), (bytestringDigest h2), BL.singleton 1]
hashes = map sha1
singletonTrees xs = map (\x -> HashTree x Leaf Leaf) xs
reduceHashes xs = map (\((HashTree x _ _), (HashTree y _ _)) -> HashTree (hashCatInner (x,y)) Leaf Leaf) (groupsOf2 xs)
combineTrees (HashTree x _ _) (t1, t2) = HashTree x t1 t2
combineTreeLists lower upper = zipWith combineTrees upper (groupsOf2 lower)
buildPreliminaryLevels ([x]) = [[x]]
buildPreliminaryLevels xs = xs : (buildPreliminaryLevels $ (reduceHashes xs))
buildTree' :: [HashTree k t] -> [[HashTree k t]] -> [HashTree k t]
buildTree' acc ([]) = acc
buildTree' acc (x:xs) = buildTree' (combineTreeLists acc x) xs
buildTree = (\x -> buildTree' (head x) (tail x)) . buildPreliminaryLevels . singletonTrees . hashes . (map (\x -> BL.concat [x,BL.singleton 0])) . padHashes
-- Padding functions
nextPowerOf n = 2 ^ (ceiling $ logBase 2 $ fromIntegral n)
padHashes xs = pad' 0 xs where
pad' n ([]) = [] ++ (take ((nextPowerOf n) - n) $ repeat BL.empty)
pad' n (x:xs) = x : (pad' (n +1) xs)