It’s time for another update!
Community proposal submission
The first thing is something to celebrate - I have officially submitted the cryptography community project proposal to the Haskell Foundation - this proposal has been a few weeks in the making, so many thanks to all who provided feedback
What to work on next
Getting the community proposal written and implementing online / incremental processing for ciphers has been my focus for the last few weeks, and now that they’re both done I need to take a moment and figure out what to work on next. I have several options:
- Get more unit tests written for
botan-low
- Incremental processing for other things
- Merge the pull request that refactors
botan-bindings
- Work on the consistency / ergonomics / exported interface for
botan-low
& botan
- Flesh out a proper task list to make these decisions easier
I am probably going to go for unit tests, or merging the pull request, because it is better to get the lower level stuff done first.
Cryptography Abstractions
In the mean time, while I’m deciding that, I like to like to work on the higher-level abstractions a bit to see how practical my lower-level decisions have been. With the recent addition of online processing to the mix, that has got me thinking about two things:
- Lazy bytestrings which lead me on to a deeper dive into their internals - very satisfying
- Higher level abstractions, which led me to re-sketch out some cryptography classes
The impetus is that existing efforts for cryptography typeclasses seem to focus on the nitty gritty mechanics of cryptography processing. Look at crypton/ite’s HashAlgorithm (or the (Block)Cipher classes), and the functions used to operate on them:
-- crypton/ite's HashAlgorithm class
class HashAlgorithm alg where
hashBlockSize :: ...
hashDigestSize :: ...
hashInternalContextSize :: ...
hashInternalInit :: ...
hashInternalUpdate :: ...
hashInternalFinalize :: ...
It just concretizes how it implemented incremental hashing, rather than abstracting hashing in general. I think we can build a much better typeclass hierarchy for cryptographic primitives, by analyzing the commonalities of the algorithm-specific functions.
You’d expect that a typeclass abstraction of hashing would be something much simpler, less restrictive, like:
-- An ideal Hash typeclass
class Hash alg where
hash :: ByteString -> Digest alg
We can also just use the same interface but with lazy bytestrings for incremental processsing, and leave how the incremental processing is achieved up to the instance. This is significant because different crypto libraries may expose incremental processing differently (eg API differences), so we mustn’t assume anything about how it performs incremental processing.
-- The only difference is that it takes lazy bytestrings
class (Hash alg) => IncrementalHash alg where
hash :: LazyByteString -> Digest alg
Then on top of these we can build more typeclasses specific to block sizes and updates and finalizing.
The Cipher typeclasses aren’t much better; the Cipher
class actually only concerns itself with initialization, without defining anything about encryption / decryption. The BlockCipher class slightly improves on this, by providing individual functions for each block cipher mode, but that conflates all modes as a requirement, plus that means that the class should be called BlockCipherMode
. Furthermore, AEADs and Stream ciphers are just sort of left to implement algorithm-specific encrypt / decrypt functions on their own. Other crypto primitives do not have classes.
Don’t get me wrong, extended typeclasses for block-based and incremental hashing / ciphers is great, but we shouldn’t use that as a base typeclass nor assume that all algorithms are capable of such things. Streaming hashes and ciphers do not have (input) block sizes and can take arbitrarily small inputs, but not all algorithms can do this (eg, block-based hashes and ciphers).
I’ve sketched more out in a file but its mostly just musings and scratchwork - I haven’t even tried to compile it yet - but a consistent interface has developed so we’re getting somewhere, and just about anything would be an improvement over the current situation.
Boolean typeclass proposal
We all know there’s some awkward stuff in base
that could be improved, and Bits
is one of them - second only to Num
in awkwardness, the Bits
class is too large, and unnecessarily lumps boolean algebra functions together with bit field functions. As a result, Bits
is often not properly implemented, to the point that there is no proper instance for ByteString
, and I believe this negatively affects the low-level-binary Haskell ecosystem in general.
This particular pet peeve is something that’s been churning in my mind for a while, and it has only gotten more relevant with the cryptography project. I believe we can fix these things by reworking things a little, and so I’ve started working on a base proposal to split off a Boolean
typeclass from Bits
, something like:
class (Eq a) => Boolean a where
complement :: a -> a -- aka not
and :: a -> a -> a
or :: a -> a -> a
xor :: a -> a -> a
-- Potentially added to complete the boolean algebra
false :: a
true :: a
class (Boolean a) => Bits a where
...
By splitting off a Boolean
class, we can now make an instance for ByteString
for boolean logic, and it also leaves the Bits
class as clearly pertaining to bit fields, with more clearly relevant functions.
It is still very rough, mostly being a bunch of notes, but I think there is a good point here - what do you think?
That’s all for now - til next time!