···11+{-# LANGUAGE FlexibleInstances #-}
22+{-# LANGUAGE TypeFamilies #-}
33+14module Main where
2536import Data.Bifunctor (Bifunctor (bimap))
44-import Data.Bits (Bits (shiftR), (.|.))
77+import Data.Bits (Bits (shiftR), (.&.), (.|.))
58import Data.Foldable (Foldable (foldr'), foldl')
69import Data.Hashable (Hashable, hash)
1010+import Data.Kind (Type)
1111+import Data.List (elemIndex, findIndex)
712import qualified Data.List.NonEmpty as NE
1313+import Data.Maybe (fromMaybe)
1414+import Data.Semigroup (Semigroup (sconcat))
1515+import qualified GHC.Generics as NE
816917type Hash = Int
10181111--- this can be also rep as a Map<a, Hash>
1212-data Merkle a = Merkle Hash a deriving (Show)
1313-1414-unHash :: Merkle a -> Hash
1515-unHash (Merkle h _) = h
1616-1717-def :: Monoid a => [a] -> a
1818-def = mempty
1919-2019nextHighestPowerOfTwoSmallerThan :: (Num a, Bits a) => a -> a
2120nextHighestPowerOfTwoSmallerThan n = (1 + foldl' go (n -1) [1, 2, 4, 8, 16, 32]) `shiftR` 1
2221 where
2322 go m i = m .|. m `shiftR` i
24232525-merkleTreeHash :: (Hashable a, Monoid a) => [a] -> NE.NonEmpty (Merkle a)
2626-merkleTreeHash xs@[] = return $ Merkle (hash $ def xs) mempty
2727-merkleTreeHash [x] = return $ Merkle (hash x) x
2828-merkleTreeHash xs =
2929- let k = nextHighestPowerOfTwoSmallerThan $ length xs
3030- (left, right) = bimap merkleTreeHash merkleTreeHash $ splitAt k xs
3131- in left <> right
2424+isPower2 :: (Integral i, Bits i) => i -> Bool
2525+isPower2 n = n .&. (n - 1) == 0
32263333-getMerkle :: (Hashable a, Monoid a, Eq a) => a -> [a] -> Maybe (Merkle a)
3434-getMerkle x = fmap NE.head . NE.nonEmpty . NE.dropWhile (\(Merkle _ a) -> a /= x) . merkleTreeHash
2727+splitOnPos :: [a] -> ([a], [a])
2828+splitOnPos [] = ([], [])
2929+splitOnPos [x] = ([x], [])
3030+splitOnPos (x1 : x2 : xs) = (x1 : odds, x2 : evens)
3131+ where
3232+ (odds, evens) = splitOnPos xs
35333636-getHash :: (Hashable a, Monoid a, Eq a) => a -> [a] -> Maybe Hash
3737-getHash x xs = unHash <$> getMerkle x xs
3434+class CMerkle a where
3535+ data HashType a :: Type
3636+ leaf_pad :: a
3737+ node_pad :: a
3838+ hhash :: a -> HashType a
3939+ eqHash :: HashType a -> HashType a -> Bool
4040+ showHash :: HashType a -> String
4141+ cconcat :: HashType a -> HashType a -> HashType a
38423939-auditPath :: (Hashable a) => Int -> [a] -> Maybe [Hash]
4040-auditPath x xs | x > length xs = Nothing
4141-auditPath x xs = error "todo"
4343+ mkLeaf :: a -> HashType a
4444+ mkLeaf x = hhash leaf_pad `cconcat` hhash x
4545+4646+ mkNode :: HashType a -> HashType a -> HashType a
4747+ mkNode x y = hhash node_pad `cconcat` x `cconcat` y
4848+4949+ mkLeafHash :: HashType a -> HashType a
5050+ mkLeafHash = cconcat $ hhash leaf_pad
5151+5252+instance CMerkle a => Semigroup (HashType a) where
5353+ (<>) = mkNode
5454+5555+instance CMerkle a => Eq (HashType a) where
5656+ (==) = eqHash
5757+5858+instance CMerkle a => Show (HashType a) where
5959+ show = showHash
6060+6161+merkleTreeHash :: CMerkle a => a -> [a] -> HashType a
6262+merkleTreeHash d [] = mkLeaf d
6363+merkleTreeHash _ [x] = mkLeaf x
6464+merkleTreeHash d xs =
6565+ let n = length xs
6666+ k = nextHighestPowerOfTwoSmallerThan n
6767+ (left, right) = bimap (merkleTreeHash d) (merkleTreeHash d) $ splitAt k xs
6868+ in mkNode left right
6969+7070+combineHashes :: CMerkle a => a -> Int -> HashType a -> NE.NonEmpty (HashType a) -> Maybe (HashType a)
7171+combineHashes d old_length old ps
7272+ | isPower2 old_length = return $ sconcat $ NE.cons old ps
7373+ | otherwise =
7474+ let (odds, evens) = splitOnPos $ NE.toList ps
7575+ go xs ys = sconcat $ NE.fromList $ [sconcat xs, sconcat ys]
7676+ in go <$> NE.nonEmpty odds <*> NE.nonEmpty evens
7777+7878+auditPath :: (CMerkle a, Eq a) => a -> a -> [a] -> [HashType a]
7979+auditPath _ _ [] = []
8080+auditPath d el xs =
8181+ let maybe_m = elemIndex el xs
8282+ go _ [x] = []
8383+ go m' xs' =
8484+ let n' = length xs'
8585+ k' = nextHighestPowerOfTwoSmallerThan n'
8686+ (left, right) = splitAt k' xs'
8787+ in if m' < k' then go m' left <> [merkleTreeHash d right] else go (m' - k') right <> [merkleTreeHash d left]
8888+ in case maybe_m of
8989+ Nothing -> []
9090+ Just m -> go m xs
9191+9292+consistencyProof :: (CMerkle a, Eq a) => a -> [a] -> [a] -> [HashType a]
9393+consistencyProof d old new =
9494+ let m = length old
9595+ n = length new
9696+ subProof m' xs True | m' == length xs && m' == m = []
9797+ subProof m' xs False | m' == length xs = [merkleTreeHash d xs]
9898+ subProof m' xs b =
9999+ let n' = length xs
100100+ k = nextHighestPowerOfTwoSmallerThan n'
101101+ (left, right) = splitAt k xs
102102+ in if m' <= k
103103+ then subProof m' left b <> [merkleTreeHash d right]
104104+ else subProof (m' - k) right False <> [merkleTreeHash d left]
105105+ in if m <= n then subProof m new True else []
106106+107107+_isIncluded :: (CMerkle a, Eq a) => a -> a -> [a] -> Bool
108108+_isIncluded d x xs = sconcat (NE.fromList $ mkLeaf x : auditPath d x xs) == merkleTreeHash d xs
109109+110110+_areConsistent :: (CMerkle a, Eq a) => a -> [a] -> [a] -> Bool
111111+_areConsistent _ [] _ = False
112112+_areConsistent d old new =
113113+ let old_hash = merkleTreeHash d old
114114+ new_hash = merkleTreeHash d new
115115+ old_length = length old
116116+ in (old_hash == new_hash) || (Just new_hash == (combineHashes d old_length old_hash =<< NE.nonEmpty (consistencyProof d old new)))
117117+118118+instance CMerkle String where
119119+ data HashType String = HashType Int
120120+ leaf_pad = "0"
121121+ node_pad = "1"
122122+ cconcat (HashType a) (HashType b) = HashType $ a + b
123123+ hhash = HashType . hash
124124+ eqHash (HashType a) (HashType b) = a == b
125125+ showHash (HashType a) = show a
126126+127127+isIncluded :: String -> [String] -> Bool
128128+isIncluded = _isIncluded ""
129129+130130+areConsistent :: [String] -> [String] -> Bool
131131+areConsistent = _areConsistent ""
4213243133main :: IO ()
4444-main = putStrLn "Hello, Haskell!"
134134+main = do
135135+ let xs = fmap show [0 .. 9]
136136+ ys = fmap show [0 .. 4]
137137+ print $ isIncluded "4" xs
138138+ print $ areConsistent ys xs