80 lines
3.1 KiB
ReStructuredText
80 lines
3.1 KiB
ReStructuredText
Mistakes Were Made
|
|
===================
|
|
|
|
These are mistakes made early on in the project's history which are difficult to
|
|
fix now, but mentioned in the hope they may serve as an example for others.
|
|
|
|
C++ API
|
|
---------
|
|
|
|
As an implementation language, I still think C++ is the best choice (or at least
|
|
the best choice available in early '00s) at offering good performance,
|
|
reasonable abstractions, and low overhead. But the user API should have been
|
|
pure C with opaque structs (rather like the FFI layer, which was added much
|
|
later). Then an expressive C++ API could be built on top of the C API. This
|
|
would have given us a stable ABI, allowed C applications to use the library, and
|
|
(these days) make it easier to progressively rewrite the library in Rust.
|
|
|
|
Public Algorithm Specific Classes
|
|
------------------------------------
|
|
|
|
Classes like AES_128 and SHA_256 should never have been exposed to applications.
|
|
Intead such operations should have been accessible only via the higher level
|
|
interfaces (here BlockCipher and HashFunction). This would substantially reduce
|
|
the overall API and ABI surface.
|
|
|
|
[These interfaces were made internal in 3.0]
|
|
|
|
Header Directories
|
|
-------------------
|
|
|
|
It would have been better to install all headers as ``X/header.h``
|
|
where ``X`` is the base dir in the source, eg ``block/aes128.h``,
|
|
``hash/md5.h``, ...
|
|
|
|
Exceptions
|
|
-----------
|
|
|
|
Constant ABI headaches from this, and it impacts performance and makes APIs
|
|
harder to understand. Should have been handled with a result<> type instead.
|
|
|
|
Alternatively, and possibly more practically, there should have not been any
|
|
exception hierarchy (or at least not one visible to users) - instead only the
|
|
high level Exception type with contains an error type enum.
|
|
|
|
Virtual inheritance
|
|
---------------------
|
|
|
|
This was used in the public key interfaces and the hierarchy is a tangle.
|
|
Public and private keys should be distinct classes, with a function on private
|
|
keys that creates a new object corresponding to the public key.
|
|
|
|
Cipher Interface
|
|
------------------
|
|
|
|
The cipher interface taking a secure_vector that it reads from and writes to was
|
|
an artifact of an earlier design which supported both compression and encryption
|
|
in a single API. But it leads to inefficient copies.
|
|
|
|
(I am hoping this issue can be somewhat fixed by introducing a new cipher API
|
|
and implementing the old API in terms of the new one.)
|
|
|
|
Pipe Interface
|
|
----------------
|
|
|
|
On the surface this API seems very convenient and easy to use. And it is. But
|
|
the downside is it makes the application code totally opaque; some bytes go into
|
|
a Pipe object and then come out the end transformed in some way. What happens in
|
|
between? Unless the Pipe was built in the same function and you can see the
|
|
parameters to the constructor, there is no way to find out.
|
|
|
|
The problems with the Pipe API are documented, and it is no longer used within
|
|
the library itself. But since many people seem to like it and many applications
|
|
use it, we are stuck at least with maintaining it as it currently exists.
|
|
|
|
License
|
|
---------
|
|
|
|
MIT is more widely used and doesn't have the ambiguity surrounding the
|
|
various flavors of BSD.
|