IMPLEMENTATION MODULE HashAlgs;

        (********************************************************)
        (*                                                      *)
        (*                    Hash algorithms                   *)
        (*                                                      *)
        (*  Programmer:         P. Moylan                       *)
        (*  Started:            14 February 2021                *)
        (*  Last edited:        26 February 2025                *)
        (*  Status:             Complete, working               *)
        (*                                                      *)
        (********************************************************)


IMPORT SHA1, SHA2, SHA512;
FROM SYSTEM IMPORT LOC, CARD8;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;

(************************************************************************)

TYPE
    HashCtx = POINTER TO
                RECORD
                    CASE alg: HashAlgorithm OF
                        sha1:
                            algctx1: SHA1.SHA1_CTX;
                      |
                        sha2_256:
                            algctx256: SHA2.SHA2_CTX;
                      |
                        sha2_512:
                            algctx512: SHA512.SHA512_CTX;
                    END (*CASE*);
                    valid: BOOLEAN;
                END (*RECORD*);

     LengthArray = ARRAY HashAlgorithm OF CARDINAL;

CONST
    DigestLength = LengthArray {20, 32, 64};

(************************************************************************)

PROCEDURE HashLength (alg: HashAlgorithm): CARDINAL;

    (* Returns the number of bytes in a hashed result. *)

    BEGIN
        RETURN DigestLength[alg];
    END HashLength;

(************************************************************************)
(*                       STARTING A NEW OPERATION                       *)
(************************************************************************)

PROCEDURE HashInit (alg: HashAlgorithm): HashCtx;

    (* Initialization.  Creates a context for a new hash operation. *)

    VAR result: HashCtx;

    BEGIN
        NEW (result);
        result^.alg := alg;
        result^.valid := TRUE;
        CASE alg OF
            sha1:
                result^.algctx1 := SHA1.SHA1Init();
          | sha2_256:
                result^.algctx256 := SHA2.SHA256Init();
          | sha2_512:
                result^.algctx512 := SHA512.SHA512Init();
        ELSE
            result^.valid := FALSE;
        END (*CASE*);
        RETURN result;
    END HashInit;

(************************************************************************)

PROCEDURE HashInitOK (ctx: HashCtx): BOOLEAN;

    (* Returns TRUE iff HashInit was successful.  *)

    BEGIN
        RETURN ctx^.valid;
    END HashInitOK;

(************************************************************************)

PROCEDURE HashAbort (VAR (*INOUT*) ctx: HashCtx);

    (* Terminates a hash operation without completing the calculation.  *)

    BEGIN
        DISPOSE (ctx);
    END HashAbort;

(************************************************************************)
(*                          INPUTTING MORE DATA                         *)
(************************************************************************)

PROCEDURE HashUpdate (context: HashCtx;
                    VAR (*IN*) data: ARRAY OF LOC;  length: CARDINAL);

    (* Block update operation. Continues hashing,  adding more data     *)
    (* to what has already been processed for this context.             *)

    BEGIN
        CASE context^.alg OF
            sha1:
                SHA1.SHA1Update (context^.algctx1, data, length);
          | sha2_256:
                SHA2.SHA2Update (context^.algctx256, data, length);
          | sha2_512:
                SHA512.SHA512Update (context^.algctx512, data, length);
        END (*CASE*);
    END HashUpdate;

(************************************************************************)
(*                      RETRIEVING THE HASHED RESULT                    *)
(************************************************************************)

PROCEDURE HashFinal (VAR (*INOUT*) context: HashCtx;
                        VAR (*OUT*) digest: ARRAY OF CARD8);

    (* Finalization. Ends a hashing operation, returning    *)
    (* the hashed result and discarding the context.        *)

    BEGIN
        CASE context^.alg OF
            sha1:
                SHA1.SHA1Final (context^.algctx1, digest);
          | sha2_256:
                SHA2.SHA2Final (context^.algctx256, digest);
          | sha2_512:
                SHA512.SHA512Final (context^.algctx512, digest);
        END (*CASE*);
        DISPOSE (context);
    END HashFinal;

(************************************************************************)

END HashAlgs.

