diff --git a/packages/fcl-hash/src/fprsa.pas b/packages/fcl-hash/src/fprsa.pas
index 066c2a8283..7a51dcd6a7 100644
--- a/packages/fcl-hash/src/fprsa.pas
+++ b/packages/fcl-hash/src/fprsa.pas
@@ -873,7 +873,7 @@ begin
   // Note: directly into ZeroesHashSalt
 
   // "3.  If emLen < hLen + sLen + 2, error"
-  if EncodedLen < HashLen + SaltLen + 2 then
+  if EncodedLen < HashLen + DWord(SaltLen) + 2 then
     exit(20220501221837);
 
   // "4.  Generate a random octet string salt of length sLen; if sLen = 0,
@@ -883,7 +883,7 @@ begin
   // "5.  Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;
   //      M' is an octet string of length 8 + hLen + sLen with eight
   //      initial zero octets."
-  SetLength(ZeroesHashSalt{%H-},8+HashLen+SaltLen);
+  SetLength(ZeroesHashSalt{%H-},8+HashLen+DWord(SaltLen));
   FillByte(ZeroesHashSalt[0],8,0);
   MsgHashP:=@ZeroesHashSalt[8];
   HashFunc^.Func(Input,InLen,MsgHashP);
@@ -935,8 +935,7 @@ function EMSA_PSS_Verify(Msg: PByte; MsgLen: DWord; EncodedMsg: PByte;
   EncodedBits: DWord; HashFunc: PRSAHashFuncInfo; SaltLen: integer): int64;
 // RFC 3447 9.1.2 Verification operation
 var
-  HashLen: Word;
-  EncodedLen, DBLen, i, Padding: DWord;
+  HashLen, EncodedLen, DBLen, i, Padding: DWord;
   MaskedDB, HashP, SaltP: PByte;
   MsgHash, DBMask, Msg2, Hash2, DB: TBytes;
 begin
@@ -966,7 +965,7 @@ begin
   begin
     if EncodedLen < HashLen + 2 then
       exit(20220502222313);
-  end else if EncodedLen < HashLen + SaltLen + 2 then
+  end else if EncodedLen < HashLen + DWord(SaltLen) + 2 then
     exit(20220502205834);
 
   // "4. If the rightmost octet of EM does not have hexadecimal value 0xbc, error."
@@ -1024,7 +1023,7 @@ begin
   // "12.  Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
   //       M' is an octet string of length 8 + hLen + sLen with eight
   //       initial zero octets.
-  SetLength(Msg2{%H-},8 + HashLen + SaltLen);
+  SetLength(Msg2{%H-},8 + HashLen + DWord(SaltLen));
   FillByte(Msg2[0],8,0);
   System.Move(MsgHash[0],Msg2[8],HashLen);
   System.Move(SaltP^,Msg2[8+HashLen],SaltLen);
diff --git a/packages/fcl-hash/src/fptlsbigint.pas b/packages/fcl-hash/src/fptlsbigint.pas
index f9d1fbfd7d..9078731d31 100644
--- a/packages/fcl-hash/src/fptlsbigint.pas
+++ b/packages/fcl-hash/src/fptlsbigint.pas
@@ -8,14 +8,17 @@
 {$h+}
 {$MODESWITCH advancedrecords}
 {$R-}
+{$Q-}
 
 unit fpTLSBigInt;
 
+{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined}
+
 interface
 
 uses SysUtils;
 
-{ $DEFINE BIGINT_DEBUG}         // Enable debug output/functions for BitInt unit
+{off $DEFINE BIGINT_DEBUG}         // Enable debug output/functions for BitInt unit
 
 const
   // Maintain a number of precomputed variables when doing reduction
@@ -108,7 +111,10 @@ function BISquare(var Context: TBigIntContext; BI: PBigInt): PBigInt; inline;
 
 function BICRT(var Context: TBigIntContext; BI, DP, DQ, P, Q, QInv: PBigInt): PBigInt;
 
-procedure BItoString(BI: PBigInt; out S: AnsiString);
+// Convert a bigint to a string of hex characters @Result[BI.Size*2]
+function BIToString(BI: PBigInt): AnsiString; overload;
+function BIToDbgString(BI: PBigInt): AnsiString; overload;
+procedure BIToString(BI: PBigInt; out S: AnsiString); overload;
 function StringToBI(var Context: TBigIntContext; const Value: AnsiString): PBigInt;
 
 implementation
