Andreas Software - Källkod - AJHash.PAS

Min egen hash-funktion AJ Hash, inkluderat är 32-bit och 64-bit, men den kan enkelt byggas ut


unit AJHash;

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

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 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;
    for Loop := 0 to (Length - 1) do begin
      Index := Loop and 3;
      ByteArray[Index] := ByteArray[Index] xor Bytes[Loop];
      ByteArray[Index] := ByteArray[Index] + AddValue;
      if Index = 3 then begin
        for I := 0 to (IterativeMixRounds - 1) 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
      for I := 0 to (IterativeMixRounds - 1) 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;
    for I := 0 to (FinishMixRounds - 1) 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 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;
    for Loop := 0 to (Length - 1) do begin
      Index := Loop and 7;
      ByteArray[Index] := ByteArray[Index] xor Bytes[Loop];
      ByteArray[Index] := ByteArray[Index] + AddValue;
      if Index = 7 then begin
        for I := 0 to (IterativeMixRounds - 1) 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
      for I := 0 to (IterativeMixRounds - 1) 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;
    for I := 0 to (FinishMixRounds - 1) 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.

[ Källkod ]

In English?
View this page in English