Create a message-digest-primitive object. The reification of a message digest algorithm.

CONTEXT-INFO is either a (procedure () <context>), or a positive integer. When an integer a memory-block of length CONTEXT-INFO is allocated (and automatically free'ed).

<context> is an opaque object, except when the CONTEXT-INFO is an integer. In which case it is known that the object is a pointer to a block of uninitialized memory.

The <context> should be a unique object. At least the object cannot be shared with another activated primitive.

DIGEST-LENGTH is the count of bytes in the result.

The processing of a message digest is split into three phases: initialization, update & finalization. These are represented by three procedures: INIT, UPDATE & FINAL, respectively.

INIT is a (procedure (<context>)). Sets up the <context>. (Technically the creation of a new <context> is part of the initialization phase but this detail is hidden from the user.)

UPDATE is a (procedure (<context> <bytevector> <count>)). Must accumulate the <bytevector>. Will be called zero, one or more times.

A <bytevector> is a string or a blob. The foreign type specifier scheme-pointer is suitable as a foreign-lambda argument type for the <bytevector> argument since the data-region of both a string and a blob is a bytevector.

<count> is the actual number of bytes in the <bytevector>. Since this value is supplied it means only the first <count> bytes in the <bytevector> are valid.

FINAL is a (procedure (<context> <bytevector>)). Must build the message-digest result in the supplied result <bytevector>, with length at least DIGEST-LENGTH.

The result <bytevector> is a blob or a string.

(Note that INIT, UPDATE & FINAL are side-effecting procedures!)

NAME must be a symbol or a string and identifies the message digest algorithm. The suggested form is <algorithm name>-primitive. Example: 'md5-primitive. The default is a nearly useless generated, uninterned symbol.

Uses the message-digest port abstraction to get an MD5 digest of a string:

(use message-digest-port)(use md5); Or sha1, or sha2, ...
(call-with-output-digest (md5-primitive)(cut display "foo" <>));=> "acbd18db4cc2f85cedef654fccc4a4d8"
(use message-digest); Uses a string as the buffer so the packed buffer is interpreted properly.
; A blob or u8vector would be converted to a string by the port i/o machinary
; with loose of information; like all of it.
(call-with-output-digest (md5-primitive)(pack-u32 #xabcdef012345 #:order 'big-endian));=> ""

If someone needs to construct a message-digest phase procedure that cannot be built upon the existing public API please contact the maintainer. There are some routines that can be exported to aid in such a project.

It must be pointed out, though, that the message-digest port API is implemented using only the existing public API.

Should the default message-digest result-form be held by a "parameter" object?

The number update routines will not process an integer represented as anything other than a fixnum or flonum.

Since Chicken does not really have a binary port concept the digest-output-port will only accumulate strings. Should a more nuanced set of sources be necessary use the Byte Packing API above.

For example, writing a 16-bit integer is actually writing the result of number->string and not the 16-bit value itself! To get this effect the value must first be packed into a string and then written.

However, the extras#write-byte routine should function as expected with a digest-output-port.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the Software),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ASIS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.