[Haskell-cafe] Re: cryptohash and an incremental API

Vincent Hanquez tab at snarc.org
Wed Jul 14 04:22:14 EDT 2010


On Mon, Jul 12, 2010 at 02:52:10PM -0700, Thomas M. DuBuisson wrote:
> I've been working on a new crypto library specifically to provide a
> unified API for packages implementing cryptographic algorithms.  You can
> see the discussions on libraries at haskell.org [1] [2].  Please feel free
> to take a look, comment, contribute, and hopefully move to the
> interface.  I should be finishing up BlockCipher modes and adding hash
> tests soon.

Hi Thomas,

first, I think that's a great efforts to standardize the crypto API !

couple of comments around the hashes interface:

* updateCtx works on blockLength, instead of working on arbitrary size: while
this does represent what the underlaying algorithm do, letting the algorithm
implementation process any size is, I think, better. chunking the bytestring
might have a significant cost (a rope based implementation would not suffer
this), and in my case, processing as much as possible at each update call,
prevent from suffering from the marshalling/unmarshalling cost of the mutable
state.

* hash is a generic operation based on the class Hash. In my case, it improve 
performance by not running the pure init/update/finalize exposed, but use the hidden
impure function. I realized yesterday it's not as much as i though since i had
a bug in my benchmark, but it's still there (100ms for 500mb of data).

* Why is the digest of a specific type ? I like representing different
things with different types, but i'm not sure what do you gain with digests
though.

* is strength really useful in the Hash class ? it might be accurate when the
thing get implemented, but i'm not sure what would happens over time, and flaws
are discovered. would people actually updates it ?


The blockCipher should exposes the chaining modes as overridable typeclass
functions, with default generic implementations that use encryptBlocks. For
example the haskell AES package has different C implementations for each
chaining modes (e.g. cbc, ebc), and i suspect that using a generic chaining
implementation would slow things down.

what about something like:

-- each plaintext bytestring need to be a multiple of blockSize
class (Binary k, Serialize k) => BlockCipher k where
  blockSize        :: Tagged k BitLength
  encryptBlocks    :: k -> ByteString -> ByteString
  decryptBlocks    :: k -> ByteString -> ByteString
  encryptBlocksCBC :: k -> ByteString -> (k, ByteString)
  encryptBlocksCBC = genericCBC encryptBlocks
  decryptBlocksCBC :: k -> ByteString -> (k, ByteString)
  .. same for ebc, ...
  buildKey        :: ByteString -> Maybe k
  keyLength       :: k -> BitLength       -- ^ keyLength may inspect...


and my last comment, is that i don't understand the streamcipher interface
you're proposing.  I've got a (inefficient) RC4 implementation that has this
interface:

stream :: Ctx -> B.ByteString -> (Ctx, B.ByteString)
streamlazy :: Ctx -> L.ByteString -> (Ctx, L.ByteString)

I'm not sure how it would fit this interface (some kind of state monad ?):

encryptStream         :: k -> B.ByteString -> B.ByteString


I hope that's useful comments,
-- 
Vincent Hanquez


More information about the Haskell-Cafe mailing list