Andreas Software - Source Code - AJHash.PAS

My own hash function AJ Hash for Embarcadero Delphi, included are 32-bit and 64-bit, but it can easily be extended

unit AJHash;

{
  My own hash function AJ Hash for Embarcadero Delphi, included are 32-bit and 64-bit, but it can easily be extended.

  Original Author: Andreas Jonsson. (www.andreas-software.com)

  NOTICE: YOU MAY USE AND MODIFY THIS SOURCE CODE FREELY, THE ONLY REQUIREMENT IS THAT THE COMMENT ABOUT THE ORIGINAL AUTHOR AND THIS NOTICE REMAINS IN THE SOURCE CODE.
}

interface

uses
  System.SysUtils, System.Variants, System.Classes;

const AJHASH_START_VALUE_32 = $7F7F7F7F;
const AJHASH_START_VALUE_64 = $7F7F7F7F7F7F7F7F;

function ROL8(Value: Byte; N: Byte): Byte; inline;
function ROR8(Value: Byte; N: Byte): Byte; inline;

procedure Mix(var X: Byte; var Y: Byte; K: Byte); inline;

function AJHash32Bytes(Bytes: TBytes; Length: Integer; StartValue: Cardinal = AJHASH_START_VALUE_32; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): Cardinal;

function AJHash32Text(Text: string; Encoding: TEncoding = nil; StartValue: Cardinal = AJHASH_START_VALUE_32; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): Cardinal;

function AJHash64Bytes(Bytes: TBytes; Length: Integer; StartValue: UInt64 = AJHASH_START_VALUE_64; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): UInt64;

function AJHash64Text(Text: string; Encoding: TEncoding = nil; StartValue: UInt64 = AJHASH_START_VALUE_64; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): UInt64;

implementation

function ROL8(Value: Byte; N: Byte): Byte; inline;
begin
  Result := ((Value shl N) or (Value shr (8 - N)));
end;

function ROR8(Value: Byte; N: Byte): Byte; inline;
begin
  Result := ((Value shr N) or (Value shl (8 - N)));
end;

procedure Mix(var X: Byte; var Y: Byte; K: Byte); inline; // Speck Style Mix.
begin
  X := ROR8(X, 6);
  X := X + Y;
  X := X xor K;
  Y := ROL8(Y, 1);
  Y := Y xor X;
end;

function AJHash32Bytes(Bytes: TBytes; Length: Integer; StartValue: Cardinal = AJHASH_START_VALUE_32; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): Cardinal;
var ByteArray: array[0..3] of Byte;
var Index: Integer;
var MinLoop: Integer;
var MaxLoop: Integer;
var MinI: Integer;
var MaxI: Integer;
var Loop: Integer;
var I: Integer;
var K: Byte;
begin
  Result := StartValue;
  if (Bytes <> nil) and (Length > 0) then begin
    Move(Result, ByteArray, 4);
    Index := 0; // Get rid of compiler warning.
    MinLoop := 0;
    MaxLoop := Length - 1;
    for Loop := MinLoop to MaxLoop do begin
      Index := Loop and 3;
      ByteArray[Index] := ByteArray[Index] xor Bytes[Loop];
      ByteArray[Index] := ByteArray[Index] + AddValue;
      if Index = 3 then begin
        MinI := 0;
        MaxI := IterativeMixRounds - 1;
        for I := MinI to MaxI do begin
          K := (I and 1) + 1;
          Mix(ByteArray[3], ByteArray[0], K);
          Mix(ByteArray[0], ByteArray[1], K);
          Mix(ByteArray[1], ByteArray[2], K);
          Mix(ByteArray[2], ByteArray[3], K);
        end;
      end;
    end;
    if Index <> 3 then begin
      MinI := 0;
      MaxI := IterativeMixRounds - 1;
      for I := MinI to MaxI do begin
        K := (I and 1) + 1;
        Mix(ByteArray[3], ByteArray[0], K);
        Mix(ByteArray[0], ByteArray[1], K);
        Mix(ByteArray[1], ByteArray[2], K);
        Mix(ByteArray[2], ByteArray[3], K);
      end;
    end;
    MinI := 0;
    MaxI := FinishMixRounds - 1;
    for I := MinI to MaxI do begin
      K := (I and 7) + 1;
      Mix(ByteArray[3], ByteArray[0], K);
      Mix(ByteArray[0], ByteArray[1], K);
      Mix(ByteArray[1], ByteArray[2], K);
      Mix(ByteArray[2], ByteArray[3], K);
    end;
    Move(ByteArray, Result, 4);
  end;
end;

