{-# LANGUAGE BangPatterns #-}{- |
Module : Data.Digest.TigerHash
Copyright : (c) Orlyuk Nikolay 2010
License : GPL-2
Maintainer : virkony@gmail.com
Stability : provisional
There comes some kind of description how to use this module.
Assume next import:
> import Data.Digest.TigerHash
Typical instant usage:
> instance TigerHashable k => TigerHashable (k, Message) where
> tigerHashUpdate ctx_ (key, Message {sender = data0, body = data1}) = do
> tigerHashUpdate ctx_ key
> tigerHashUpdate ctx_ data0
> tigerHashUpdate ctx_ data1
>
> signMessage :: TigerHashable k => k -> Message -> SignedMessage
> signMessage pkey msg = SignedMessage { message = msg, sign = tigerHash (pkey, msg) }
This is pretty useful when you need to send signed messages over public channel.
But using this in a such functional way have its drawbacks. Each time system
requires calculation of @hash@ it will issue prepearing of new context for each
calculation instead of using the same context.
To solve that there is function for processing lazy list:
> hashMessageSenders :: [Message] -> [(TigerHash, Message)]
> hashMessageSenders msgs = zip (tigerHashList senders) msgs
> where senders = map sender msgs
This can be used for building hashed storage, which requires hash of each element.
Notice that while you expand each node of the list 'tigerHashList' will calculate it's @head@
for you. That's done with intention to loose overhead while hashing files for DC++ .
-}moduleData.Digest.TigerHash(TigerHash,TigerHashable(..),hexTigerHash,b32TigerHash)whereimportSystem.IO.UnsafeimportForeign.ForeignPtrimportForeign.PtrimportText.ShowimportData.ByteString.Internal(inlinePerformIO)importqualifiedData.ByteString.LazyasLBSimportData.BinaryimportData.Binary.PutimportData.Binary.GetimportqualifiedCodec.Binary.Base16asB16importqualifiedCodec.Binary.Base32asB32importControl.MonadimportData.Digest.TigerHash.Internal-- | render 'TigerHash' to 'String' as hex-dumphexTigerHash::TigerHash->StringhexTigerHash=B16.encode.LBS.unpack.runPut.put-- | render 'TigerHash' to 'String' using Base32 encoding (as used in magnet-links and etc.)b32TigerHash::TigerHash->Stringb32TigerHash=B32.encode.LBS.unpack.runPut.putinstanceShowTigerHashwhereshowsPrec_th=(++)(b32TigerHashth)instanceBinaryTigerHashwhereput(TigerHashabc)=putWord64hosta>>putWord64hostb>>putWord64hostcget=doa<-getWord64hostb<-getWord64hostc<-getWord64hostreturn(TigerHashabc)classTigerHashableawhere-- | Each 'TigerHashable' data should implement this using 'updateContext' of-- 'TigerContext' class from "Data.Digest.TigerHash.Internal". But usually-- there is enough to just call 'tigerHashUpdate' for data which already-- have instance for 'TigerHashable'.tigerHashUpdate::(TigerContext(Ptrc))=>Ptrc->a->IO()-- | Instant caluculation of Tiger Hash with stack allocated context.tigerHash::a->TigerHashtigerHashx=inlinePerformIO.withTigerContext$\ctx->dotigerHashUpdatectxxfinalizeContextctx-- | Same as 'tgerHash', but with Tiger Tree hashing algorithmtigerTreeHash::a->TigerHashtigerTreeHashx=inlinePerformIO.withTigerTreeContext$\ctx->dotigerHashUpdatectxxfinalizeContextctx-- | Calculate sequence of hashes where each next is calculated on-demand-- and /only after previous one/ using one context for all calculations.-- Be sure to prepare sequence wich contains /only required for hashing/-- entries.tigerHashList::[a]->[TigerHash]tigerHashList[]=[]tigerHashList(x0:xs)=unsafePerformIO$doctx<-newTigerContextletmcombxmys=unsafeInterleaveIO$do-- list structure is lazyy<-withForeignPtrctx$\ctx_->doresetContextctx_tigerHashUpdatectx_xfinalizeContextctx_liftM(y:)mys-- no need to resetContext after newContexty0<-withForeignPtrctx$\ctx_->dotigerHashUpdatectx_x0finalizeContextctx_liftM(y0:)$foldrmcomb(return[])xs{-# NOINLINE tigerHashList #-}-- | Same as 'tigerHashList', but with Tiger Tree hashing algorithmtigerTreeHashList::[a]->[TigerHash]tigerTreeHashList[]=[]tigerTreeHashList(x0:xs)=unsafePerformIO$doctx<-newTigerTreeContextletmcombxmys=unsafeInterleaveIO$do-- list structure is lazyy<-withForeignPtrctx$\ctx_->doresetContextctx_tigerHashUpdatectx_xfinalizeContextctx_liftM(y:)mys-- no need to resetContext after newContexty0<-withForeignPtrctx$\ctx_->dotigerHashUpdatectx_x0finalizeContextctx_liftM(y0:)$foldrmcomb(return[])xs{-# NOINLINE tigerTreeHashList #-}