As a form of practice, and as I'll be needing SHA1 for potential future work, I've decided to create my own implementations across my three main languages. That final implementation I'll be showcasing is written in Common Lisp, measuring at roughly two hundred lines. It's been educational to compare implementations across these languages; I feel I've learned the most with Ada and the Common Lisp is a mirror of the Ada in design; the APL dealt with bits, the Ada with words, and this fills the final primary unit by dealing in octets.
This program is licensed under the GNU Affero General Public License version three.
Unlike my previous Common Lisp libraries and as with the Ada version, this library is designed to be used without bringing in its names. That's to write you shouldn't USE-PACKAGE it and should instead use its package name on every symbol reference; the symbol names are chosen to make this convenient.
Similarly to the Ada, one good name, HASH, was chosen and reused as much as was feasible. The means was making SHA1:HASH a generic function with several overloadings, and adding more at my leisure; do note that this is exemplary of the naming scheme; rather than embed SHA1 into the symbol's name, the package name achieves this nicely.
The INITIAL-STATUS is a constant and corresponds to the beginning state of that core SHA1 algorithm. Both of PARTIAL-HASH and PAD are used internally and provided solely for the cases in which the HASH is insufficient; this includes instances where all data to hash isn't currently available or where a message granularity other than octet is desired. Both SHA1:PRINT and SHA1:STRING exist to transform the final digest into a more usable form and note the internal representation is subject to my whim.
Follows are the HASH overloadings followed by any keyword arguments; note HASH always enforces a bit granularity of eight and operates solely on octets, (UNSIGNED-BYTE 8).
VECTOR :START :END
The contents of the VECTOR given by the bounds, as for standard functions, are hashed and the digest returned; the contents outside of the relevant subsequence are ignored.
The contents of the STREAM are hashed and the digest returned; every STREAM-ELEMENT-TYPE must adhere to the requirements; the STREAM is closed afterwards.
The PATHNAME is opened with an octet ELEMENT-TYPE as if by WITH-OPEN-FILE, and the resulting STREAM is hashed as if by the STREAM overloading.
A LIST overloading is planned and a BIT-VECTOR overloading is being considered.
Note and be warned I've still yet to exhaustively test this library. I'll remove this notice once I do. Comparing this with any SHA1 implementation known to be correct or otherwise trusted can easily be done by using the SHA1:HASH overloading with a pathname, in the general case, or by using PAD and PARTIAL-HASH manually, for those cases requiring different bit granularities.
In sum, this has been a valuable learning experience. The APL is most concise and so the easiest to modify; the Ada is the most robust, lacking error cases and dynamic allocations, and which was given the most thought in design; and the Common Lisp is the easiest to use, along with its supporting the octet and so that very common unit. I may reflect on this in a separate article, say.
Here is the source and the documentation. Here is the license.