Learning/AoC/2015/day_4/day_4.adb
2025-03-22 14:47:45 +01:00

210 lines
6.6 KiB
Ada

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces;
procedure Day_4 is
type Uint32 is mod 2**32;
type Uint64 is mod 2**64;
type Uint128 is mod 2**128;
type Byte is range 0 .. 2**8 -1;
for Byte'Size use 8;
package Uint128_IO is new Ada.Text_IO.Modular_IO( Uint128 );
package Uint32_IO is new Ada.Text_IO.Modular_IO( Uint32 );
type Byte_Array is array (Natural range <>) of Byte;
type Uint32_Array is array (Natural range <>) of Uint32;
function Hex( Num : Uint32 ) return String is
Str : String( 1 .. 8 );
Tally : Uint32 := Num;
Temp : Uint32;
begin
for I in reverse Str'Range loop
Temp := Tally mod 16;
case Temp is
when 0 .. 9 => Str(I) := Character'Val(48 + Temp);
when 10 .. 15 => Str(I) := Character'val(65 + (Temp - 10));
when others => Str(I) := 'x';
end case;
Tally := Tally / 16;
end loop;
return Str;
end Hex;
function Pad( Key : String ) return Byte_Array is
Size : Natural := Key'Length;
Mod_Size : Natural := Size mod 64;
Pad_Size : Natural;
Original : Uint64 := Uint64(Size) * 8;
begin
if Mod_Size <= 55 then
Pad_Size := 55 - Mod_Size;
else
Pad_Size := (63 - Mod_Size) + 56;
end if;
declare
B : Byte_Array( 0 .. Pad_Size + Size + 8);
begin
for I in Key'Range loop
B(I-1) := Byte(Character'Pos(Key(I)));
end loop;
B(Key'Last) := 16#80#;
for I in 1 .. Pad_Size loop
B(Key'Last + I) := 0;
end loop;
for I in 0 .. 7 loop
B(B'Last - (7-I)) := Byte((Original / 2**(8*I)) and 16#FF#);
end loop;
return B;
end;
end Pad;
function MD5( Key : String ) return Uint128 is
S : Uint32_Array( 0 .. 63 ) := (
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
);
K : Uint32_Array( 0 .. 63 ) := (
16#d76aa478#, 16#e8c7b756#, 16#242070db#, 16#c1bdceee#,
16#f57c0faf#, 16#4787c62a#, 16#a8304613#, 16#fd469501#,
16#698098d8#, 16#8b44f7af#, 16#ffff5bb1#, 16#895cd7be#,
16#6b901122#, 16#fd987193#, 16#a679438e#, 16#49b40821#,
16#f61e2562#, 16#c040b340#, 16#265e5a51#, 16#e9b6c7aa#,
16#d62f105d#, 16#02441453#, 16#d8a1e681#, 16#e7d3fbc8#,
16#21e1cde6#, 16#c33707d6#, 16#f4d50d87#, 16#455a14ed#,
16#a9e3e905#, 16#fcefa3f8#, 16#676f02d9#, 16#8d2a4c8a#,
16#fffa3942#, 16#8771f681#, 16#6d9d6122#, 16#fde5380c#,
16#a4beea44#, 16#4bdecfa9#, 16#f6bb4b60#, 16#bebfbc70#,
16#289b7ec6#, 16#eaa127fa#, 16#d4ef3085#, 16#04881d05#,
16#d9d4d039#, 16#e6db99e5#, 16#1fa27cf8#, 16#c4ac5665#,
16#f4292244#, 16#432aff97#, 16#ab9423a7#, 16#fc93a039#,
16#655b59c3#, 16#8f0ccc92#, 16#ffeff47d#, 16#85845dd1#,
16#6fa87e4f#, 16#fe2ce6e0#, 16#a3014314#, 16#4e0811a1#,
16#f7537e82#, 16#bd3af235#, 16#2ad7d2bb#, 16#eb86d391#
);
A0 : Uint32 := 16#67452301#;
B0 : Uint32 := 16#efcdab89#;
C0 : Uint32 := 16#98badcfe#;
D0 : Uint32 := 16#10325476#;
Data : Byte_Array := Pad(Key);
Output : Uint128 := 0;
begin
for I in 0 .. (Data'Length / 64) - 1 loop
declare
M : Uint32_Array( 0 .. 15 );
A : Uint32 := A0;
B : Uint32 := B0;
C : Uint32 := C0;
D : Uint32 := D0;
F : Uint32;
G : Uint32;
begin
for J in 0 .. 15 loop
declare
Index : Integer := (I*64) + (J*4);
begin
M(J) := Uint32(Data(Index));
M(J) := @ + Uint32(Data(Index + 1)) * 2**8;
M(J) := @ + Uint32(Data(Index + 2)) * 2**16;
M(J) := @ + Uint32(Data(Index + 3)) * 2**24;
end;
end loop;
for J in 0 .. 63 loop
if J >= 0 and J <= 15 then
F := (B and C) or ((not B) and D);
G := Uint32(J);
elsif J >= 16 and J <= 31 then
F := (D and B) or ((not D) and C);
G := (5*Uint32(J) + 1) mod 16;
elsif J >= 32 and J <= 47 then
F := B xor C xor D;
G := (3*Uint32(J) + 5) mod 16;
else
F := C xor (B or (not D));
G := (7*Uint32(J)) mod 16;
end if;
F := F + A + K(J) + M(Integer(G));
A := D;
D := C;
C := B;
B := B + Uint32(
Interfaces.Rotate_Left(
Interfaces.Unsigned_32(F), Natural(S(J))));
end loop;
A0 := @ + A;
B0 := @ + B;
C0 := @ + C;
D0 := @ + D;
end;
end loop;
declare
Output_Arr : Uint32_Array := [A0, B0, C0, D0];
begin
for I in 0 .. 3 loop
declare
Nibble : Uint32 := Output_Arr(I);
begin
for J in 0 .. 3 loop
Output := (@ * 2**8) + Uint128(Nibble mod 2**8);
Nibble := @ / 2**8;
end loop;
end;
end loop;
end;
return Output;
end MD5;
Base_Key : String := "yzbqklnj";
Index : Positive := 1;
MD5_Hash : Uint128;
begin
Uint128_IO.Put(MD5("a"), Base => 16);
New_Line;
loop
declare
Num : String := Index'Image;
begin
Put_Line("Testing: " & Base_Key & Num(Num'First + 1 .. Num'Last));
MD5_Hash := MD5(Base_Key & Num( Num'First + 1 .. Num'Last));
Uint128_IO.Put(MD5_Hash, Base => 16);
New_Line;
end;
exit when (MD5_Hash and 16#FFFFFF00000000000000000000000000#) = 0;
Index := @ + 1;
end loop;
Put_Line("Key is" & Index'Image);
end Day_4;