function AJHash32Text(Text: string; Encoding: TEncoding = nil; StartValue: Cardinal = AJHASH_START_VALUE_32; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): Cardinal;
var Bytes: TBytes;
begin
  Result := StartValue;
  if Text <> '' then begin
    if Encoding = nil then begin
      Encoding := TEncoding.UTF8;
    end;
    try
      Bytes := Encoding.GetBytes(Text);
    except
      Bytes := nil;
    end;
    if Bytes <> nil then begin
      Result := AJHash32Bytes(Bytes, Length(Bytes), Result, AddValue, IterativeMixRounds, FinishMixRounds);
    end;
  end;
end;

function AJHash64Bytes(Bytes: TBytes; Length: Integer; StartValue: UInt64 = AJHASH_START_VALUE_64; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): UInt64;
var ByteArray: array[0..7] of Byte;
var Index: Integer;
var MinLoop: Integer;
var MaxLoop: Integer;
var MinI: Integer;
var MaxI: Integer;
var Loop: Integer;
var I: Integer;
var K: Byte;
begin
  Result := StartValue;
  if (Bytes <> nil) and (Length > 0) then begin
    Move(Result, ByteArray, 8);
    Index := 0; // Get rid of compiler warning.
    MinLoop := 0;
    MaxLoop := Length - 1;
    for Loop := MinLoop to MaxLoop do begin
      Index := Loop and 7;
      ByteArray[Index] := ByteArray[Index] xor Bytes[Loop];
      ByteArray[Index] := ByteArray[Index] + AddValue;
      if Index = 7 then begin
        MinI := 0;
        MaxI := IterativeMixRounds - 1;
        for I := MinI to MaxI do begin
          K := (I and 1) + 1;
          Mix(ByteArray[7], ByteArray[0], K);
          Mix(ByteArray[0], ByteArray[1], K);
          Mix(ByteArray[1], ByteArray[2], K);
          Mix(ByteArray[2], ByteArray[3], K);
          Mix(ByteArray[3], ByteArray[4], K);
          Mix(ByteArray[4], ByteArray[5], K);
          Mix(ByteArray[5], ByteArray[6], K);
          Mix(ByteArray[6], ByteArray[7], K);
        end;
      end;
    end;
    if Index <> 7 then begin
      MinI := 0;
      MaxI := IterativeMixRounds - 1;
      for I := MinI to MaxI do begin
        K := (I and 1) + 1;
        Mix(ByteArray[7], ByteArray[0], K);
        Mix(ByteArray[0], ByteArray[1], K);
        Mix(ByteArray[1], ByteArray[2], K);
        Mix(ByteArray[2], ByteArray[3], K);
        Mix(ByteArray[3], ByteArray[4], K);
        Mix(ByteArray[4], ByteArray[5], K);
        Mix(ByteArray[5], ByteArray[6], K);
        Mix(ByteArray[6], ByteArray[7], K);
      end;
    end;
    MinI := 0;
    MaxI := FinishMixRounds - 1;
    for I := MinI to MaxI do begin
      K := (I and 7) + 1;
      Mix(ByteArray[7], ByteArray[0], K);
      Mix(ByteArray[0], ByteArray[1], K);
      Mix(ByteArray[1], ByteArray[2], K);
      Mix(ByteArray[2], ByteArray[3], K);
      Mix(ByteArray[3], ByteArray[4], K);
      Mix(ByteArray[4], ByteArray[5], K);
      Mix(ByteArray[5], ByteArray[6], K);
      Mix(ByteArray[6], ByteArray[7], K);
    end;
    Move(ByteArray, Result, 8);
  end;
end;

function AJHash64Text(Text: string; Encoding: TEncoding = nil; StartValue: UInt64 = AJHASH_START_VALUE_64; AddValue: Integer = 1; IterativeMixRounds: Integer = 2; FinishMixRounds: Integer = 8): UInt64;
var Bytes: TBytes;
begin
  Result := StartValue;
  if Text <> '' then begin
    if Encoding = nil then begin
      Encoding := TEncoding.UTF8;
    end;
    try
      Bytes := Encoding.GetBytes(Text);
    except
      Bytes := nil;
    end;
    if Bytes <> nil then begin
      Result := AJHash64Bytes(Bytes, Length(Bytes), Result, AddValue, IterativeMixRounds, FinishMixRounds);
    end;
  end;
end;

end.

⎙ Print AJHash.PAS

You can also view the source code as plain text, AJHash.PAS.TXT.

The source code is related to N/A.

www.andreas-software.com

Copyright © 1998-2021, Andreas Jönsson. All rights reserved.

In Swedish?
View this page in Swedish