-
Notifications
You must be signed in to change notification settings - Fork 3
/
nosodig.crypto68.pas
141 lines (115 loc) · 2.82 KB
/
nosodig.crypto68.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
unit NosoDig.Crypto68;
{$ifdef FPC}
{$mode DELPHI}{$H+}
{$endif}
{$ifopt D+}
{$define DEBUG}
{$endif}
interface
uses
Classes,
SysUtils;
type
THash32 = array[0..31] of Char; { 256 bits }
function NosoHash68(S: String): THash32;
function GetHashDiff68(const HashA, HashB: THash32): THash32;
implementation
uses
MD5;
type
PByteHash128 = ^TByteHash128;
TByteHash128 = packed array[0..127] of Byte; { 1024 bits }
PAsciiLookup = ^TAsciiLookup;
TAsciiLookup = packed array[0..511] of Byte; { keep it power-of-two }
const
MAX_DIFF = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
var
AsciiLookupTable: TAsciiLookup;
function BinToHexFast(const B: Byte): Char;{$ifndef DEBUG}inline;{$endif}
const
bin2hex_lookup: array[0..15] of Char =
('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
begin
if (B > 15) then
Exit(#0);
Result := bin2hex_lookup[B]
end;
function HexToBinFast(const C: Char): Byte;{$ifndef DEBUG}inline;{$endif}
const
hex2bin_lookup: array['0'..'F'] of Byte =
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15);
begin
Assert( ((C>='0') and (C<='9')) or ((C>='A') and (C<='F')));
Result := hex2bin_lookup[C];
end;
function NosoHash68(S: String): THash32;
function Mutate(const pHash: Pointer): Pointer;
var
i, n, LFirst: UInt8;
p: PByte;
begin
Result := pHash;
for n:=127 downto 0 do
begin
p := Result;
LFirst := p^;
for i:=126 downto 0 do
begin
p^ := AsciiLookupTable[ (p^ + PByte(p+1)^) ];
Inc(p)
end;
p^ := AsciiLookupTable[ (p^ + LFirst) ]
end
end;
var
i: UInt8;
p: PByte;
const
NOSOHASH_FILLER = '%)+/5;=CGIOSYaegk';
begin
Result := '';
if Length(S) > 63 then
SetLength(S, 0);
for i := 1 to Length(S) do
if (Ord(S[i]) < 33) or (Ord(S[i]) > 126) then
begin
SetLength(S, 0);
Break;
end;
repeat
S := S + NOSOHASH_FILLER;
until Length(S) >= 128;
{ For some strange reason, calling this Mutate() function here
is faster than inline code in 32-bit systems }
p := Mutate(PAnsiChar(S));
for i:=0 to 31 do
begin
Result[i] := BinToHexFast(AsciiLookupTable[ (p^ + PByte(p+1)^ + PByte(p+2)^ + PByte(p+3)^) ] mod 16);
Inc(p, 4);
end;
Result := MD5Print(MDBuffer(Result, SizeOf(THash32), MD_VERSION_5)).ToUpper;
end;
function GetHashDiff68(const HashA, HashB: THash32): THash32;
var
i: Integer;
begin
Result := MAX_DIFF;
for i := 0 to 31 do
Result[i] := HexStr(Abs(HexToBinFast(HashB[i]) - HexToBinFast(HashA[i])), 1)[1];
end;
procedure FillLookupTables;
var
i, n: Word;
begin
for i:=Low(AsciiLookupTable) to High(AsciiLookupTable) do
begin
if (i < 32) or (i > 504) then
continue;
n := i;
while n > 126 do Dec(n, 95);
AsciiLookupTable[i] := n;
end;
end;
initialization
FillLookupTables;
end.