@@ -260,10 +266,10 @@ begin
   Result := BIAllocate(Context, N + 1);
   R := Result^.Components;
   A := BIA^.Components;
-  FillChar(R^, (N+1) * BIGINT_COMP_BYTE_SIZE, 0);
+  FillByte(R^, (N+1) * BIGINT_COMP_BYTE_SIZE, 0);
   repeat
-    Tmp := R^ + TBILongComponent(A[J]) * B + Carry; // Avoid overflow
-    R^ := Tmp; // Downsize
+    Tmp := TBILongComponent(R^) + TBILongComponent(A[J]) * B + Carry; // Avoid overflow
+    R^ := DWord(Tmp and $ffffffff); // Downsize
     Inc(R);
     Carry := Tmp shr BIGINT_COMP_BIT_SIZE;
     Inc(J);
@@ -287,7 +293,7 @@ begin
   R := 0;
   repeat
     R := (R shl BIGINT_COMP_BIT_SIZE) + BIR^.Components[I];
-    BIR^.Components[I] := R div Denom;
+    BIR^.Components[I] := DWord((R div Denom) and $ffffffff);
     R := R mod Denom;
     Dec(I);
   until I < 0;
@@ -391,8 +397,8 @@ begin
     repeat
       if (InnerPartial > 0) and (RIndex >= InnerPartial) then
         Break;
-      Tmp := SR[RIndex] + TBILongComponent(SA[J]) * SB[I] + Carry; // Avoid overflow
-      SR[RIndex] := Tmp; // Downsize
+      Tmp := TBILongComponent(SR[RIndex]) + TBILongComponent(SA[J]) * SB[I] + Carry; // Avoid overflow
+      SR[RIndex] := TBIComponent(Tmp and $ffffffff); // Downsize
       Inc(RIndex);
       Carry := Tmp shr BIGINT_COMP_BIT_SIZE;
       Inc(J);
@@ -424,7 +430,7 @@ begin
   FillChar(W^,BIR^.Size * BIGINT_COMP_BYTE_SIZE,0);
   repeat
     Tmp := W[2*I] + TBILongComponent(X[I]) * X[I]; // Avoid overflow
-    W[2 * I] := Tmp;
+    W[2 * I] := DWord(Tmp and $ffffffff);
     Carry := Tmp shr BIGINT_COMP_BIT_SIZE;
     J := I+1;
     while J < T do
@@ -440,14 +446,14 @@ begin
       if BIGINT_COMP_MAX-Tmp < Carry then
         C := 1;
       Tmp := Tmp + Carry;
-      W[I + J] := Tmp;
+      W[I + J] := DWord(Tmp and $ffffffff);
       Carry := Tmp shr BIGINT_COMP_BIT_SIZE;
       if C > 0 then
         Carry := Carry + BIGINT_COMP_RADIX;
       Inc(J);
     end;
     Tmp := W[I+T]+Carry;
-    W[I+T] := Tmp;
+    W[I+T] := DWord(Tmp and $ffffffff);
     W[I+T+1] := Tmp shr BIGINT_COMP_BIT_SIZE;
     Inc(I);
   until I >= T;
@@ -658,7 +664,7 @@ end;
 function BIImport(var Context: TBigIntContext; const Data: AnsiString): PBigInt; overload;
 
 begin
-  Result:=BIImport(Context,TEncoding.UTF8.GetAnsiBytes(Data));
+  Result:=BIImport(Context,@Data[1],length(Data));
 end;
 
 
@@ -783,7 +789,7 @@ end;
 // @IsMod: Determines if this is a normal division (False) or a reduction (True)}
 function BIDivide(var Context: TBigIntContext; U, V: PBigInt; IsMod: Boolean): PBigInt;
 
-  function BIDivide_V1(V:PBigInt):TBIComponent; inline;
+  function BIDivide_V1(V: PBigInt): TBIComponent; inline;
   begin // V1 for division
     Result := V^.Components[V^.Size-1];
   end;
