Could we request CamelCase class names?
(The Nettle directory is visible now, by the way. Sorry about the glitch.)
/ Johan Sundström (folkskådare)
Previous text:
2003-03-13 20:57: Subject: nettle-1.7
Now it's "Nettle".
Perhaps I should describe the current organization, for hash functions. Sorry it's a little hairy.
The Nettle library provides an abstraction struct nettle_hash, defined in nettle/nettle-meta.h. These are constant read-only structs that contains the name of the hash algorith, block size, digest size, and the size of the context struct. There's nettle_md5, nettle_sha1, etc. This is used to minimize the amount of glue code needed for each hash algorithm. The classes are:
PIKECLASS nettle_hash
This class has one instance variable, const struct nettle_hash *meta, and the methods name(), digest_size(), block_size().
The meta variable is initialized to NULL, it's up to a suitable mixin to initialize it.
PIKECLASS hash_instance
Inherits nettle_hash, and has one additional instance variable, void *ctx. This should point to a context struct for a hash algorithm, also initialized to NULL. This function has the familiar methods update and digest, and will raise errors if meta or ctx is NULL, or if input contains wide characters,
PIKECLASS nettle_md5
This is a mixin class, it has no superclass of its own. It's initializer uses get_storage to get the storage for an inherited nettle_hash class, supposedly inherited in parallel with this mixin. It checks that get_storage doesn't return NULL, and that the meta instance variable is not yet initialized. It then sets meta = &nettle_md5. That's all. I found out the hard way that the INIT method can't call Pike_error, so it will just leave meta alone on failure.
PIKECLASS md5_state
This is the state class for md5. It inherits nettle_md5 and hash_instance (and depends on these being initialized in the right order, hash_instance *first*. It has one new instance variable, a struct md5_ctx. The INIT method uses get_storage to get to the inherited hash_instance storage, and sets the ctx pointer to point to the struct md5_ctx.
That is, it sets up a pointer in one block in the storage area to point to another block (probably just a constant offset away from the pointer). That seems easier and cleaner that dependeing on the storage layout directly.
That's all, the md5_state object is equivalent to the current Crypto.md5 class. But then I'd like to put some code into Crypto.pmod as well, like
class md5_algorithm { inherit Nettle.nettle_md5; inherit Nettle.nettle_hash;
constant `() = Nettle.md5_state; };
constant MD5 = md5_algorithm();
Then one can do Crypto.MD5.digest_size() to get the digest size, Crypto.MD5()->update("foo")->digest(); one could also add a method Crypto.MD5.hash(string data) that hashes a string in one go.
For the hairyness factor, note that the order of the inherits is important here too. I'm assuming the INIT order is the same as for my cmod classes, but that should be properly defined somewhere.
For type checking purposes, the Nettle.md5_state class can be used. One can add some alias in Crypto too, of course, if you don't like either of
Nettle.md5_state foo; Crypto.MD5.`() foo; // ;-)
Perhaps this still doesn't quite justify the amount of small classes, but I believe that being able to get out the meta pointer from objects will be handy for example for the hmac code.
Block ciphers can be dealt with in mostly the same way, I think. Except that some ugly algorithms, like des, have weak keys, and need to raise exceptions in their set_key functions, which means that more information is needed than that which is provided by the the corresponding cipher meta abstraction in the nettle library.
The code is up for view at URL: http://pike.ida.liu.se/development/cvs/view.xml?module=Pike&file=7.5/src/post_modules/Nettle/hash.cmod&rev=1.1, even if the Nettle directory for some reason isn't listed at URL: http://pike.ida.liu.se/development/cvs/browse.xml?module=Pike&dir=/7.5/src/post_modules.
/ Niels Möller ()