@@ -828,7 +834,7 @@ begin
   TmpU := BIAllocate(Context, N+1);
   BITrim(V); // Make sure we have no leading 0's
   D := BIGINT_COMP_RADIX div (TBILongComponent(BIDivide_V1(V)) + 1);
-  FillChar(Quotient^.Components^, Quotient^.Size * BIGINT_COMP_BYTE_SIZE, 0);
+  FillByte(Quotient^.Components^, Quotient^.Size * BIGINT_COMP_BYTE_SIZE, 0);
   if D > 1 then
   begin // Normalize
     U := BIIntMultiply(Context,U,D);
@@ -852,8 +858,11 @@ begin
       if (V^.Size > 1) and (BIDivide_V2(V) > 0) then
       begin
         // We are implementing the following: if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - q_dash*V1)*COMP_RADIX) + U(2))) ...
-        Inner := BIGINT_COMP_RADIX * BIDivide_U(TmpU, 0) + BIDivide_U(TmpU, 1) - TBILongComponent(QDash) * BIDivide_V1(V); {Avoid overflow}
-        if (TBILongComponent(BIDivide_V2(V)) * QDash) > (TBILongComponent(Inner) * BIGINT_COMP_RADIX + BIDivide_U(TmpU, 2)) then {Avoid overflow}
+        Inner := (BIGINT_COMP_RADIX * BIDivide_U(TmpU, 0) + BIDivide_U(TmpU, 1)
+                  - TBILongComponent(QDash) * BIDivide_V1(V))
+                  and $ffffffff; {Avoid overflow}
+        if (TBILongComponent(BIDivide_V2(V)) * QDash) >
+            (TBILongComponent(Inner) * BIGINT_COMP_RADIX + BIDivide_U(TmpU, 2)) then {Avoid overflow}
           Dec(QDash);
       end;
     end;
@@ -882,7 +891,7 @@ begin
   BIRelease(Context, V);
   if IsMod then
   begin // Get the remainder
-    BIRelease(Context, Quotient);;
+    BIRelease(Context, Quotient);
     BITrim(U);
     Result := BIIntDivide(U, D);
   end else
@@ -1165,33 +1174,48 @@ begin
   Result := BIAdd(Context, M2, BIMultiply(Context, Q, H));
 end;
 
-// Convert a bigint to a string of hex characters
-// @Result[BI.Size*2]
-procedure BItoString(BI: PBigInt; out S: AnsiString);
+function BIToString(BI: PBigInt): AnsiString;
 const
   Digits: Array[0..15] of char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
 var
   I,J,K: Integer;
   Num: TBIComponent;
-  Mask: TBIComponent;
 begin
-  S:='';
+  Result:='';
   if BI = nil then
     Exit;
-  SetLength(S,BI^.Size*BIGINT_COMP_NUM_NIBBLES);
+  SetLength(Result,BI^.Size*BIGINT_COMP_NUM_NIBBLES);
   K:=1;
   for I := BI^.Size-1 downto 0 do
   begin
     for J := BIGINT_COMP_NUM_NIBBLES-1 downto 0 do
     begin
-      Mask := $0F shl (J*4);
-      Num := (BI^.Components[I] and Mask) shr (J*4);
-      S[K]:=Digits[Num and $F];
+      Num := (BI^.Components[I] shr (J*4)) and $F;
+      Result[K]:=Digits[Num];
       inc(K);
     end;
   end;
 end;
 
+function BIToDbgString(BI: PBigInt): AnsiString;
+var
+  Num, I, J: Integer;
+begin
+  Result:='';
+  if BI=nil then
+    exit;
+  Num:=0;
+  for I := BI^.Size-1 downto 0 do
+    for J := BIGINT_COMP_NUM_NIBBLES-1 downto 0 do
+      inc(Num, (BI^.Components[I] shr (J*4)) and $F);
+  Result:='{'+IntToStr(Num)+'}'+BIToString(BI);
+end;
+
+procedure BIToString(BI: PBigInt; out S: AnsiString);
+begin
+  S:=BIToString(BI);
+end;
+
 // Convert a string of hex characters to a bigint
 function StringToBI(var Context: TBigIntContext; const Value: AnsiString): PBigInt;
 const