Ugochukwu Mmaduekwe пре 1 недеља
родитељ
комит
53dc02fb91

+ 14 - 8
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -269,7 +269,6 @@ uses
   ClpIMac in '..\..\CryptoLib\src\Interfaces\Crypto\Macs\ClpIMac.pas',
   ClpIMacFactory in '..\..\CryptoLib\src\Interfaces\Crypto\ClpIMacFactory.pas',
   ClpIMultipliers in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIMultipliers.pas',
-  ClpInterleave in '..\..\CryptoLib\src\Math\Raw\ClpInterleave.pas',
   ClpIOaepEncoding in '..\..\CryptoLib\src\Interfaces\Crypto\Encodings\ClpIOaepEncoding.pas',
   ClpIOidTokenizer in '..\..\CryptoLib\src\Interfaces\Asn1\ClpIOidTokenizer.pas',
   ClpIPaddedBufferedBlockCipher in '..\..\CryptoLib\src\Interfaces\Crypto\Paddings\ClpIPaddedBufferedBlockCipher.pas',
@@ -361,14 +360,7 @@ uses
   ClpLongArray in '..\..\CryptoLib\src\Math\EC\ClpLongArray.pas',
   ClpMacUtilities in '..\..\CryptoLib\src\Crypto\Macs\ClpMacUtilities.pas',
   ClpMiscObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Misc\ClpMiscObjectIdentifiers.pas',
-  ClpMod in '..\..\CryptoLib\src\Math\Raw\ClpMod.pas',
   ClpMultipliers in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpMultipliers.pas',
-  ClpNat in '..\..\CryptoLib\src\Math\Raw\ClpNat.pas',
-  ClpNat192 in '..\..\CryptoLib\src\Math\Raw\ClpNat192.pas',
-  ClpNat256 in '..\..\CryptoLib\src\Math\Raw\ClpNat256.pas',
-  ClpNat320 in '..\..\CryptoLib\src\Math\Raw\ClpNat320.pas',
-  ClpNat384 in '..\..\CryptoLib\src\Math\Raw\ClpNat384.pas',
-  ClpNat512 in '..\..\CryptoLib\src\Math\Raw\ClpNat512.pas',
   ClpNistNamedCurves in '..\..\CryptoLib\src\Asn1\Nist\ClpNistNamedCurves.pas',
   ClpNistObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Nist\ClpNistObjectIdentifiers.pas',
   ClpNoOpDigest in '..\..\CryptoLib\src\Crypto\Digests\ClpNoOpDigest.pas',
@@ -515,6 +507,20 @@ uses
   ClpBinaryPrimitives in '..\..\CryptoLib\src\BitUtilities\ClpBinaryPrimitives.pas',
   ClpBitUtilities in '..\..\CryptoLib\src\BitUtilities\ClpBitUtilities.pas',
   ClpPack in '..\..\CryptoLib\src\BitUtilities\ClpPack.pas',
+  ClpBits in '..\..\CryptoLib\src\Math\Raw\ClpBits.pas',
+  ClpMod in '..\..\CryptoLib\src\Math\Raw\ClpMod.pas',
+  ClpInterleave in '..\..\CryptoLib\src\Math\Raw\ClpInterleave.pas',
+  ClpNat in '..\..\CryptoLib\src\Math\Raw\ClpNat.pas',
+  ClpNat128 in '..\..\CryptoLib\src\Math\Raw\ClpNat128.pas',
+  ClpNat160 in '..\..\CryptoLib\src\Math\Raw\ClpNat160.pas',
+  ClpNat192 in '..\..\CryptoLib\src\Math\Raw\ClpNat192.pas',
+  ClpNat224 in '..\..\CryptoLib\src\Math\Raw\ClpNat224.pas',
+  ClpNat256 in '..\..\CryptoLib\src\Math\Raw\ClpNat256.pas',
+  ClpNat320 in '..\..\CryptoLib\src\Math\Raw\ClpNat320.pas',
+  ClpNat384 in '..\..\CryptoLib\src\Math\Raw\ClpNat384.pas',
+  ClpNat448 in '..\..\CryptoLib\src\Math\Raw\ClpNat448.pas',
+  ClpNat512 in '..\..\CryptoLib\src\Math\Raw\ClpNat512.pas',
+  ClpNat576 in '..\..\CryptoLib\src\Math\Raw\ClpNat576.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIShortenedDigest in '..\src\Utils\ClpIShortenedDigest.pas',

+ 1 - 1
CryptoLib/src/Crypto/Engines/ClpRsaBlindedEngine.pas

@@ -161,7 +161,7 @@ begin
     // blind = r^e mod m
     blind := r.ModPow(e, m);
     // unblind = r^(-1) mod m
-    unblind := TBigIntegers.ModOddInverseVar(m, r);
+    unblind := TBigIntegers.ModOddInverse(m, r);
 
     // Blind the input: blindedInput = blind * input mod m
     blindedInput := blind.Multiply(input).&Mod(m);

+ 1 - 1
CryptoLib/src/Crypto/Engines/ClpRsaBlindingEngine.pas

@@ -150,7 +150,7 @@ var
   m, blindFactorInverse, res: TBigInteger;
 begin
   m := FKey.Modulus;
-  blindFactorInverse := TBigIntegers.ModOddInverseVar(m, FBlindingFactor);
+  blindFactorInverse := TBigIntegers.ModOddInverse(m, FBlindingFactor);
   res := blindedMsg.Multiply(blindFactorInverse);
   Result := res.&Mod(m);
 end;

+ 3 - 23
CryptoLib/src/Crypto/Generators/ClpRsaKeyPairGenerator.pas

@@ -23,6 +23,7 @@ interface
 
 uses
   SysUtils,
+  ClpArrayUtilities,
   ClpBigInteger,
   ClpBigIntegers,
   ClpIKeyGenerationParameters,
@@ -69,9 +70,6 @@ type
     function ChooseRandomPrime(bitLength: Int32;
       const e: TBigInteger): TBigInteger;
 
-
-    class function ArrayContains(const arr: TCryptoLibInt32Array; value: Int32): Boolean; static;
-
   public
     constructor Create();
 
@@ -108,31 +106,13 @@ begin
       FDefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
 end;
 
-class function TRsaKeyPairGenerator.ArrayContains(const arr: TCryptoLibInt32Array;
-  value: Int32): Boolean;
-var
-  i: Int32;
-begin
-  for i := 0 to System.Length(arr) - 1 do
-  begin
-    if arr[i] = value then
-    begin
-      Result := True;
-      Exit;
-    end;
-  end;
-  Result := False;
-end;
-
-
-
 function TRsaKeyPairGenerator.ChooseRandomPrime(bitLength: Int32;
   const e: TBigInteger): TBigInteger;
 var
   p, pSub1: TBigInteger;
   eIsKnownOddPrime: Boolean;
 begin
-  eIsKnownOddPrime := (e.BitLength <= FSpecialEBits) and ArrayContains(FSpecialEValues, e.Int32Value);
+  eIsKnownOddPrime := (e.BitLength <= FSpecialEBits) and TArrayUtilities.Contains<Int32>(FSpecialEValues, e.Int32Value);
 
   while True do
   begin
@@ -248,7 +228,7 @@ begin
     // Calculate CRT parameters
     dP := d.Remainder(pSub1);
     dQ := d.Remainder(qSub1);
-    qInv := TBigIntegers.ModOddInverseVar(p, q);
+    qInv := TBigIntegers.ModOddInverse(p, q);
 
     // Create key pair
     pubKey := TRsaKeyParameters.Create(False, n, e) as IRsaKeyParameters;

+ 24 - 3
CryptoLib/src/GeneralUtilities/ClpArrayUtilities.pas

@@ -89,8 +89,11 @@ type
 
     class function NoZeroes(const AData: TCryptoLibByteArray): Boolean; static;
 
-    class function Exists<T>(const AData: TCryptoLibGenericArray<T>;
-      const APredicate: TFunc<T, Boolean>): Boolean; static;
+    class function Contains<T>(const AData: TCryptoLibGenericArray<T>;
+      const APredicate: TFunc<T, Boolean>): Boolean; overload; static;
+
+    class function Contains<T>(const AData: TCryptoLibGenericArray<T>;
+      const AValue: T; const AComparer: IEqualityComparer<T> = nil): Boolean; overload; static;
 
     class function Map<T, TResult>(const AData: TCryptoLibGenericArray<T>;
       const AFunc: TFunc<T, TResult>): TCryptoLibGenericArray<TResult>; static;
@@ -412,7 +415,7 @@ begin
     Result[I] := ACloneFunc(AData[I]);
 end;
 
-class function TArrayUtilities.Exists<T>(const AData: TCryptoLibGenericArray<T>;
+class function TArrayUtilities.Contains<T>(const AData: TCryptoLibGenericArray<T>;
   const APredicate: TFunc<T, Boolean>): Boolean;
 var
   I: Int32;
@@ -425,6 +428,24 @@ begin
   Result := False;
 end;
 
+class function TArrayUtilities.Contains<T>(const AData: TCryptoLibGenericArray<T>;
+  const AValue: T; const AComparer: IEqualityComparer<T>): Boolean;
+var
+  I: Int32;
+  LComparer: IEqualityComparer<T>;
+begin
+  if (AData = nil) or (System.Length(AData) = 0) then
+    Exit(False);
+  if AComparer = nil then
+    LComparer := TEqualityComparer<T>.Default
+  else
+    LComparer := AComparer;
+  for I := System.Low(AData) to System.High(AData) do
+    if LComparer.Equals(AData[I], AValue) then
+      Exit(True);
+  Result := False;
+end;
+
 class function TArrayUtilities.Map<T, TResult>(const AData: TCryptoLibGenericArray<T>;
   const AFunc: TFunc<T, TResult>): TCryptoLibGenericArray<TResult>;
 var

+ 101 - 22
CryptoLib/src/Math/ClpBigIntegers.pas

@@ -25,6 +25,8 @@ uses
   SysUtils,
   Classes,
   ClpBigInteger,
+  ClpMod,
+  ClpNat,
   ClpISecureRandom,
   ClpCryptoLibTypes;
 
@@ -33,6 +35,7 @@ resourcestring
   SMinMayNotBeGreaterThanMax = '''min'' may not be greater than ''max''';
   SMustBeOdd = 'must be odd';
   SModulusNotPositive = 'BigInteger: modulus not positive';
+  SBigIntegerNotInvertible = 'BigInteger not invertible';
 
 type
   /// <summary>
@@ -131,7 +134,15 @@ type
     class procedure WriteUnsignedByteArray(const AOutStr: TStream; const AN: TBigInteger); static;
 
     /// <summary>
-    /// ModOddInverseVar.
+    /// ModOddInverse: modular inverse of X mod M (M must be odd). Throws if not invertible.
+    /// </summary>
+    /// <param name="AM">the modulus (must be odd).</param>
+    /// <param name="AX">the value to invert.</param>
+    /// <returns>inverse.</returns>
+    class function ModOddInverse(const AM, AX: TBigInteger): TBigInteger; static;
+
+    /// <summary>
+    /// ModOddInverseVar: variable-time modular inverse of X mod M (M must be odd). Throws if not invertible.
     /// </summary>
     /// <param name="AM">the modulus (must be odd).</param>
     /// <param name="AX">the value to invert.</param>
@@ -139,7 +150,15 @@ type
     class function ModOddInverseVar(const AM, AX: TBigInteger): TBigInteger; static;
 
     /// <summary>
-    /// ModOddIsCoprimeVar.
+    /// ModOddIsCoprime: whether X is coprime to M (M must be odd).
+    /// </summary>
+    /// <param name="AM">the modulus (must be odd).</param>
+    /// <param name="AX">the value to check.</param>
+    /// <returns>whether is coprime or not.</returns>
+    class function ModOddIsCoprime(const AM, AX: TBigInteger): Boolean; static;
+
+    /// <summary>
+    /// ModOddIsCoprimeVar: variable-time check whether X is coprime to M (M must be odd).
     /// </summary>
     /// <param name="AM">the modulus (must be odd).</param>
     /// <param name="AX">the value to check.</param>
@@ -282,9 +301,39 @@ begin
   AOutStr.Write(LBuffer, 0, System.Length(LBuffer));
 end;
 
+class function TBigIntegers.ModOddInverse(const AM, AX: TBigInteger): TBigInteger;
+var
+  LBits, LLen: Int32;
+  LReducedX: TBigInteger;
+  LM, LX, LZ: TCryptoLibUInt32Array;
+begin
+  if not AM.TestBit(0) then
+    raise EArgumentCryptoLibException.Create(SMustBeOdd);
+
+  if AM.SignValue <> 1 then
+    raise EArithmeticCryptoLibException.Create(SModulusNotPositive);
+
+  LReducedX := AX;
+  if (LReducedX.SignValue < 0) or (LReducedX.BitLength > AM.BitLength) then
+    LReducedX := LReducedX.&Mod(AM);
+
+  LBits := AM.BitLength;
+  LM := TNat.FromBigInteger(LBits, AM);
+  LX := TNat.FromBigInteger(LBits, LReducedX);
+  LLen := System.Length(LM);
+  LZ := TNat.Create(LLen);
+
+  if TMod.ModOddInverse(LM, LX, LZ) = 0 then
+    raise EArithmeticCryptoLibException.Create(SBigIntegerNotInvertible);
+
+  Result := TNat.ToBigInteger(LLen, LZ);
+end;
+
 class function TBigIntegers.ModOddInverseVar(const AM, AX: TBigInteger): TBigInteger;
 var
-  LX: TBigInteger;
+  LBits, LLen: Int32;
+  LReducedX: TBigInteger;
+  LM, LX, LZ: TCryptoLibUInt32Array;
 begin
   if not AM.TestBit(0) then
     raise EArgumentCryptoLibException.Create(SMustBeOdd);
@@ -298,26 +347,33 @@ begin
     Exit;
   end;
 
-  LX := AX;
-
-  if (LX.SignValue < 0) or (LX.BitLength > AM.BitLength) then
-  begin
-    LX := LX.&Mod(AM);
-  end;
+  LReducedX := AX;
+  if (LReducedX.SignValue < 0) or (LReducedX.BitLength > AM.BitLength) then
+    LReducedX := LReducedX.&Mod(AM);
 
-  if LX.Equals(One) then
+  if LReducedX.Equals(One) then
   begin
     Result := One;
     Exit;
   end;
 
-  // Use BigInteger's built-in ModInverse
-  Result := LX.ModInverse(AM);
+  LBits := AM.BitLength;
+  LM := TNat.FromBigInteger(LBits, AM);
+  LX := TNat.FromBigInteger(LBits, LReducedX);
+  LLen := System.Length(LM);
+  LZ := TNat.Create(LLen);
+
+  if not TMod.ModOddInverseVar(LM, LX, LZ) then
+    raise EArithmeticCryptoLibException.Create(SBigIntegerNotInvertible);
+
+  Result := TNat.ToBigInteger(LLen, LZ);
 end;
 
-class function TBigIntegers.ModOddIsCoprimeVar(const AM, AX: TBigInteger): Boolean;
+class function TBigIntegers.ModOddIsCoprime(const AM, AX: TBigInteger): Boolean;
 var
-  LX: TBigInteger;
+  LBits: Int32;
+  LReducedX: TBigInteger;
+  LM, LX: TCryptoLibUInt32Array;
 begin
   if not AM.TestBit(0) then
     raise EArgumentCryptoLibException.Create(SMustBeOdd);
@@ -325,21 +381,44 @@ begin
   if AM.SignValue <> 1 then
     raise EArithmeticCryptoLibException.Create(SModulusNotPositive);
 
-  LX := AX;
+  LReducedX := AX;
+  if (LReducedX.SignValue < 0) or (LReducedX.BitLength > AM.BitLength) then
+    LReducedX := LReducedX.&Mod(AM);
 
-  if (LX.SignValue < 0) or (LX.BitLength > AM.BitLength) then
-  begin
-    LX := LX.&Mod(AM);
-  end;
+  LBits := AM.BitLength;
+  LM := TNat.FromBigInteger(LBits, AM);
+  LX := TNat.FromBigInteger(LBits, LReducedX);
+
+  Result := TMod.ModOddIsCoprime(LM, LX) <> 0;
+end;
+
+class function TBigIntegers.ModOddIsCoprimeVar(const AM, AX: TBigInteger): Boolean;
+var
+  LBits: Int32;
+  LReducedX: TBigInteger;
+  LM, LX: TCryptoLibUInt32Array;
+begin
+  if not AM.TestBit(0) then
+    raise EArgumentCryptoLibException.Create(SMustBeOdd);
+
+  if AM.SignValue <> 1 then
+    raise EArithmeticCryptoLibException.Create(SModulusNotPositive);
+
+  LReducedX := AX;
+  if (LReducedX.SignValue < 0) or (LReducedX.BitLength > AM.BitLength) then
+    LReducedX := LReducedX.&Mod(AM);
 
-  if LX.Equals(One) then
+  if LReducedX.Equals(One) then
   begin
     Result := True;
     Exit;
   end;
 
-  // Check if GCD(M, X) = 1
-  Result := AM.Gcd(LX).Equals(One);
+  LBits := AM.BitLength;
+  LM := TNat.FromBigInteger(LBits, AM);
+  LX := TNat.FromBigInteger(LBits, LReducedX);
+
+  Result := TMod.ModOddIsCoprimeVar(LM, LX);
 end;
 
 end.

+ 116 - 0
CryptoLib/src/Math/Raw/ClpBits.pas

@@ -0,0 +1,116 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpBits;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils;
+
+type
+  TBits = class sealed
+  public
+    class function BitPermuteStep(AX: UInt32; AM: UInt32; &AS: Int32): UInt32; overload; static;
+    class function BitPermuteStep(AX: UInt64; AM: UInt64; &AS: Int32): UInt64; overload; static;
+
+    class procedure BitPermuteStep2(var AHi: UInt32; var ALo: UInt32; AM: UInt32; &AS: Int32); overload; static;
+    class procedure BitPermuteStep2(var AHi: UInt64; var ALo: UInt64; AM: UInt64; &AS: Int32); overload; static;
+
+    class function BitPermuteStepSimple(AX: UInt32; AM: UInt32; &AS: Int32): UInt32; overload; static;
+    class function BitPermuteStepSimple(AX: UInt64; AM: UInt64; &AS: Int32): UInt64; overload; static;
+  end;
+
+implementation
+
+{ TBits }
+
+class function TBits.BitPermuteStep(AX: UInt32; AM: UInt32; &AS: Int32): UInt32;
+var
+  LT: UInt32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AM and (AM shl &AS)) = 0);
+  System.Assert(((AM shl &AS) shr &AS) = AM);
+  {$ENDIF}
+
+  LT := (AX xor (AX shr &AS)) and AM;
+  Result := LT xor (LT shl &AS) xor AX;
+end;
+
+class function TBits.BitPermuteStep(AX: UInt64; AM: UInt64; &AS: Int32): UInt64;
+var
+  LT: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AM and (AM shl &AS)) = 0);
+  System.Assert(((AM shl &AS) shr &AS) = AM);
+  {$ENDIF}
+
+  LT := (AX xor (AX shr &AS)) and AM;
+  Result := LT xor (LT shl &AS) xor AX;
+end;
+
+class procedure TBits.BitPermuteStep2(var AHi: UInt32; var ALo: UInt32; AM: UInt32; &AS: Int32);
+var
+  LT: UInt32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(((AM shl &AS) shr &AS) = AM);
+  {$ENDIF}
+
+  LT := ((ALo shr &AS) xor AHi) and AM;
+  ALo := ALo xor (LT shl &AS);
+  AHi := AHi xor LT;
+end;
+
+class procedure TBits.BitPermuteStep2(var AHi: UInt64; var ALo: UInt64; AM: UInt64; &AS: Int32);
+var
+  LT: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(((AM shl &AS) shr &AS) = AM);
+  {$ENDIF}
+
+  LT := ((ALo shr &AS) xor AHi) and AM;
+  ALo := ALo xor (LT shl &AS);
+  AHi := AHi xor LT;
+end;
+
+class function TBits.BitPermuteStepSimple(AX: UInt32; AM: UInt32; &AS: Int32): UInt32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AM shl &AS) = not AM);
+  System.Assert((AM and (not AM)) = 0);
+  {$ENDIF}
+
+  Result := ((AX and AM) shl &AS) or ((AX shr &AS) and AM);
+end;
+
+class function TBits.BitPermuteStepSimple(AX: UInt64; AM: UInt64; &AS: Int32): UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AM shl &AS) = not AM);
+  System.Assert((AM and (not AM)) = 0);
+  {$ENDIF}
+
+  Result := ((AX and AM) shl &AS) or ((AX shr &AS) and AM);
+end;
+
+end.

+ 233 - 150
CryptoLib/src/Math/Raw/ClpInterleave.pas

@@ -22,214 +22,297 @@ unit ClpInterleave;
 interface
 
 uses
+  SysUtils,
+  ClpBits,
   ClpCryptoLibTypes;
 
 type
-  TInterleave = class sealed(TObject)
+  TInterleave = class sealed
+  private
+    const M32: UInt64 = UInt64($55555555);
+    const M64: UInt64 = UInt64($5555555555555555);
+    const M64R: UInt64 = UInt64($AAAAAAAAAAAAAAAA);
+  public
+    class function Expand8to16(AX: Byte): UInt32; static;
+    class function Expand16to32(AX: UInt16): UInt32; static;
+    class function Expand32to64(AX: UInt32): UInt64; static;
 
-  strict private
-  const
-    M32 = UInt64($55555555);
-    M64 = UInt64($5555555555555555);
-    M64R = UInt64($AAAAAAAAAAAAAAAA);
+    class procedure Expand64To128(AX: UInt64; const AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+    class procedure Expand64To128(const AXs: TCryptoLibUInt64Array; AXsOff: Int32; AXsLen: Int32;
+      const AZs: TCryptoLibUInt64Array; AZsOff: Int32); overload; static;
 
-  public
-    class function Expand8to16(x: UInt32): UInt32; static; inline;
-    class function Expand16to32(x: UInt32): UInt32; static; inline;
-    class function Expand32to64(x: UInt32): UInt64; static;
-    class procedure Expand64To128(x: UInt64; const z: TCryptoLibUInt64Array;
-      zOff: Int32); static;
-    class procedure Expand64To128Rev(x: UInt64; const z: TCryptoLibUInt64Array;
-      zOff: Int32); static;
-    class function Shuffle(x: UInt32): UInt32; overload; static;
-    class function Shuffle(x: UInt64): UInt64; overload; static;
-    class function Shuffle2(x: UInt32): UInt32; static;
-    class function Unshuffle(x: UInt32): UInt32; overload; static;
-    class function Unshuffle(x: UInt64): UInt64; overload; static;
-    class function Unshuffle2(x: UInt32): UInt32; static;
+    class function Expand64To128Rev(AX: UInt64; out ALow: UInt64): UInt64; static;
+
+    class function Shuffle(AX: UInt32): UInt32; overload; static;
+    class function Shuffle(AX: UInt64): UInt64; overload; static;
+
+    class function Shuffle2(AX: UInt32): UInt32; overload; static;
+    class function Shuffle2(AX: UInt64): UInt64; overload; static;
 
+    class function Unshuffle(AX: UInt32): UInt32; overload; static;
+    class function Unshuffle(AX: UInt64): UInt64; overload; static;
+    class function Unshuffle(AX: UInt64; out AEven: UInt64): UInt64; overload; static;
+    class function Unshuffle(AX0, AX1: UInt64; out AEven: UInt64): UInt64; overload; static;
+
+    class function Unshuffle2(AX: UInt32): UInt32; overload; static;
+    class function Unshuffle2(AX: UInt64): UInt64; overload; static;
+
+    class function Transpose(AX: UInt64): UInt64; static;
   end;
 
 implementation
 
 { TInterleave }
 
-class function TInterleave.Expand8to16(x: UInt32): UInt32;
+class function TInterleave.Expand8to16(AX: Byte): UInt32;
+var
+  LT: UInt32;
 begin
-  x := x and UInt32($FF);
-  x := (x or (x shl 4)) and UInt32($0F0F);
-  x := (x or (x shl 2)) and UInt32($3333);
-  x := (x or (x shl 1)) and UInt32($5555);
-  result := x;
+  LT := AX;
+  LT := (LT or (LT shl 4)) and $0F0F;
+  LT := (LT or (LT shl 2)) and $3333;
+  LT := (LT or (LT shl 1)) and $5555;
+  Result := LT;
 end;
 
-class function TInterleave.Expand16to32(x: UInt32): UInt32;
+class function TInterleave.Expand16to32(AX: UInt16): UInt32;
+var
+  LT: UInt32;
 begin
-  x := x and UInt32($FFFF);
-  x := (x or (x shl 8)) and UInt32($00FF00FF);
-  x := (x or (x shl 4)) and UInt32($0F0F0F0F);
-  x := (x or (x shl 2)) and UInt32($33333333);
-  x := (x or (x shl 1)) and UInt32($55555555);
-  result := x;
+  LT := AX;
+  LT := (LT or (LT shl 8)) and $00FF00FF;
+  LT := (LT or (LT shl 4)) and $0F0F0F0F;
+  LT := (LT or (LT shl 2)) and $33333333;
+  LT := (LT or (LT shl 1)) and $55555555;
+  Result := LT;
 end;
 
-class function TInterleave.Expand32to64(x: UInt32): UInt64;
+class function TInterleave.Expand32to64(AX: UInt32): UInt64;
 var
-  t: UInt32;
+  LX: UInt32;
 begin
   // "shuffle" low half to even bits and high half to odd bits
-  t := (x xor (x shr 8)) and UInt32($0000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 4)) and UInt32($00F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 2)) and UInt32($0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 1)) and UInt32($22222222);
-  x := x xor (t xor (t shl 1));
+  LX := AX;
+  LX := TBits.BitPermuteStep(LX, $0000FF00, 8);
+  LX := TBits.BitPermuteStep(LX, $00F000F0, 4);
+  LX := TBits.BitPermuteStep(LX, $0C0C0C0C, 2);
+  LX := TBits.BitPermuteStep(LX, $22222222, 1);
 
-  result := ((x shr 1) and M32) shl 32 or (x and M32);
+  Result := (UInt64((LX shr 1) and UInt32(M32)) shl 32) or UInt64(LX and UInt32(M32));
 end;
 
-class procedure TInterleave.Expand64To128(x: UInt64;
-  const z: TCryptoLibUInt64Array; zOff: Int32);
+class procedure TInterleave.Expand64To128(AX: UInt64; const AZ: TCryptoLibUInt64Array; AZOff: Int32);
 var
-  t: UInt64;
+  LX: UInt64;
 begin
+  LX := AX;
+
   // "shuffle" low half to even bits and high half to odd bits
-  t := (x xor (x shr 16)) and UInt64($00000000FFFF0000);
-  x := x xor (t xor (t shl 16));
-  t := (x xor (x shr 8)) and UInt64($0000FF000000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 4)) and UInt64($00F000F000F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 2)) and UInt64($0C0C0C0C0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 1)) and UInt64($2222222222222222);
-  x := x xor (t xor (t shl 1));
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000FFFF0000), 16);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000FF000000FF00), 8);
+  LX := TBits.BitPermuteStep(LX, UInt64($00F000F000F000F0), 4);
+  LX := TBits.BitPermuteStep(LX, UInt64($0C0C0C0C0C0C0C0C), 2);
+  LX := TBits.BitPermuteStep(LX, UInt64($2222222222222222), 1);
+
+  AZ[AZOff] := LX and M64;
+  AZ[AZOff + 1] := (LX shr 1) and M64;
+end;
 
-  z[zOff] := (x) and M64;
-  z[zOff + 1] := (x shr 1) and M64;
+class procedure TInterleave.Expand64To128(const AXs: TCryptoLibUInt64Array; AXsOff: Int32; AXsLen: Int32;
+  const AZs: TCryptoLibUInt64Array; AZsOff: Int32);
+var
+  LXsPos, LZsPos: Int32;
+begin
+  LXsPos := AXsLen;
+  LZsPos := AZsOff + (AXsLen shl 1);
+  while True do
+  begin
+    System.Dec(LXsPos);
+    if LXsPos < 0 then
+      Break;
+
+    System.Dec(LZsPos, 2);
+    Expand64To128(AXs[AXsOff + LXsPos], AZs, LZsPos);
+  end;
 end;
 
-class procedure TInterleave.Expand64To128Rev(x: UInt64;
-  const z: TCryptoLibUInt64Array; zOff: Int32);
+class function TInterleave.Expand64To128Rev(AX: UInt64; out ALow: UInt64): UInt64;
 var
-  t: UInt64;
+  LX: UInt64;
 begin
+  LX := AX;
+
   // "shuffle" low half to even bits and high half to odd bits
-  t := (x xor (x shr 16)) and UInt64($00000000FFFF0000);
-  x := x xor (t xor (t shl 16));
-  t := (x xor (x shr 8)) and UInt64($0000FF000000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 4)) and UInt64($00F000F000F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 2)) and UInt64($0C0C0C0C0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 1)) and UInt64($2222222222222222);
-  x := x xor (t xor (t shl 1));
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000FFFF0000), 16);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000FF000000FF00), 8);
+  LX := TBits.BitPermuteStep(LX, UInt64($00F000F000F000F0), 4);
+  LX := TBits.BitPermuteStep(LX, UInt64($0C0C0C0C0C0C0C0C), 2);
+  LX := TBits.BitPermuteStep(LX, UInt64($2222222222222222), 1);
 
-  z[zOff] := (x) and M64R;
-  z[zOff + 1] := (x shl 1) and M64R;
+  ALow := LX and M64R;
+  Result := (LX shl 1) and M64R;
 end;
 
-class function TInterleave.Shuffle(x: UInt32): UInt32;
+class function TInterleave.Shuffle(AX: UInt32): UInt32;
 var
-  t: UInt32;
+  LX: UInt32;
 begin
+  LX := AX;
+
   // "shuffle" low half to even bits and high half to odd bits
-  t := (x xor (x shr 8)) and UInt32($0000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 4)) and UInt32($00F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 2)) and UInt32($0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 1)) and UInt32($22222222);
-  x := x xor (t xor (t shl 1));
-  result := x;
+  LX := TBits.BitPermuteStep(LX, $0000FF00, 8);
+  LX := TBits.BitPermuteStep(LX, $00F000F0, 4);
+  LX := TBits.BitPermuteStep(LX, $0C0C0C0C, 2);
+  LX := TBits.BitPermuteStep(LX, $22222222, 1);
+  Result := LX;
 end;
 
-class function TInterleave.Shuffle(x: UInt64): UInt64;
+class function TInterleave.Shuffle(AX: UInt64): UInt64;
 var
-  t: UInt64;
+  LX: UInt64;
 begin
+  LX := AX;
+
   // "shuffle" low half to even bits and high half to odd bits
-  t := (x xor (x shr 16)) and UInt64($00000000FFFF0000);
-  x := x xor (t xor (t shl 16));
-  t := (x xor (x shr 8)) and UInt64($0000FF000000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 4)) and UInt64($00F000F000F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 2)) and UInt64($0C0C0C0C0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 1)) and UInt64($2222222222222222);
-  x := x xor (t xor (t shl 1));
-  result := x;
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000FFFF0000), 16);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000FF000000FF00), 8);
+  LX := TBits.BitPermuteStep(LX, UInt64($00F000F000F000F0), 4);
+  LX := TBits.BitPermuteStep(LX, UInt64($0C0C0C0C0C0C0C0C), 2);
+  LX := TBits.BitPermuteStep(LX, UInt64($2222222222222222), 1);
+  Result := LX;
 end;
 
-class function TInterleave.Shuffle2(x: UInt32): UInt32;
+class function TInterleave.Shuffle2(AX: UInt32): UInt32;
 var
-  t: UInt32;
+  LX: UInt32;
 begin
-  // "shuffle" (twice) low half to even bits and high half to odd bits
-  t := (x xor (x shr 7)) and UInt32($00AA00AA);
-  x := x xor (t xor (t shl 7));
-  t := (x xor (x shr 14)) and UInt32($0000CCCC);
-  x := x xor (t xor (t shl 14));
-  t := (x xor (x shr 4)) and UInt32($00F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 8)) and UInt32($0000FF00);
-  x := x xor (t xor (t shl 8));
-  result := x;
+  LX := AX;
+
+  // 4 3 2 1 0 => 2 1 4 3 0
+  LX := TBits.BitPermuteStep(LX, $0000F0F0, 12);
+  LX := TBits.BitPermuteStep(LX, $00CC00CC, 6);
+
+  // 2 1 4 3 0 => 2 1 4 0 3
+  LX := TBits.BitPermuteStep(LX, $22222222, 1);
+
+  // 2 1 4 0 3 => 2 1 0 4 3
+  LX := TBits.BitPermuteStep(LX, $0C0C0C0C, 2);
+
+  Result := LX;
 end;
 
-class function TInterleave.Unshuffle(x: UInt32): UInt32;
+class function TInterleave.Shuffle2(AX: UInt64): UInt64;
 var
-  t: UInt32;
+  LX: UInt64;
 begin
+  LX := AX;
+
+  // 5 4 3 2 1 0 => 3 2 5 4 1 0
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000FF00FF00), 24);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000F0F00000F0F0), 12);
+
+  // 3 2 5 4 1 0 => 3 2 1 0 5 4
+  LX := TBits.BitPermuteStep(LX, UInt64($00CC00CC00CC00CC), 6);
+  LX := TBits.BitPermuteStep(LX, UInt64($0A0A0A0A0A0A0A0A), 3);
+
+  Result := LX;
+end;
+
+class function TInterleave.Unshuffle(AX: UInt32): UInt32;
+var
+  LX: UInt32;
+begin
+  LX := AX;
+
   // "unshuffle" even bits to low half and odd bits to high half
-  t := (x xor (x shr 1)) and UInt32($22222222);
-  x := x xor (t xor (t shl 1));
-  t := (x xor (x shr 2)) and UInt32($0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 4)) and UInt32($00F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 8)) and UInt32($0000FF00);
-  x := x xor (t xor (t shl 8));
-  result := x;
+  LX := TBits.BitPermuteStep(LX, $22222222, 1);
+  LX := TBits.BitPermuteStep(LX, $0C0C0C0C, 2);
+  LX := TBits.BitPermuteStep(LX, $00F000F0, 4);
+  LX := TBits.BitPermuteStep(LX, $0000FF00, 8);
+
+  Result := LX;
 end;
 
-class function TInterleave.Unshuffle(x: UInt64): UInt64;
+class function TInterleave.Unshuffle(AX: UInt64): UInt64;
 var
-  t: UInt64;
+  LX: UInt64;
 begin
+  LX := AX;
+
   // "unshuffle" even bits to low half and odd bits to high half
-  t := (x xor (x shr 1)) and UInt64($2222222222222222);
-  x := x xor (t xor (t shl 1));
-  t := (x xor (x shr 2)) and UInt64($0C0C0C0C0C0C0C0C);
-  x := x xor (t xor (t shl 2));
-  t := (x xor (x shr 4)) and UInt64($00F000F000F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 8)) and UInt64($0000FF000000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 16)) and UInt64($00000000FFFF0000);
-  x := x xor (t xor (t shl 16));
-  result := x;
-end;
-
-class function TInterleave.Unshuffle2(x: UInt32): UInt32;
-var
-  t: UInt32;
-begin
-  // "unshuffle" (twice) even bits to low half and odd bits to high half
-  t := (x xor (x shr 8)) and UInt32($0000FF00);
-  x := x xor (t xor (t shl 8));
-  t := (x xor (x shr 4)) and UInt32($00F000F0);
-  x := x xor (t xor (t shl 4));
-  t := (x xor (x shr 14)) and UInt32($0000CCCC);
-  x := x xor (t xor (t shl 14));
-  t := (x xor (x shr 7)) and UInt32($00AA00AA);
-  x := x xor (t xor (t shl 7));
-  result := x;
+  LX := TBits.BitPermuteStep(LX, UInt64($2222222222222222), 1);
+  LX := TBits.BitPermuteStep(LX, UInt64($0C0C0C0C0C0C0C0C), 2);
+  LX := TBits.BitPermuteStep(LX, UInt64($00F000F000F000F0), 4);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000FF000000FF00), 8);
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000FFFF0000), 16);
+
+  Result := LX;
+end;
+
+class function TInterleave.Unshuffle(AX: UInt64; out AEven: UInt64): UInt64;
+var
+  LU0: UInt64;
+begin
+  LU0 := Unshuffle(AX);
+  AEven := LU0 and UInt64($00000000FFFFFFFF);
+  Result := LU0 shr 32;
+end;
+
+class function TInterleave.Unshuffle(AX0, AX1: UInt64; out AEven: UInt64): UInt64;
+var
+  LU0, LU1: UInt64;
+begin
+  LU0 := Unshuffle(AX0);
+  LU1 := Unshuffle(AX1);
+  AEven := (LU1 shl 32) or (LU0 and UInt64($00000000FFFFFFFF));
+  Result := (LU0 shr 32) or (LU1 and UInt64($FFFFFFFF00000000));
+end;
+
+class function TInterleave.Unshuffle2(AX: UInt32): UInt32;
+var
+  LX: UInt32;
+begin
+  LX := AX;
+
+  // 4 3 2 1 0 => 4 3 1 2 0
+  LX := TBits.BitPermuteStep(LX, $0C0C0C0C, 2);
+
+  // 4 3 1 2 0 => 4 3 1 0 2
+  LX := TBits.BitPermuteStep(LX, $22222222, 1);
+
+  // 4 3 1 0 2 => 1 0 4 3 2
+  LX := TBits.BitPermuteStep(LX, $0000F0F0, 12);
+  LX := TBits.BitPermuteStep(LX, $00CC00CC, 6);
+
+  Result := LX;
+end;
+
+class function TInterleave.Unshuffle2(AX: UInt64): UInt64;
+var
+  LX: UInt64;
+begin
+  LX := AX;
+
+  // 5 4 3 2 1 0 => 5 4 1 0 3 2
+  LX := TBits.BitPermuteStep(LX, UInt64($00CC00CC00CC00CC), 6);
+  LX := TBits.BitPermuteStep(LX, UInt64($0A0A0A0A0A0A0A0A), 3);
+
+  // 5 4 1 0 3 2 => 1 0 5 4 3 2
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000FF00FF00), 24);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000F0F00000F0F0), 12);
+
+  Result := LX;
+end;
+
+class function TInterleave.Transpose(AX: UInt64): UInt64;
+var
+  LX: UInt64;
+begin
+  LX := AX;
+  LX := TBits.BitPermuteStep(LX, UInt64($00000000F0F0F0F0), 28);
+  LX := TBits.BitPermuteStep(LX, UInt64($0000CCCC0000CCCC), 14);
+  LX := TBits.BitPermuteStep(LX, UInt64($00AA00AA00AA00AA), 7);
+  Result := LX;
 end;
 
 end.

+ 777 - 196
CryptoLib/src/Math/Raw/ClpMod.pas

@@ -22,318 +22,899 @@ unit ClpMod;
 interface
 
 uses
-  ClpCryptoLibTypes,
-{$IFDEF DELPHI}
-  ClpBitConverter,
-{$ENDIF DELPHI}
+  Math,
+  SysUtils,
+  ClpISecureRandom,
+  ClpPack,
   ClpNat,
-  ClpConverters,
-  ClpSecureRandom,
-  ClpISecureRandom;
-
-resourcestring
-  SCannotBeZero = 'cannot be 0, "x"';
+  ClpBitUtilities,
+  ClpCryptoLibTypes;
 
 type
-  TMod = class abstract(TObject)
+   /// <summary>
+  /// Modular inversion as implemented in this class is based on the paper "Fast constant-time gcd computation and
+  /// modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
+  /// </summary>
+  /// <remarks>
+  /// In some cases (when it is faster) we use the "half delta" variant of safegcd based on
+  /// <a href="https://github.com/sipa/safegcd-bounds">hddivsteps</a>.
+  /// </remarks>
+  TMod = class sealed
+  private
+    const M30: Int32 = $3FFFFFFF;
+    const M32UL: UInt64 = UInt64($FFFFFFFF);
+
+    class function Add30(ALen30: Int32; const AD: TCryptoLibInt32Array; const AM: TCryptoLibInt32Array): Int32; static;
+    class procedure CNegate30(ALen30: Int32; ACond: Int32; const AD: TCryptoLibInt32Array); static;
+    class procedure CNormalize30(ALen30: Int32; ACondNegate: Int32; const AD: TCryptoLibInt32Array;
+      const AM: TCryptoLibInt32Array); static;
+
+    class procedure Decode30(ABits: Int32; const AX: TCryptoLibInt32Array; const AZ: TCryptoLibUInt32Array); static;
+    class function Divsteps30Var(AEta: Int32; AF0: Int32; AG0: Int32; const AT: TCryptoLibInt32Array): Int32; static;
+    class procedure Encode30(ABits: Int32; const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibInt32Array); static;
+
+    class function EqualTo(ALen: Int32; const AX: TCryptoLibInt32Array; AY: Int32): Int32; static;
+    class function EqualToVar(ALen: Int32; const AX: TCryptoLibInt32Array; AY: Int32): Boolean; static;
 
-  strict private
+    class function GetMaximumDivsteps(ABits: Int32): Int32; static;
+    class function GetMaximumHDDivsteps(ABits: Int32): Int32; static;
 
-    class var
+    class function HDDivsteps30(ATheta: Int32; AF0: Int32; AG0: Int32; const AT: TCryptoLibInt32Array): Int32; static;
 
-      FRandomSource: ISecureRandom;
+    class function Negate30(ALen30: Int32; const AD: TCryptoLibInt32Array): Int32; static;
+    class function TrimFG30Var(ALen30: Int32; const AF: TCryptoLibInt32Array; const AG: TCryptoLibInt32Array): Int32; static;
 
-    class procedure Boot(); static;
-    class constructor &Mod();
+    class procedure UpdateDE30(ALen30: Int32; const AD: TCryptoLibInt32Array; const AE: TCryptoLibInt32Array;
+      const AT: TCryptoLibInt32Array; AM0Inv32: Int32; const AM: TCryptoLibInt32Array); static;
 
-    class procedure InversionResult(const p: TCryptoLibUInt32Array; ac: Int32;
-      const a: TCryptoLibUInt32Array; const z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure InversionStep(const p, u: TCryptoLibUInt32Array;
-      uLen: Int32; const x: TCryptoLibUInt32Array; var xc: Int32); static;
+    class procedure UpdateFG30(ALen30: Int32; const AF: TCryptoLibInt32Array; const AG: TCryptoLibInt32Array;
+      const AT: TCryptoLibInt32Array); static;
 
   public
-    class procedure Invert(const p, x, z: TCryptoLibUInt32Array); static;
-    class function Random(const p: TCryptoLibUInt32Array)
-      : TCryptoLibUInt32Array; static;
-    class procedure Add(const p, x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Subtract(const p, x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class function GetTrailingZeroes(x: UInt32): Int32; static; inline;
-    class function Inverse32(const AD: UInt32): UInt32; static; inline;
-    class function Inverse64(const AD: UInt64): UInt64; static; inline;
+    class procedure CheckedModOddInverse(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+      const AZ: TCryptoLibUInt32Array); static;
+
+    class procedure CheckedModOddInverseVar(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+      const AZ: TCryptoLibUInt32Array); static;
+
+    class function Inverse32(AD: UInt32): UInt32; static;
+    class function Inverse64(AD: UInt64): UInt64; static;
+
+    class function ModOddInverse(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+      const AZ: TCryptoLibUInt32Array): UInt32; static;
 
+    class function ModOddInverseVar(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+      const AZ: TCryptoLibUInt32Array): Boolean; static;
+
+    class function ModOddIsCoprime(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array): UInt32; static;
+    class function ModOddIsCoprimeVar(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array): Boolean; static;
+
+    class function Random(const ARandom: ISecureRandom; const AP: TCryptoLibUInt32Array): TCryptoLibUInt32Array; overload; static;
   end;
 
 implementation
 
 { TMod }
 
-class procedure TMod.Add(const p, x, y, z: TCryptoLibUInt32Array);
-var
-  len: Int32;
-  c: UInt32;
+class procedure TMod.CheckedModOddInverse(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+  const AZ: TCryptoLibUInt32Array);
 begin
-  len := System.Length(p);
-  c := TNat.Add(len, x, y, z);
-  if (c <> 0) then
-  begin
-    TNat.SubFrom(len, p, z);
-  end;
+  if ModOddInverse(AM, AX, AZ) = 0 then
+    raise EArithmeticCryptoLibException.Create('Inverse does not exist.');
 end;
 
-class procedure TMod.Boot;
+class procedure TMod.CheckedModOddInverseVar(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+  const AZ: TCryptoLibUInt32Array);
 begin
-
-  FRandomSource := TSecureRandom.Create();
+  if not ModOddInverseVar(AM, AX, AZ) then
+    raise EArithmeticCryptoLibException.Create('Inverse does not exist.');
 end;
 
-class function TMod.GetTrailingZeroes(x: UInt32): Int32;
-var
-  count: Int32;
-begin
-{$IFDEF DEBUG}
-  System.Assert(x <> 0);
-{$ENDIF DEBUG}
-  count := 0;
-  while ((x and 1) = 0) do
-  begin
-    x := x shr 1;
-    System.Inc(count);
-  end;
-  result := count;
-end;
-
-class function TMod.Inverse32(const AD: UInt32): UInt32;
+class function TMod.Inverse32(AD: UInt32): UInt32;
 var
   LX: UInt32;
 begin
-{$IFDEF DEBUG}
+  {$IFDEF DEBUG}
   System.Assert((AD and 1) = 1);
-{$ENDIF DEBUG}
-  // x = d (d.x == 1 mod 2**3)
+  {$ENDIF}
+
   LX := AD;
-  // d.x == 1 mod 2**6
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**12
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**24
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**48
   LX := LX * (2 - AD * LX);
-{$IFDEF DEBUG}
+  {$IFDEF DEBUG}
   System.Assert(AD * LX = 1);
-{$ENDIF DEBUG}
+  {$ENDIF}
   Result := LX;
 end;
 
-class function TMod.Inverse64(const AD: UInt64): UInt64;
+class function TMod.Inverse64(AD: UInt64): UInt64;
 var
   LX: UInt64;
 begin
-{$IFDEF DEBUG}
+  {$IFDEF DEBUG}
   System.Assert((AD and 1) = 1);
-{$ENDIF DEBUG}
-  // x = d (d.x == 1 mod 2**3)
+  {$ENDIF}
+
   LX := AD;
-  // d.x == 1 mod 2**6
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**12
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**24
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**48
   LX := LX * (2 - AD * LX);
-  // d.x == 1 mod 2**96
   LX := LX * (2 - AD * LX);
-{$IFDEF DEBUG}
+  {$IFDEF DEBUG}
   System.Assert(AD * LX = 1);
-{$ENDIF DEBUG}
+  {$ENDIF}
   Result := LX;
 end;
 
-class procedure TMod.InversionResult(const p: TCryptoLibUInt32Array; ac: Int32;
-  const a, z: TCryptoLibUInt32Array);
+class function TMod.ModOddInverse(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+  const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LLen32, LBits, LLen30, LAllocSize: Int32;
+  LT, LD, LE, LF, LG, LM: TCryptoLibInt32Array;
+  LTheta, LM0Inv32, LMaxDivsteps, LSignF: Int32;
+  LDivSteps: Int32;
 begin
-  if (ac < 0) then
+  LLen32 := System.Length(AM);
+  {$IFDEF DEBUG}
+  System.Assert(LLen32 > 0);
+  System.Assert((AM[0] and 1) <> 0);
+  System.Assert(AM[LLen32 - 1] <> 0);
+  {$ENDIF}
+
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LLen30 := (LBits + 29) div 30;
+
+  SetLength(LT, 4);
+  SetLength(LD, LLen30);
+  SetLength(LE, LLen30);
+  SetLength(LF, LLen30);
+  SetLength(LG, LLen30);
+  SetLength(LM, LLen30);
+
+  LE[0] := 1;
+  Encode30(LBits, AX, LG);
+  Encode30(LBits, AM, LM);
+
+  System.Move(LM[0], LF[0], LLen30 * SizeOf(Int32));
+
+  LTheta := 0;
+  LM0Inv32 := Int32(Inverse32(UInt32(LM[0])));
+  LMaxDivsteps := GetMaximumHDDivsteps(LBits);
+
+  LDivSteps := 0;
+  while LDivSteps < LMaxDivsteps do
   begin
-    TNat.Add(System.Length(p), a, p, z);
-  end
-  else
-  begin
-    System.Move(a[0], z[0], System.Length(p) * System.SizeOf(UInt32));
+    LTheta := HDDivsteps30(LTheta, LF[0], LG[0], LT);
+    UpdateDE30(LLen30, LD, LE, LT, LM0Inv32, LM);
+    UpdateFG30(LLen30, LF, LG, LT);
+    Inc(LDivSteps, 30);
   end;
+
+  LSignF := TBitUtilities.Asr32(LF[LLen30 - 1], 31);
+  CNegate30(LLen30, LSignF, LF);
+
+  CNormalize30(LLen30, LSignF, LD, LM);
+
+  Decode30(LBits, LD, AZ);
+
+  {$IFDEF DEBUG}
+  System.Assert(TNat.LessThan(LLen32, AZ, AM) <> 0);
+  {$ENDIF}
+
+  Result := UInt32(EqualTo(LLen30, LF, 1) and EqualTo(LLen30, LG, 0));
 end;
 
-class procedure TMod.InversionStep(const p, u: TCryptoLibUInt32Array;
-  uLen: Int32; const x: TCryptoLibUInt32Array; var xc: Int32);
+class function TMod.ModOddInverseVar(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array;
+  const AZ: TCryptoLibUInt32Array): Boolean;
 var
-  len, count, zeroes, i: Int32;
+  LLen32, LBits, LLen30, LClz: Int32;
+  LT, LD, LE, LF, LG, LM: TCryptoLibInt32Array;
+  LEta, LLenDE, LLenFG, LM0Inv32, LMaxDivsteps: Int32;
+  LDivsteps: Int32;
+  LSignF, LSignD: Int32;
 begin
-  len := System.Length(p);
-  count := 0;
-  while (u[0] = 0) do
+  LLen32 := System.Length(AM);
+  {$IFDEF DEBUG}
+  System.Assert(LLen32 > 0);
+  System.Assert((AM[0] and 1) <> 0);
+  System.Assert(AM[LLen32 - 1] <> 0);
+  {$ENDIF}
+
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LLen30 := (LBits + 29) div 30;
+
+  LClz := LBits - TNat.GetBitLength(LLen32, AX);
+  {$IFDEF DEBUG}
+  System.Assert(LClz >= 0);
+  {$ENDIF}
+
+  SetLength(LT, 4);
+  SetLength(LD, LLen30);
+  SetLength(LE, LLen30);
+  SetLength(LF, LLen30);
+  SetLength(LG, LLen30);
+  SetLength(LM, LLen30);
+
+  LE[0] := 1;
+  Encode30(LBits, AX, LG);
+  Encode30(LBits, AM, LM);
+  System.Move(LM[0], LF[0], LLen30 * SizeOf(Int32));
+
+  // We use the original safegcd here, with eta == 1 - delta
+  // For shorter x, configure as if low zeros of x had been shifted away by divsteps
+  LEta := -LClz;
+  LLenDE := LLen30;
+  LLenFG := LLen30;
+  LM0Inv32 := Int32(Inverse32(UInt32(LM[0])));
+  LMaxDivsteps := GetMaximumDivsteps(LBits);
+
+  LDivsteps := LClz;
+  while not EqualToVar(LLenFG, LG, 0) do
   begin
-    TNat.ShiftDownWord(uLen, u, 0);
-    count := count + 32;
+    if LDivsteps >= LMaxDivsteps then
+      Exit(False);
+
+    Inc(LDivsteps, 30);
+
+    LEta := Divsteps30Var(LEta, LF[0], LG[0], LT);
+    UpdateDE30(LLenDE, LD, LE, LT, LM0Inv32, LM);
+    UpdateFG30(LLenFG, LF, LG, LT);
+    LLenFG := TrimFG30Var(LLenFG, LF, LG);
   end;
 
-  zeroes := GetTrailingZeroes(u[0]);
-  if (zeroes > 0) then
+  LSignF := TBitUtilities.Asr32(LF[LLenFG - 1], 31);
+
+  // D is in the range (-2.M, M) ...
+  LSignD := TBitUtilities.Asr32(LD[LLenDE - 1], 31);
+  if LSignD < 0 then
+    LSignD := Add30(LLenDE, LD, LM);
+
+  if LSignF < 0 then
   begin
-    TNat.ShiftDownBits(uLen, u, zeroes, 0);
-    count := count + zeroes;
+    LSignD := Negate30(LLenDE, LD);
+    LSignF := Negate30(LLenFG, LF);
   end;
 
-  i := 0;
-  while i < count do
+  {$IFDEF DEBUG}
+  System.Assert(LSignF = 0);
+  {$ENDIF}
+
+  if not EqualToVar(LLenFG, LF, 1) then
+    Exit(False);
+
+  if LSignD < 0 then
+    LSignD := Add30(LLenDE, LD, LM);
+
+  {$IFDEF DEBUG}
+  System.Assert(LSignD = 0);
+  {$ENDIF}
+
+  Decode30(LBits, LD, AZ);
+
+  {$IFDEF DEBUG}
+  System.Assert(not TNat.Gte(LLen32, AZ, AM));
+  {$ENDIF}
+
+  Result := True;
+end;
+
+class function TMod.ModOddIsCoprime(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array): UInt32;
+var
+  LLen32, LBits, LLen30: Int32;
+  LT, LF, LG, LM: TCryptoLibInt32Array;
+  LTheta, LMaxDivsteps, LDivSteps, LSignF: Int32;
+begin
+  LLen32 := System.Length(AM);
+  {$IFDEF DEBUG}
+  System.Assert(LLen32 > 0);
+  System.Assert((AM[0] and 1) <> 0);
+  System.Assert(AM[LLen32 - 1] <> 0);
+  {$ENDIF}
+
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LLen30 := (LBits + 29) div 30;
+
+  SetLength(LT, 4);
+  SetLength(LF, LLen30);
+  SetLength(LG, LLen30);
+  SetLength(LM, LLen30);
+
+  Encode30(LBits, AX, LG);
+  Encode30(LBits, AM, LM);
+  System.Move(LM[0], LF[0], LLen30 * SizeOf(Int32));
+
+  LTheta := 0;
+  LMaxDivsteps := GetMaximumHDDivsteps(LBits);
+
+  LDivSteps := 0;
+  while LDivSteps < LMaxDivsteps do
   begin
+    LTheta := HDDivsteps30(LTheta, LF[0], LG[0], LT);
+    UpdateFG30(LLen30, LF, LG, LT);
+    Inc(LDivSteps, 30);
+  end;
 
-    if ((x[0] and 1) <> 0) then
-    begin
-      if (xc < 0) then
-      begin
-        xc := xc + Int32(TNat.AddTo(len, p, x));
-      end
-      else
-      begin
-        xc := xc + (TNat.SubFrom(len, p, x));
-      end;
-    end;
+  LSignF := TBitUtilities.Asr32(LF[LLen30 - 1], 31);
+  CNegate30(LLen30, LSignF, LF);
 
-{$IFDEF DEBUG}
-    System.Assert((xc = 0) or (xc = -1));
-{$ENDIF DEBUG}
-    TNat.ShiftDownBit(len, x, UInt32(xc));
+  Result := UInt32(EqualTo(LLen30, LF, 1) and EqualTo(LLen30, LG, 0));
+end;
 
-    System.Inc(i);
+class function TMod.ModOddIsCoprimeVar(const AM: TCryptoLibUInt32Array; const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LLen32, LBits, LLen30, LClz: Int32;
+  LT, LF, LG, LM: TCryptoLibInt32Array;
+  LEta, LLenFG, LMaxDivsteps, LDivsteps, LSignF: Int32;
+begin
+  LLen32 := System.Length(AM);
+  {$IFDEF DEBUG}
+  System.Assert(LLen32 > 0);
+  System.Assert((AM[0] and 1) <> 0);
+  System.Assert(AM[LLen32 - 1] <> 0);
+  {$ENDIF}
+
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LLen30 := (LBits + 29) div 30;
+
+  LClz := LBits - TNat.GetBitLength(LLen32, AX);
+  {$IFDEF DEBUG}
+  System.Assert(LClz >= 0);
+  {$ENDIF}
+
+  SetLength(LT, 4);
+  SetLength(LF, LLen30);
+  SetLength(LG, LLen30);
+  SetLength(LM, LLen30);
+
+  Encode30(LBits, AX, LG);
+  Encode30(LBits, AM, LM);
+  System.Move(LM[0], LF[0], LLen30 * SizeOf(Int32));
+
+  // We use the original safegcd here, with eta == 1 - delta
+  // For shorter x, configure as if low zeros of x had been shifted away by divsteps
+  LEta := -LClz;
+  LLenFG := LLen30;
+  LMaxDivsteps := GetMaximumDivsteps(LBits);
+
+  LDivsteps := LClz;
+  while not EqualToVar(LLenFG, LG, 0) do
+  begin
+    if LDivsteps >= LMaxDivsteps then
+      Exit(False);
+
+    Inc(LDivsteps, 30);
+
+    LEta := Divsteps30Var(LEta, LF[0], LG[0], LT);
+    UpdateFG30(LLenFG, LF, LG, LT);
+    LLenFG := TrimFG30Var(LLenFG, LF, LG);
+  end;
+
+  LSignF := TBitUtilities.Asr32(LF[LLenFG - 1], 31);
+  if LSignF < 0 then
+  begin
+    LSignF := Negate30(LLenFG, LF);
   end;
 
+  {$IFDEF DEBUG}
+  System.Assert(LSignF = 0);
+  {$ENDIF}
+
+  Result := EqualToVar(LLenFG, LF, 1);
+end;
+
+class function TMod.Random(const ARandom: ISecureRandom; const AP: TCryptoLibUInt32Array): TCryptoLibUInt32Array;
+var
+  LLen: Integer;
+  LS: TCryptoLibUInt32Array;
+  LM: UInt32;
+  LBytes: TCryptoLibByteArray;
+begin
+  LLen := Length(AP);
+
+  LS := TNat.Create(LLen);
+
+  LM := AP[LLen - 1];
+  LM := LM or (LM shr 1);
+  LM := LM or (LM shr 2);
+  LM := LM or (LM shr 4);
+  LM := LM or (LM shr 8);
+  LM := LM or (LM shr 16);
+
+  SetLength(LBytes, LLen shl 2);
+
+  repeat
+    ARandom.NextBytes(LBytes);
+    TPack.BE_To_UInt32(LBytes, 0, LS);
+
+    LS[LLen - 1] := LS[LLen - 1] and LM;
+  until not TNat.Gte(LLen, LS, AP);
+
+  Result := LS;
 end;
 
-class procedure TMod.Invert(const p, x, z: TCryptoLibUInt32Array);
+class function TMod.Add30(ALen30: Int32; const AD: TCryptoLibInt32Array; const AM: TCryptoLibInt32Array): Int32;
 var
-  len, ac, bc, uvLen: Int32;
-  u, a, v, b: TCryptoLibUInt32Array;
+  LC, LLast, LI: Int32;
 begin
-  len := System.Length(p);
-  if (TNat.IsZero(len, x)) then
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AD) >= ALen30);
+  System.Assert(System.Length(AM) >= ALen30);
+  {$ENDIF}
+
+  LC := 0;
+  LLast := ALen30 - 1;
+
+  for LI := 0 to LLast - 1 do
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SCannotBeZero);
+    LC := LC + AD[LI] + AM[LI];
+    AD[LI] := LC and M30;
+    LC := TBitUtilities.Asr32(LC, 30);
   end;
-  if (TNat.IsOne(len, x)) then
+
+  LC := LC + AD[LLast] + AM[LLast];
+  AD[LLast] := LC;
+  LC := TBitUtilities.Asr32(LC, 30);
+  Result := LC;
+end;
+
+class procedure TMod.CNegate30(ALen30: Int32; ACond: Int32; const AD: TCryptoLibInt32Array);
+var
+  LC, LLast, LI: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AD) >= ALen30);
+  {$ENDIF}
+
+  LC := 0;
+  LLast := ALen30 - 1;
+
+  for LI := 0 to LLast - 1 do
   begin
-    System.Move(x[0], z[0], len * System.SizeOf(UInt32));
-    Exit;
+    LC := LC + ((AD[LI] xor ACond) - ACond);
+    AD[LI] := LC and M30;
+    LC := TBitUtilities.Asr32(LC, 30);
   end;
 
-  u := TNat.Copy(len, x);
-  a := TNat.Create(len);
-  a[0] := 1;
-  ac := 0;
+  LC := LC + ((AD[LLast] xor ACond) - ACond);
+  AD[LLast] := LC;
+end;
+
+class procedure TMod.CNormalize30(ALen30: Int32; ACondNegate: Int32; const AD: TCryptoLibInt32Array;
+  const AM: TCryptoLibInt32Array);
+var
+  LLast, LI: Int32;
+  LC, LCondAdd, LDi: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AD) >= ALen30);
+  System.Assert(System.Length(AM) >= ALen30);
+  {$ENDIF}
+
+  LLast := ALen30 - 1;
 
-  if ((u[0] and 1) = 0) then
   begin
-    InversionStep(p, u, len, a, ac);
+    LC := 0;
+    LCondAdd := TBitUtilities.Asr32(AD[LLast], 31);
+    for LI := 0 to LLast - 1 do
+    begin
+      LDi := AD[LI] + (AM[LI] and LCondAdd);
+      LDi := (LDi xor ACondNegate) - ACondNegate;
+      LC := LC + LDi;
+      AD[LI] := LC and M30;
+      LC := TBitUtilities.Asr32(LC, 30);
+    end;
+
+    LDi := AD[LLast] + (AM[LLast] and LCondAdd);
+    LDi := (LDi xor ACondNegate) - ACondNegate;
+    LC := LC + LDi;
+    AD[LLast] := LC;
   end;
 
-  if (TNat.IsOne(len, u)) then
   begin
-    InversionResult(p, ac, a, z);
-    Exit;
+    LC := 0;
+    LCondAdd := TBitUtilities.Asr32(AD[LLast], 31);
+    for LI := 0 to LLast - 1 do
+    begin
+      LDi := AD[LI] + (AM[LI] and LCondAdd);
+      LC := LC + LDi;
+      AD[LI] := LC and M30;
+      LC := TBitUtilities.Asr32(LC, 30);
+    end;
+
+    LDi := AD[LLast] + (AM[LLast] and LCondAdd);
+    LC := LC + LDi;
+    AD[LLast] := LC;
+
+    {$IFDEF DEBUG}
+    System.Assert((TBitUtilities.Asr32(LC, 30)) = 0);
+    {$ENDIF}
   end;
+end;
 
-  v := TNat.Copy(len, p);
-  b := TNat.Create(len);
-  bc := 0;
+class procedure TMod.Decode30(ABits: Int32; const AX: TCryptoLibInt32Array; const AZ: TCryptoLibUInt32Array);
+var
+  LAvail: Int32;
+  LData: UInt64;
+  LXOff, LZOff: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ABits > 0);
+  {$ENDIF}
 
-  uvLen := len;
+  LAvail := 0;
+  LData := 0;
 
-  while True do
+  LXOff := 0;
+  LZOff := 0;
 
+  while ABits > 0 do
   begin
-    while ((u[uvLen - 1] = 0) and (v[uvLen - 1] = 0)) do
+    while LAvail < Min(32, ABits) do
     begin
-      System.Dec(uvLen);
+      LData := LData or (UInt64(UInt32(AX[LXOff])) shl LAvail);
+      Inc(LXOff);
+      Inc(LAvail, 30);
     end;
 
-    if (TNat.Gte(len, u, v)) then
+    AZ[LZOff] := UInt32(LData);
+    Inc(LZOff);
+    LData := LData shr 32;
+    Dec(LAvail, 32);
+    Dec(ABits, 32);
+  end;
+end;
+
+class function TMod.Divsteps30Var(AEta: Int32; AF0: Int32; AG0: Int32; const AT: TCryptoLibInt32Array): Int32;
+var
+  LU, LV, LQ, LR: Int32;
+  LF, LG, LM, LW, LX, LY, LZ: Int32;
+  LI, LLimit, LZeros: Int32;
+begin
+  LU := 1; LV := 0; LQ := 0; LR := 1;
+  LF := AF0; LG := AG0;
+  LI := 30;
+
+  while True do
+  begin
+    // sentinel bit to count zeros only up to i.
+    //LZeros := TBitUtilities.NumberOfTrailingZeros(UInt32(LG) or (-1 shl LI));
+    LZeros := TBitUtilities.NumberOfTrailingZeros(UInt32(LG) or (UInt32($FFFFFFFF) shl LI));
+
+    LG := TBitUtilities.Asr32(LG, LZeros);
+    LU := LU shl LZeros;
+    LV := LV shl LZeros;
+    AEta := AEta - LZeros;
+    LI := LI - LZeros;
+
+    if LI <= 0 then
+      Break;
+
+    if AEta <= 0 then
     begin
-      TNat.SubFrom(len, v, u);
-{$IFDEF DEBUG}
-      System.Assert((u[0] and 1) = 0);
-{$ENDIF DEBUG}
-      ac := ac + (TNat.SubFrom(len, b, a) - bc);
-      InversionStep(p, u, uvLen, a, ac);
-      if (TNat.IsOne(len, u)) then
-      begin
-        InversionResult(p, ac, a, z);
-        Exit;
-      end;
+      AEta := 2 - AEta;
+      LX := LF; LF := LG; LG := -LX;
+      LY := LU; LU := LQ; LQ := -LY;
+      LZ := LV; LV := LR; LR := -LZ;
+
+      LLimit := AEta;
+      if LLimit > LI then
+        LLimit := LI;
+
+      LM := Int32((UInt32.MaxValue shr (32 - LLimit)) and 63);
+      LW := (LF * LG * (LF * LF - 2)) and LM;
     end
     else
     begin
-      TNat.SubFrom(len, u, v);
-{$IFDEF DEBUG}
-      System.Assert((v[0] and 1) = 0);
-{$ENDIF DEBUG}
-      bc := bc + (TNat.SubFrom(len, a, b) - ac);
-      InversionStep(p, v, uvLen, b, bc);
-      if (TNat.IsOne(len, v)) then
-      begin
-        InversionResult(p, bc, b, z);
-        Exit;
-      end;
+      LLimit := AEta;
+      if LLimit > LI then
+        LLimit := LI;
+
+      LM := Int32((UInt32.MaxValue shr (32 - LLimit)) and 15);
+
+      LW := LF + (((LF + 1) and 4) shl 1);
+      LW := (LW * (-LG)) and LM;
+    end;
+
+    LG := LG + LF * LW;
+    LQ := LQ + LU * LW;
+    LR := LR + LV * LW;
+
+    {$IFDEF DEBUG}
+    System.Assert((LG and LM) = 0);
+    {$ENDIF}
+  end;
+
+  AT[0] := LU;
+  AT[1] := LV;
+  AT[2] := LQ;
+  AT[3] := LR;
+
+  Result := AEta;
+end;
+
+class procedure TMod.Encode30(ABits: Int32; const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibInt32Array);
+var
+  LAvail: Int32;
+  LData: UInt64;
+  LXOff, LZOff: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ABits > 0);
+  {$ENDIF}
+
+  LAvail := 0;
+  LData := 0;
+
+  LXOff := 0;
+  LZOff := 0;
+
+  while ABits > 0 do
+  begin
+    if LAvail < Min(30, ABits) then
+    begin
+      LData := LData or ((UInt64(AX[LXOff]) and M32UL) shl LAvail);
+      Inc(LXOff);
+      Inc(LAvail, 32);
     end;
+
+    AZ[LZOff] := Int32(LData) and M30;
+    Inc(LZOff);
+    LData := LData shr 30;
+    Dec(LAvail, 30);
+    Dec(ABits, 30);
   end;
 end;
 
-class constructor TMod.&Mod;
+class function TMod.EqualTo(ALen: Int32; const AX: TCryptoLibInt32Array; AY: Int32): Int32;
+var
+  LD, LI: Int32;
 begin
-  TMod.Boot;
+  LD := AX[0] xor AY;
+  for LI := 1 to ALen - 1 do
+  begin
+    LD := LD or AX[LI];
+  end;
+
+  LD := Int32(UInt32(LD) shr 1) or (LD and 1);
+  Result := TBitUtilities.Asr32(LD - 1, 31);
 end;
 
-class function TMod.Random(const p: TCryptoLibUInt32Array)
-  : TCryptoLibUInt32Array;
+class function TMod.EqualToVar(ALen: Int32; const AX: TCryptoLibInt32Array; AY: Int32): Boolean;
 var
-  len: Int32;
-  m: UInt32;
-  s: TCryptoLibUInt32Array;
-  bytes: TCryptoLibByteArray;
+  LD, LI: Int32;
 begin
-  len := System.Length(p);
-  s := TNat.Create(len);
+  LD := AX[0] xor AY;
+  if LD <> 0 then
+    Exit(False);
+
+  for LI := 1 to ALen - 1 do
+    LD := LD or AX[LI];
 
-  m := p[len - 1];
-  m := m or (m shr 1);
-  m := m or (m shr 2);
-  m := m or (m shr 4);
-  m := m or (m shr 8);
-  m := m or (m shr 16);
+  Result := LD = 0;
+end;
 
-  System.SetLength(bytes, len shl 2);
+class function TMod.GetMaximumDivsteps(ABits: Int32): Int32;
+begin
+  Result := Int32((Int64(188898) * ABits + (IfThen(ABits < 46, 308405, 181188))) shr 16);
+end;
 
-  repeat
-    FRandomSource.NextBytes(bytes);
-    TConverters.be32_copy(PByte(bytes), 0, PCardinal(s), 0, System.Length(s));
-    s[len - 1] := s[len - 1] and m;
+class function TMod.GetMaximumHDDivsteps(ABits: Int32): Int32;
+begin
+  Result := Int32(TBitUtilities.Asr64((Int64(150964) * ABits + 99243), 16));
+end;
+
+class function TMod.HDDivsteps30(ATheta: Int32; AF0: Int32; AG0: Int32; const AT: TCryptoLibInt32Array): Int32;
+var
+  LU, LV, LQ, LR: Int32;
+  LF, LG: Int32;
+  LI: Int32;
+  LC1, LC2, LX, LY, LZ, LC3: Int32;
+begin
+  LU := 1 shl 30; LV := 0; LQ := 0; LR := 1 shl 30;
+  LF := AF0;
+  LG := AG0;
+
+  for LI := 0 to 29 do
+  begin
+    LC1 := TBitUtilities.Asr32(ATheta, 31);
+    LC2 := -(LG and 1);
+
+    LX := LF xor LC1;
+    LY := LU xor LC1;
+    LZ := LV xor LC1;
+
+    LG := LG - (LX and LC2);
+    LQ := LQ - (LY and LC2);
+    LR := LR - (LZ and LC2);
+
+    LC3 := LC2 and (not LC1);
+    ATheta := (ATheta xor LC3) + 1;
+
+    LF := LF + (LG and LC3);
+    LU := LU + (LQ and LC3);
+    LV := LV + (LR and LC3);
+
+    LG := TBitUtilities.Asr32(LG, 1);
+    LQ := TBitUtilities.Asr32(LQ, 1);
+    LR := TBitUtilities.Asr32(LR, 1);
+  end;
+
+  AT[0] := LU;
+  AT[1] := LV;
+  AT[2] := LQ;
+  AT[3] := LR;
 
-  until (not(TNat.Gte(len, s, p)));
+  Result := ATheta;
+end;
+
+class function TMod.Negate30(ALen30: Int32; const AD: TCryptoLibInt32Array): Int32;
+var
+  LC, LLast, LI: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AD) >= ALen30);
+  {$ENDIF}
+
+  LC := 0;
+  LLast := ALen30 - 1;
+
+  for LI := 0 to LLast - 1 do
+  begin
+    LC := LC - AD[LI];
+    AD[LI] := LC and M30;
+    LC := TBitUtilities.Asr32(LC, 30);
+  end;
+
+  LC := LC - AD[LLast];
+  AD[LLast] := LC;
+  LC := TBitUtilities.Asr32(LC, 30);
+  Result := LC;
+end;
+
+class function TMod.TrimFG30Var(ALen30: Int32; const AF: TCryptoLibInt32Array; const AG: TCryptoLibInt32Array): Int32;
+var
+  LFn, LGn, LCond: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AF) >= ALen30);
+  System.Assert(System.Length(AG) >= ALen30);
+  {$ENDIF}
+
+  LFn := AF[ALen30 - 1];
+  LGn := AG[ALen30 - 1];
+
+  LCond := TBitUtilities.Asr32(ALen30 - 2, 31);
+  LCond := LCond or (LFn xor (TBitUtilities.Asr32(LFn, 31)));
+  LCond := LCond or (LGn xor (TBitUtilities.Asr32(LGn, 31)));
+
+  if LCond = 0 then
+  begin
+    AF[ALen30 - 2] := AF[ALen30 - 2] or (LFn shl 30);
+    AG[ALen30 - 2] := AG[ALen30 - 2] or (LGn shl 30);
+    Dec(ALen30);
+  end;
+
+  Result := ALen30;
+end;
+
+class procedure TMod.UpdateDE30(ALen30: Int32; const AD: TCryptoLibInt32Array; const AE: TCryptoLibInt32Array;
+  const AT: TCryptoLibInt32Array; AM0Inv32: Int32; const AM: TCryptoLibInt32Array);
+var
+  LU, LV, LQ, LR: Int32;
+  LDi, LEi, LI, LMd, LMe, LMi, LSd, LSe: Int32;
+  LCd, LCe: Int64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AD) >= ALen30);
+  System.Assert(System.Length(AE) >= ALen30);
+  System.Assert(System.Length(AM) >= ALen30);
+  System.Assert(Int32(AM0Inv32 * AM[0]) = 1);
+  {$ENDIF}
+
+  LU := AT[0]; LV := AT[1]; LQ := AT[2]; LR := AT[3];
 
-  result := s;
+  LSd := TBitUtilities.Asr32(AD[ALen30 - 1], 31);
+  LSe := TBitUtilities.Asr32(AE[ALen30 - 1], 31);
+
+  LMd := (LU and LSd) + (LV and LSe);
+  LMe := (LQ and LSd) + (LR and LSe);
+
+  LMi := AM[0];
+  LDi := AD[0];
+  LEi := AE[0];
+
+  LCd := Int64(LU) * LDi + Int64(LV) * LEi;
+  LCe := Int64(LQ) * LDi + Int64(LR) * LEi;
+
+  LMd := LMd - ((AM0Inv32 * Int32(LCd) + LMd) and M30);
+  LMe := LMe - ((AM0Inv32 * Int32(LCe) + LMe) and M30);
+
+  LCd := LCd + Int64(LMi) * LMd;
+  LCe := LCe + Int64(LMi) * LMe;
+
+  {$IFDEF DEBUG}
+  System.Assert((Int32(LCd) and M30) = 0);
+  System.Assert((Int32(LCe) and M30) = 0);
+  {$ENDIF}
+
+  LCd := TBitUtilities.Asr64(LCd, 30);
+  LCe := TBitUtilities.Asr64(LCe, 30);
+
+  for LI := 1 to ALen30 - 1 do
+  begin
+    LMi := AM[LI];
+    LDi := AD[LI];
+    LEi := AE[LI];
+
+    LCd := LCd + Int64(LU) * LDi + Int64(LV) * LEi + Int64(LMi) * LMd;
+    LCe := LCe + Int64(LQ) * LDi + Int64(LR) * LEi + Int64(LMi) * LMe;
+
+    AD[LI - 1] := Int32(LCd) and M30;
+    LCd := TBitUtilities.Asr64(LCd, 30);
+
+    AE[LI - 1] := Int32(LCe) and M30;
+    LCe := TBitUtilities.Asr64(LCe, 30);
+  end;
+
+  AD[ALen30 - 1] := Int32(LCd);
+  AE[ALen30 - 1] := Int32(LCe);
 end;
 
-class procedure TMod.Subtract(const p, x, y, z: TCryptoLibUInt32Array);
+class procedure TMod.UpdateFG30(ALen30: Int32; const AF: TCryptoLibInt32Array; const AG: TCryptoLibInt32Array;
+  const AT: TCryptoLibInt32Array);
 var
-  len, c: Int32;
+  LU, LV, LQ, LR: Int32;
+  LFi, LGi, LI: Int32;
+  LCf, LCg: Int64;
 begin
-  len := System.Length(p);
-  c := TNat.Sub(len, x, y, z);
-  if (c <> 0) then
+  {$IFDEF DEBUG}
+  System.Assert(ALen30 > 0);
+  System.Assert(System.Length(AF) >= ALen30);
+  System.Assert(System.Length(AG) >= ALen30);
+  {$ENDIF}
+
+  LU := AT[0]; LV := AT[1]; LQ := AT[2]; LR := AT[3];
+
+  LFi := AF[0];
+  LGi := AG[0];
+
+  LCf := Int64(LU) * LFi + Int64(LV) * LGi;
+  LCg := Int64(LQ) * LFi + Int64(LR) * LGi;
+
+  {$IFDEF DEBUG}
+  System.Assert((Int32(LCf) and M30) = 0);
+  System.Assert((Int32(LCg) and M30) = 0);
+  {$ENDIF}
+
+  LCf := TBitUtilities.Asr64(LCf, 30);
+  LCg := TBitUtilities.Asr64(LCg, 30);
+
+  for LI := 1 to ALen30 - 1 do
   begin
-    TNat.AddTo(len, p, z);
+    LFi := AF[LI];
+    LGi := AG[LI];
+
+    LCf := LCf + Int64(LU) * LFi + Int64(LV) * LGi;
+    LCg := LCg + Int64(LQ) * LFi + Int64(LR) * LGi;
+
+    AF[LI - 1] := Int32(LCf) and M30;
+    LCf := TBitUtilities.Asr64(LCf, 30);
+
+    AG[LI - 1] := Int32(LCg) and M30;
+    LCg := TBitUtilities.Asr64(LCg, 30);
   end;
+
+  AF[ALen30 - 1] := Int32(LCf);
+  AG[ALen30 - 1] := Int32(LCg);
 end;
 
 end.

Разлика између датотеке није приказан због своје велике величине
+ 464 - 828
CryptoLib/src/Math/Raw/ClpNat.pas


+ 1114 - 0
CryptoLib/src/Math/Raw/ClpNat128.pas

@@ -0,0 +1,1114 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpNat128;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpBitUtilities,
+  ClpArrayUtilities,
+  ClpBigInteger,
+  ClpPack,
+  ClpNat,
+  ClpCryptoLibTypes;
+
+type
+  TNat128 = class sealed
+  strict private
+    const M: UInt64 = UInt64($FFFFFFFF);
+  public
+    class function Add(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function AddBothTo(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32;
+      ACIn: UInt32): UInt32; overload; static;
+    class function AddToEachOther(const AU: TCryptoLibUInt32Array; AUOff: Int32; const AV: TCryptoLibUInt32Array;
+      AVOff: Int32): UInt32; static;
+
+    class procedure Copy(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; const AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+
+    class function Create: TCryptoLibUInt32Array; static;
+    class function Create64: TCryptoLibUInt64Array; static;
+    class function CreateExt: TCryptoLibUInt32Array; static;
+    class function CreateExt64: TCryptoLibUInt64Array; static;
+
+    class function Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean; static;
+
+    class function Eq(const AX, AY: TCryptoLibUInt32Array): Boolean; static;
+    class function Eq64(const AX, AY: TCryptoLibUInt64Array): Boolean; static;
+
+    class function GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32; static;
+
+    class function Gte(const AX, AY: TCryptoLibUInt32Array): Boolean; overload; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean; overload; static;
+
+    class function IsOne(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class function IsOne64(const AX: TCryptoLibUInt64Array): Boolean; static;
+
+    class function IsZero(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class function IsZero64(const AX: TCryptoLibUInt64Array): Boolean; overload; static;
+    class function IsZero64(const AX: TCryptoLibUInt64Array; AXOff: Int32): Boolean; overload; static;
+
+    class procedure Mul(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZZ: TCryptoLibUInt32Array; AZZOff: Int32); overload; static;
+
+    class function MulAddTo(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZZ: TCryptoLibUInt32Array; AZZOff: Int32): UInt32; overload; static;
+
+    class function Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array;
+      AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64; static;
+
+    class function MulWordAddExt(AX: UInt32; const AYY: TCryptoLibUInt32Array; AYYOff: Int32; const AZZ: TCryptoLibUInt32Array;
+      AZZOff: Int32): UInt32; static;
+
+    class function Mul33DWordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function Mul33WordAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWordDwordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWordsAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+
+    class procedure Square(const AX: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZZ: TCryptoLibUInt32Array; AZZOff: Int32); overload; static;
+
+    class function Sub(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+
+    class function SubBothFrom(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+
+    class function ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger; static;
+    class function ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger; static;
+
+    class procedure Zero(const AZ: TCryptoLibUInt32Array); static;
+  end;
+
+implementation
+
+class function TNat128.Add(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat128.AddBothTo(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0] + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1] + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2] + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3] + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat128.AddTo(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat128.AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32;
+  ACIn: UInt32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := ACIn;
+  LC := LC + UInt64(AX[AXOff + 0]) + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 1]) + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 2]) + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 3]) + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat128.AddToEachOther(const AU: TCryptoLibUInt32Array; AUOff: Int32; const AV: TCryptoLibUInt32Array;
+  AVOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LTmp: UInt32;
+begin
+  LC := 0;
+  LC := LC + UInt64(AU[AUOff + 0]) + AV[AVOff + 0];
+  LTmp := UInt32(LC);
+  AU[AUOff + 0] := LTmp;
+  AV[AVOff + 0] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 1]) + AV[AVOff + 1];
+  LTmp := UInt32(LC);
+  AU[AUOff + 1] := LTmp;
+  AV[AVOff + 1] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 2]) + AV[AVOff + 2];
+  LTmp := UInt32(LC);
+  AU[AUOff + 2] := LTmp;
+  AV[AVOff + 2] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 3]) + AV[AVOff + 3];
+  LTmp := UInt32(LC);
+  AU[AUOff + 3] := LTmp;
+  AV[AVOff + 3] := LTmp;
+  LC := LC shr 32;
+
+  Result := UInt32(LC);
+end;
+
+class procedure TNat128.Copy(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array);
+begin
+  System.Move(AX[0], AZ[0], 4 * System.SizeOf(UInt32));
+end;
+
+class procedure TNat128.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32);
+begin
+  System.Move(AX[AXOff], AZ[AZOff], 4 * System.SizeOf(UInt32));
+end;
+
+class procedure TNat128.Copy64(const AX: TCryptoLibUInt64Array; const AZ: TCryptoLibUInt64Array);
+begin
+  AZ[0] := AX[0];
+  AZ[1] := AX[1];
+end;
+
+class procedure TNat128.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AZ: TCryptoLibUInt64Array; AZOff: Int32);
+begin
+  System.Move(AX[AXOff], AZ[AZOff], 2 * System.SizeOf(UInt64));
+end;
+
+class function TNat128.Create: TCryptoLibUInt32Array;
+begin
+  System.SetLength(Result, 4);
+end;
+
+class function TNat128.Create64: TCryptoLibUInt64Array;
+begin
+  System.SetLength(Result, 2);
+end;
+
+class function TNat128.CreateExt: TCryptoLibUInt32Array;
+begin
+  System.SetLength(Result, 8);
+end;
+
+class function TNat128.CreateExt64: TCryptoLibUInt64Array;
+begin
+  System.SetLength(Result, 4);
+end;
+
+class function TNat128.Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean;
+var
+  LPos: Boolean;
+begin
+  LPos := Gte(AX, AXOff, AY, AYOff);
+  if LPos then
+    Sub(AX, AXOff, AY, AYOff, AZ, AZOff)
+  else
+    Sub(AY, AYOff, AX, AXOff, AZ, AZOff);
+  Result := LPos;
+end;
+
+class function TNat128.Eq(const AX, AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 3 downto 0 do
+  begin
+    if AX[LI] <> AY[LI] then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat128.Eq64(const AX, AY: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 1 downto 0 do
+  begin
+    if AX[LI] <> AY[LI] then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat128.GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32;
+var
+  LW, LB: Int32;
+begin
+  if ABit = 0 then
+  begin
+    Result := AX[0] and 1;
+    Exit;
+  end;
+
+  if ((ABit and 127) <> ABit) then
+  begin
+    Result := 0;
+    Exit;
+  end;
+
+  LW := TBitUtilities.Asr32(ABit, 5);
+
+  LB := ABit and 31;
+  Result := (AX[LW] shr LB) and 1;
+end;
+
+class function TNat128.Gte(const AX, AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+  LX, LY: UInt32;
+begin
+  for LI := 3 downto 0 do
+  begin
+    LX := AX[LI];
+    LY := AY[LI];
+    if LX < LY then
+    begin
+      Result := False;
+      Exit;
+    end;
+    if LX > LY then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat128.Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean;
+var
+  LI: Int32;
+  LX, LY: UInt32;
+begin
+  for LI := 3 downto 0 do
+  begin
+    LX := AX[AXOff + LI];
+    LY := AY[AYOff + LI];
+    if LX < LY then
+    begin
+      Result := False;
+      Exit;
+    end;
+    if LX > LY then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat128.IsOne(const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  if AX[0] <> 1 then
+  begin
+    Result := False;
+    Exit;
+  end;
+
+  for LI := 1 to 3 do
+  begin
+    if AX[LI] <> 0 then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  Result := True;
+end;
+
+class function TNat128.IsOne64(const AX: TCryptoLibUInt64Array): Boolean;
+begin
+  if AX[0] <> 1 then
+  begin
+    Result := False;
+    Exit;
+  end;
+  Result := AX[1] = 0;
+end;
+
+class function TNat128.IsZero(const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 0 to 3 do
+  begin
+    if AX[LI] <> 0 then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat128.IsZero64(const AX: TCryptoLibUInt64Array): Boolean;
+begin
+  Result := (AX[0] = 0) and (AX[1] = 0);
+end;
+
+class function TNat128.IsZero64(const AX: TCryptoLibUInt64Array; AXOff: Int32): Boolean;
+begin
+  Result := (AX[AXOff + 0] = 0) and (AX[AXOff + 1] = 0);
+end;
+
+class procedure TNat128.Mul(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array);
+var
+  LY0, LY1, LY2, LY3: UInt64;
+  LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+
+  // i = 0
+  LC := 0;
+  LXI := AX[0];
+  LC := LC + LXI * LY0;
+  AZZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY1;
+  AZZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY2;
+  AZZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY3;
+  AZZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  AZZ[4] := UInt32(LC);
+
+  for LI := 1 to 3 do
+  begin
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + LXI * LY0 + AZZ[LI + 0];
+    AZZ[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[LI + 1];
+    AZZ[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[LI + 2];
+    AZZ[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[LI + 3];
+    AZZ[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    AZZ[LI + 4] := UInt32(LC);
+  end;
+end;
+
+class procedure TNat128.Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZZ: TCryptoLibUInt32Array; AZZOff: Int32);
+var
+  LY0, LY1, LY2, LY3: UInt64;
+  LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+
+  LC := 0;
+  LXI := AX[AXOff + 0];
+  LC := LC + LXI * LY0;
+  AZZ[AZZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY1;
+  AZZ[AZZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY2;
+  AZZ[AZZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY3;
+  AZZ[AZZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  AZZ[AZZOff + 4] := UInt32(LC);
+
+  for LI := 1 to 3 do
+  begin
+    Inc(AZZOff);
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + LXI * LY0 + AZZ[AZZOff + 0];
+    AZZ[AZZOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[AZZOff + 1];
+    AZZ[AZZOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[AZZOff + 2];
+    AZZ[AZZOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[AZZOff + 3];
+    AZZ[AZZOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    AZZ[AZZOff + 4] := UInt32(LC);
+  end;
+end;
+
+class function TNat128.MulAddTo(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array): UInt32;
+var
+  LY0, LY1, LY2, LY3: UInt64;
+  LZC, LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+
+  LZC := 0;
+  for LI := 0 to 3 do
+  begin
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + LXI * LY0 + AZZ[LI + 0];
+    AZZ[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[LI + 1];
+    AZZ[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[LI + 2];
+    AZZ[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[LI + 3];
+    AZZ[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+
+    LZC := LZC + LC + AZZ[LI + 4];
+    AZZ[LI + 4] := UInt32(LZC);
+    LZC := LZC shr 32;
+  end;
+
+  Result := UInt32(LZC);
+end;
+
+class function TNat128.MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZZ: TCryptoLibUInt32Array; AZZOff: Int32): UInt32;
+var
+  LY0, LY1, LY2, LY3: UInt64;
+  LZC, LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+
+  LZC := 0;
+  for LI := 0 to 3 do
+  begin
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + LXI * LY0 + AZZ[AZZOff + 0];
+    AZZ[AZZOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[AZZOff + 1];
+    AZZ[AZZOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[AZZOff + 2];
+    AZZ[AZZOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[AZZOff + 3];
+    AZZ[AZZOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+
+    LZC := LZC + LC + AZZ[AZZOff + 4];
+    AZZ[AZZOff + 4] := UInt32(LZC);
+    LZC := LZC shr 32;
+    Inc(AZZOff);
+  end;
+
+  Result := UInt32(LZC);
+end;
+
+class function TNat128.Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array;
+  AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64;
+var
+  LC, LWVal: UInt64;
+  LX0, LX1, LX2, LX3: UInt64;
+begin
+ {$IFDEF DEBUG}
+  System.Assert((AW shr 31) = 0);
+ {$ENDIF}
+
+  LC := 0;
+  LWVal := AW;
+
+  LX0 := AX[AXOff + 0];
+  LC := LC + LWVal * LX0 + AY[AYOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX1 := AX[AXOff + 1];
+  LC := LC + LWVal * LX1 + LX0 + AY[AYOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX2 := AX[AXOff + 2];
+  LC := LC + LWVal * LX2 + LX1 + AY[AYOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX3 := AX[AXOff + 3];
+  LC := LC + LWVal * LX3 + LX2 + AY[AYOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LX3;
+  Result := LC;
+end;
+
+class function TNat128.MulWordAddExt(AX: UInt32; const AYY: TCryptoLibUInt32Array; AYYOff: Int32; const AZZ: TCryptoLibUInt32Array;
+  AZZOff: Int32): UInt32;
+var
+  LC, LXVal: UInt64;
+begin
+ {$IFDEF DEBUG}
+  System.Assert(AYYOff <= 4);
+  System.Assert(AZZOff <= 4);
+ {$ENDIF}
+
+  LC := 0;
+  LXVal := AX;
+
+  LC := LC + LXVal * AYY[AYYOff + 0] + AZZ[AZZOff + 0];
+  AZZ[AZZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 1] + AZZ[AZZOff + 1];
+  AZZ[AZZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 2] + AZZ[AZZOff + 2];
+  AZZ[AZZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 3] + AZZ[AZZOff + 3];
+  AZZ[AZZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+
+  Result := UInt32(LC);
+end;
+
+class function TNat128.Mul33DWordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal, LY00, LY01: UInt64;
+begin
+ {$IFDEF DEBUG}
+  System.Assert((AX shr 31) = 0);
+  System.Assert(AZOff <= 0);
+ {$ENDIF}
+
+  LC := 0;
+  LXVal := AX;
+  LY00 := AY and M;
+
+  LC := LC + LXVal * LY00 + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LY01 := AY shr 32;
+  LC := LC + LXVal * LY01 + LY00 + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LY01 + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(4, AZ, AZOff, 3);
+end;
+
+class function TNat128.Mul33WordAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LYVal: UInt64;
+begin
+ {$IFDEF DEBUG}
+  System.Assert((AX shr 31) = 0);
+  System.Assert(AZOff <= 1);
+ {$ENDIF}
+
+  LC := 0;
+  LYVal := AY;
+
+  LC := LC + LYVal * AX + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LYVal + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(4, AZ, AZOff, 2);
+end;
+
+class function TNat128.MulWordDwordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal: UInt64;
+begin
+ {$IFDEF DEBUG}
+  System.Assert(AZOff <= 1);
+ {$ENDIF}
+
+  LC := 0;
+  LXVal := AX;
+
+  LC := LC + LXVal * AY + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * (AY shr 32) + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(4, AZ, AZOff, 3);
+end;
+
+class function TNat128.MulWordsAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal, LYVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AZOff <= 2);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LYVal := AY;
+
+  LC := LC + LYVal * LXVal + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(4, AZ, AZOff, 2);
+end;
+
+class function TNat128.MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal: UInt64;
+  LI: Int32;
+begin
+  LC := 0;
+  LXVal := AX;
+  LI := 0;
+  repeat
+    LC := LC + LXVal * AY[LI];
+    AZ[AZOff + LI] := UInt32(LC);
+    LC := LC shr 32;
+    Inc(LI);
+  until LI >= 4;
+
+  Result := UInt32(LC);
+end;
+
+class procedure TNat128.Square(const AX: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array);
+var
+  LX0, LX1, LX2, LX3: UInt64;
+  LZZ1, LZZ2, LZZ3, LZZ4, LZZ5, LZZ6: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI, LJ: Int32;
+  LXVal, LP: UInt64;
+begin
+  LX0 := AX[0];
+
+  LC := 0;
+  LI := 3;
+  LJ := 8;
+  repeat
+    LXVal := AX[LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZZ[LJ] := (LC shl 31) or UInt32(LP shr 33);
+    Dec(LJ);
+    AZZ[LJ] := UInt32(LP shr 1);
+    LC := UInt32(LP);
+  until LI <= 0;
+
+  LP := LX0 * LX0;
+  LZZ1 := UInt64(LC shl 31) or (LP shr 33);
+  AZZ[0] := UInt32(LP);
+  LC := UInt32(LP shr 32) and 1;
+
+  LX1 := AX[1];
+  LZZ2 := AZZ[2];
+
+  LZZ1 := LZZ1 + LX1 * LX0;
+  LW := UInt32(LZZ1);
+  AZZ[1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ2 := LZZ2 + (LZZ1 shr 32);
+
+  LX2 := AX[2];
+  LZZ3 := AZZ[3];
+  LZZ4 := AZZ[4];
+
+  LZZ2 := LZZ2 + LX2 * LX0;
+  LW := UInt32(LZZ2);
+  AZZ[2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ3 := LZZ3 + (LZZ2 shr 32) + LX2 * LX1;
+  LZZ4 := LZZ4 + (LZZ3 shr 32);
+  LZZ3 := LZZ3 and M;
+
+  LX3 := AX[3];
+  LZZ5 := AZZ[5] + (LZZ4 shr 32);
+  LZZ4 := LZZ4 and M;
+  LZZ6 := AZZ[6] + (LZZ5 shr 32);
+  LZZ5 := LZZ5 and M;
+
+  LZZ3 := LZZ3 + LX3 * LX0;
+  LW := UInt32(LZZ3);
+  AZZ[3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ4 := LZZ4 + (LZZ3 shr 32) + LX3 * LX1;
+  LZZ5 := LZZ5 + (LZZ4 shr 32) + LX3 * LX2;
+  LZZ4 := LZZ4 and M;
+  LZZ6 := LZZ6 + (LZZ5 shr 32);
+
+  LW := UInt32(LZZ4);
+  AZZ[4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ5);
+  AZZ[5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ6);
+  AZZ[6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+
+  LW := AZZ[7] + UInt32(LZZ6 shr 32);
+  AZZ[7] := (LW shl 1) or LC;
+end;
+
+class procedure TNat128.Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZZ: TCryptoLibUInt32Array; AZZOff: Int32);
+var
+  LX0, LX1, LX2, LX3: UInt64;
+  LZZ1, LZZ2, LZZ3, LZZ4, LZZ5, LZZ6: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI, LJ: Int32;
+  LXVal, LP: UInt64;
+begin
+  LX0 := AX[AXOff + 0];
+
+  LC := 0;
+  LI := 3;
+  LJ := 8;
+  repeat
+    LXVal := AX[AXOff + LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZZ[AZZOff + LJ] := (LC shl 31) or UInt32(LP shr 33);
+    Dec(LJ);
+    AZZ[AZZOff + LJ] := UInt32(LP shr 1);
+    LC := UInt32(LP);
+  until LI <= 0;
+
+  LP := LX0 * LX0;
+  LZZ1 := UInt64(LC shl 31) or (LP shr 33);
+  AZZ[AZZOff + 0] := UInt32(LP);
+  LC := UInt32(LP shr 32) and 1;
+
+  LX1 := AX[AXOff + 1];
+  LZZ2 := AZZ[AZZOff + 2];
+
+  LZZ1 := LZZ1 + LX1 * LX0;
+  LW := UInt32(LZZ1);
+  AZZ[AZZOff + 1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ2 := LZZ2 + (LZZ1 shr 32);
+
+  LX2 := AX[AXOff + 2];
+  LZZ3 := AZZ[AZZOff + 3];
+  LZZ4 := AZZ[AZZOff + 4];
+
+  LZZ2 := LZZ2 + LX2 * LX0;
+  LW := UInt32(LZZ2);
+  AZZ[AZZOff + 2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ3 := LZZ3 + (LZZ2 shr 32) + LX2 * LX1;
+  LZZ4 := LZZ4 + (LZZ3 shr 32);
+  LZZ3 := LZZ3 and M;
+
+  LX3 := AX[AXOff + 3];
+  LZZ5 := AZZ[AZZOff + 5] + (LZZ4 shr 32);
+  LZZ4 := LZZ4 and M;
+  LZZ6 := AZZ[AZZOff + 6] + (LZZ5 shr 32);
+  LZZ5 := LZZ5 and M;
+
+  LZZ3 := LZZ3 + LX3 * LX0;
+  LW := UInt32(LZZ3);
+  AZZ[AZZOff + 3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ4 := LZZ4 + (LZZ3 shr 32) + LX3 * LX1;
+  LZZ5 := LZZ5 + (LZZ4 shr 32) + LX3 * LX2;
+  LZZ4 := LZZ4 and M;
+  LZZ6 := LZZ6 + (LZZ5 shr 32);
+
+  LW := UInt32(LZZ4);
+  AZZ[AZZOff + 4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ5);
+  AZZ[AZZOff + 5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ6);
+  AZZ[AZZOff + 6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+
+  LW := AZZ[AZZOff + 7] + UInt32(LZZ6 shr 32);
+  AZZ[AZZOff + 7] := (LW shl 1) or LC;
+end;
+
+class function TNat128.Sub(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AX[0]) - AY[0];
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[1]) - AY[1];
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[2]) - AY[2];
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[3]) - AY[3];
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat128.Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AX[AXOff + 0]) - AY[AYOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 1]) - AY[AYOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 2]) - AY[AYOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 3]) - AY[AYOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat128.SubBothFrom(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AZ[0]) - AX[0] - AY[0];
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[1]) - AX[1] - AY[1];
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[2]) - AX[2] - AY[2];
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[3]) - AX[3] - AY[3];
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat128.SubFrom(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AZ[0]) - AX[0];
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[1]) - AX[1];
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[2]) - AX[2];
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[3]) - AX[3];
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat128.SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AZ[AZOff + 0]) - AX[AXOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 1]) - AX[AXOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 2]) - AX[AXOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 3]) - AX[AXOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat128.ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger;
+var
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXI: UInt32;
+begin
+  System.SetLength(LBs, 16);
+  for LI := 0 to 3 do
+  begin
+    LXI := AX[LI];
+    if LXI <> 0 then
+      TPack.UInt32_To_BE(LXI, LBs, (3 - LI) shl 2);
+  end;
+
+  Result := TBigInteger.Create(1, LBs);
+end;
+
+class function TNat128.ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger;
+var
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXI: UInt64;
+begin
+  System.SetLength(LBs, 16);
+  for LI := 0 to 1 do
+  begin
+    LXI := AX[LI];
+    if LXI <> 0 then
+      TPack.UInt64_To_BE(LXI, LBs, (1 - LI) shl 3);
+  end;
+
+  Result := TBigInteger.Create(1, LBs);
+end;
+
+class procedure TNat128.Zero(const AZ: TCryptoLibUInt32Array);
+begin
+  TArrayUtilities.Fill<UInt32>(AZ, 0, 4, UInt32(0));
+end;
+
+end.

+ 1145 - 0
CryptoLib/src/Math/Raw/ClpNat160.pas

@@ -0,0 +1,1145 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpNat160;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpArrayUtilities,
+  ClpBitUtilities,
+  ClpBigInteger,
+  ClpPack,
+  ClpNat,
+  ClpCryptoLibTypes;
+
+type
+  TNat160 = class sealed
+  strict private
+    const M: UInt64 = UInt64($FFFFFFFF);
+  public
+    class function Add(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function AddBothTo(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32;
+      ACIn: UInt32): UInt32; overload; static;
+    class function AddToEachOther(const AU: TCryptoLibUInt32Array; AUOff: Int32; const AV: TCryptoLibUInt32Array;
+      AVOff: Int32): UInt32; static;
+
+    class procedure Copy(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+
+    class function Create: TCryptoLibUInt32Array; static;
+    class function CreateExt: TCryptoLibUInt32Array; static;
+
+    class function Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean; static;
+
+    class function Eq(const AX, AY: TCryptoLibUInt32Array): Boolean; static;
+    class function GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32; static;
+
+    class function Gte(const AX, AY: TCryptoLibUInt32Array): Boolean; overload; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean; overload; static;
+
+    class function IsOne(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Boolean; static;
+
+    class procedure Mul(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZZ: TCryptoLibUInt32Array; AZZOff: Int32); overload; static;
+
+    class function MulAddTo(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZZ: TCryptoLibUInt32Array; AZZOff: Int32): UInt32; overload; static;
+
+    class function Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array;
+      AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64; static;
+
+    class function MulWordAddExt(AX: UInt32; const AYY: TCryptoLibUInt32Array; AYYOff: Int32; const AZZ: TCryptoLibUInt32Array;
+      AZZOff: Int32): UInt32; static;
+
+    class function Mul33DWordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function Mul33WordAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWordDwordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWordsAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+
+    class procedure Square(const AX: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZZ: TCryptoLibUInt32Array; AZZOff: Int32); overload; static;
+
+    class function Sub(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+      const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+
+    class function SubBothFrom(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+
+    class function ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger; static;
+    class procedure Zero(const AZ: TCryptoLibUInt32Array); static;
+  end;
+
+implementation
+
+class function TNat160.Add(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AY[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat160.AddBothTo(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0] + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1] + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2] + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3] + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AY[4] + AZ[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat160.AddTo(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AZ[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat160.AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32;
+  ACIn: UInt32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := ACIn;
+  LC := LC + UInt64(AX[AXOff + 0]) + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 1]) + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 2]) + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 3]) + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 4]) + AZ[AZOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  //LC := LC + UInt64(AX[AXOff + 5]) + AZ[AZOff + 5];
+  Result := UInt32(LC);
+end;
+
+class function TNat160.AddToEachOther(const AU: TCryptoLibUInt32Array; AUOff: Int32; const AV: TCryptoLibUInt32Array;
+  AVOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LTmp: UInt32;
+begin
+  LC := 0;
+  LC := LC + UInt64(AU[AUOff + 0]) + AV[AVOff + 0];
+  LTmp := UInt32(LC);
+  AU[AUOff + 0] := LTmp;
+  AV[AVOff + 0] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 1]) + AV[AVOff + 1];
+  LTmp := UInt32(LC);
+  AU[AUOff + 1] := LTmp;
+  AV[AVOff + 1] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 2]) + AV[AVOff + 2];
+  LTmp := UInt32(LC);
+  AU[AUOff + 2] := LTmp;
+  AV[AVOff + 2] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 3]) + AV[AVOff + 3];
+  LTmp := UInt32(LC);
+  AU[AUOff + 3] := LTmp;
+  AV[AVOff + 3] := LTmp;
+  LC := LC shr 32;
+
+  LC := LC + UInt64(AU[AUOff + 4]) + AV[AVOff + 4];
+  LTmp := UInt32(LC);
+  AU[AUOff + 4] := LTmp;
+  AV[AVOff + 4] := LTmp;
+  LC := LC shr 32;
+
+  Result := UInt32(LC);
+end;
+
+class procedure TNat160.Copy(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array);
+begin
+  System.Move(AX[0], AZ[0], 5 * System.SizeOf(UInt32));
+end;
+
+class procedure TNat160.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32);
+begin
+  AZ[AZOff + 0] := AX[AXOff + 0];
+  AZ[AZOff + 1] := AX[AXOff + 1];
+  AZ[AZOff + 2] := AX[AXOff + 2];
+  AZ[AZOff + 3] := AX[AXOff + 3];
+  AZ[AZOff + 4] := AX[AXOff + 4];
+end;
+
+class function TNat160.Create: TCryptoLibUInt32Array;
+begin
+  System.SetLength(Result, 5);
+end;
+
+class function TNat160.CreateExt: TCryptoLibUInt32Array;
+begin
+  System.SetLength(Result, 10);
+end;
+
+class function TNat160.Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean;
+var
+  LPos: Boolean;
+begin
+  LPos := Gte(AX, AXOff, AY, AYOff);
+  if LPos then
+    Sub(AX, AXOff, AY, AYOff, AZ, AZOff)
+  else
+    Sub(AY, AYOff, AX, AXOff, AZ, AZOff);
+  Result := LPos;
+end;
+
+class function TNat160.Eq(const AX, AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 4 downto 0 do
+  begin
+    if AX[LI] <> AY[LI] then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat160.GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32;
+var
+  LW, LB: Int32;
+begin
+  if ABit = 0 then
+  begin
+    Result := AX[0] and 1;
+    Exit;
+  end;
+
+  LW := TBitUtilities.Asr32(ABit, 5);
+  if (LW < 0) or (LW >= 5) then
+  begin
+    Result := 0;
+    Exit;
+  end;
+
+  LB := ABit and 31;
+  Result := (AX[LW] shr LB) and 1;
+end;
+
+class function TNat160.Gte(const AX, AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+  LX, LY: UInt32;
+begin
+  for LI := 4 downto 0 do
+  begin
+    LX := AX[LI];
+    LY := AY[LI];
+    if LX < LY then
+    begin
+      Result := False;
+      Exit;
+    end;
+    if LX > LY then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat160.Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean;
+var
+  LI: Int32;
+  LX, LY: UInt32;
+begin
+  for LI := 4 downto 0 do
+  begin
+    LX := AX[AXOff + LI];
+    LY := AY[AYOff + LI];
+    if LX < LY then
+    begin
+      Result := False;
+      Exit;
+    end;
+    if LX > LY then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat160.IsOne(const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  if AX[0] <> 1 then
+  begin
+    Result := False;
+    Exit;
+  end;
+
+  for LI := 1 to 4 do
+  begin
+    if AX[LI] <> 0 then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  Result := True;
+end;
+
+class function TNat160.IsZero(const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 0 to 4 do
+  begin
+    if AX[LI] <> 0 then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class procedure TNat160.Mul(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array);
+var
+  LY0, LY1, LY2, LY3, LY4: UInt64;
+  LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+  LY4 := AY[4];
+
+  // i = 0
+  LC := 0;
+  LXI := AX[0];
+  LC := LC + LXI * LY0;
+  AZZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY1;
+  AZZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY2;
+  AZZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY3;
+  AZZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY4;
+  AZZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  AZZ[5] := UInt32(LC);
+
+  for LI := 1 to 4 do
+  begin
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + LXI * LY0 + AZZ[LI + 0];
+    AZZ[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[LI + 1];
+    AZZ[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[LI + 2];
+    AZZ[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[LI + 3];
+    AZZ[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY4 + AZZ[LI + 4];
+    AZZ[LI + 4] := UInt32(LC);
+    LC := LC shr 32;
+    AZZ[LI + 5] := UInt32(LC);
+  end;
+end;
+
+class procedure TNat160.Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZZ: TCryptoLibUInt32Array; AZZOff: Int32);
+var
+  LY0, LY1, LY2, LY3, LY4: UInt64;
+  LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+  LY4 := AY[AYOff + 4];
+
+  // i = 0
+  LC := 0;
+  LXI := AX[AXOff + 0];
+  LC := LC + LXI * LY0;
+  AZZ[AZZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY1;
+  AZZ[AZZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY2;
+  AZZ[AZZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY3;
+  AZZ[AZZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXI * LY4;
+  AZZ[AZZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  AZZ[AZZOff + 5] := UInt32(LC);
+
+  for LI := 1 to 4 do
+  begin
+    Inc(AZZOff);
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + LXI * LY0 + AZZ[AZZOff + 0];
+    AZZ[AZZOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[AZZOff + 1];
+    AZZ[AZZOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[AZZOff + 2];
+    AZZ[AZZOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[AZZOff + 3];
+    AZZ[AZZOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY4 + AZZ[AZZOff + 4];
+    AZZ[AZZOff + 4] := UInt32(LC);
+    LC := LC shr 32;
+    AZZ[AZZOff + 5] := UInt32(LC);
+  end;
+end;
+
+class function TNat160.MulAddTo(const AX, AY: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array): UInt32;
+var
+  LY0, LY1, LY2, LY3, LY4: UInt64;
+  LZC, LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+  LY4 := AY[4];
+
+  LZC := 0;
+  for LI := 0 to 4 do
+  begin
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + LXI * LY0 + AZZ[LI + 0];
+    AZZ[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[LI + 1];
+    AZZ[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[LI + 2];
+    AZZ[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[LI + 3];
+    AZZ[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY4 + AZZ[LI + 4];
+    AZZ[LI + 4] := UInt32(LC);
+    LC := LC shr 32;
+
+    LZC := LZC + LC + AZZ[LI + 5];
+    AZZ[LI + 5] := UInt32(LZC);
+    LZC := LZC shr 32;
+  end;
+
+  Result := UInt32(LZC);
+end;
+
+class function TNat160.MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZZ: TCryptoLibUInt32Array; AZZOff: Int32): UInt32;
+var
+  LY0, LY1, LY2, LY3, LY4: UInt64;
+  LZC, LC, LXI: UInt64;
+  LI: Int32;
+begin
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+  LY4 := AY[AYOff + 4];
+
+  LZC := 0;
+  for LI := 0 to 4 do
+  begin
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + LXI * LY0 + AZZ[AZZOff + 0];
+    AZZ[AZZOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY1 + AZZ[AZZOff + 1];
+    AZZ[AZZOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY2 + AZZ[AZZOff + 2];
+    AZZ[AZZOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY3 + AZZ[AZZOff + 3];
+    AZZ[AZZOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + LXI * LY4 + AZZ[AZZOff + 4];
+    AZZ[AZZOff + 4] := UInt32(LC);
+    LC := LC shr 32;
+
+    LZC := LZC + LC + AZZ[AZZOff + 5];
+    AZZ[AZZOff + 5] := UInt32(LZC);
+    LZC := LZC shr 32;
+    Inc(AZZOff);
+  end;
+
+  Result := UInt32(LZC);
+end;
+
+class function TNat160.Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array;
+  AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64;
+var
+  LC, LWVal: UInt64;
+  LX0, LX1, LX2, LX3, LX4: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AW shr 31) = 0);
+  {$ENDIF}
+
+  LC := 0;
+  LWVal := AW;
+
+  LX0 := AX[AXOff + 0];
+  LC := LC + LWVal * LX0 + AY[AYOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX1 := AX[AXOff + 1];
+  LC := LC + LWVal * LX1 + LX0 + AY[AYOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX2 := AX[AXOff + 2];
+  LC := LC + LWVal * LX2 + LX1 + AY[AYOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX3 := AX[AXOff + 3];
+  LC := LC + LWVal * LX3 + LX2 + AY[AYOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+
+  LX4 := AX[AXOff + 4];
+  LC := LC + LWVal * LX4 + LX3 + AY[AYOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LX4;
+  Result := LC;
+end;
+
+class function TNat160.MulWordAddExt(AX: UInt32; const AYY: TCryptoLibUInt32Array; AYYOff: Int32; const AZZ: TCryptoLibUInt32Array;
+  AZZOff: Int32): UInt32;
+var
+  LC, LXVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AYYOff <= 5);
+  System.Assert(AZZOff <= 5);
+  {$ENDIF}
+
+  LC := 0;
+  LXVal := AX;
+
+  LC := LC + LXVal * AYY[AYYOff + 0] + AZZ[AZZOff + 0];
+  AZZ[AZZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 1] + AZZ[AZZOff + 1];
+  AZZ[AZZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 2] + AZZ[AZZOff + 2];
+  AZZ[AZZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 3] + AZZ[AZZOff + 3];
+  AZZ[AZZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * AYY[AYYOff + 4] + AZZ[AZZOff + 4];
+  AZZ[AZZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+
+  Result := UInt32(LC);
+end;
+
+class function TNat160.Mul33DWordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal, LY00, LY01: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AX shr 31) = 0);
+  System.Assert(AZOff <= 1);
+  {$ENDIF}
+
+  LC := 0;
+  LXVal := AX;
+  LY00 := AY and M;
+
+  LC := LC + LXVal * LY00 + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LY01 := AY shr 32;
+  LC := LC + LXVal * LY01 + LY00 + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LY01 + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(5, AZ, AZOff, 4);
+end;
+
+class function TNat160.Mul33WordAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LYVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((AX shr 31) = 0);
+  System.Assert(AZOff <= 2);
+  {$ENDIF}
+
+  LC := 0;
+  LYVal := AY;
+
+  LC := LC + LYVal * AX + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LYVal + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(5, AZ, AZOff, 3);
+end;
+
+class function TNat160.MulWordDwordAdd(AX: UInt32; AY: UInt64; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AZOff <= 2);
+  {$ENDIF}
+
+  LC := 0;
+  LXVal := AX;
+
+  LC := LC + LXVal * AY + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + LXVal * (AY shr 32) + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(5, AZ, AZOff, 3);
+end;
+
+class function TNat160.MulWordsAdd(AX, AY: UInt32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal, LYVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AZOff <= 3);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LYVal := AY;
+
+  LC := LC + LYVal * LXVal + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+
+  LC := LC + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(5, AZ, AZOff, 2);
+end;
+
+class function TNat160.MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC, LXVal: UInt64;
+  LI: Int32;
+begin
+  LC := 0;
+  LXVal := AX;
+  LI := 0;
+  repeat
+    LC := LC + LXVal * AY[LI];
+    AZ[AZOff + LI] := UInt32(LC);
+    LC := LC shr 32;
+    Inc(LI);
+  until LI >= 5;
+
+  Result := UInt32(LC);
+end;
+
+class procedure TNat160.Square(const AX: TCryptoLibUInt32Array; const AZZ: TCryptoLibUInt32Array);
+var
+  LX0, LX1, LX2, LX3, LX4: UInt64;
+  LZZ1, LZZ2, LZZ3, LZZ4, LZZ5, LZZ6, LZZ7, LZZ8: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI, LJ: Int32;
+  LXVal, LP: UInt64;
+begin
+  LX0 := AX[0];
+
+  LC := 0;
+  // Fill high words of square
+  LI := 4;
+  LJ := 10;
+  repeat
+    LXVal := AX[LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZZ[LJ] := (LC shl 31) or UInt32(LP shr 33);
+    Dec(LJ);
+    AZZ[LJ] := UInt32(LP shr 1);
+    LC := UInt32(LP);
+  until LI <= 0;
+
+  // i = 0
+  LP := LX0 * LX0;
+  LZZ1 := UInt64(LC shl 31) or (LP shr 33);
+  AZZ[0] := UInt32(LP);
+  LC := UInt32(LP shr 32) and 1;
+
+  LX1 := AX[1];
+  LZZ2 := AZZ[2];
+
+  // x1 * x0
+  LZZ1 := LZZ1 + LX1 * LX0;
+  LW := UInt32(LZZ1);
+  AZZ[1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ2 := LZZ2 + (LZZ1 shr 32);
+
+  LX2 := AX[2];
+  LZZ3 := AZZ[3];
+  LZZ4 := AZZ[4];
+
+  // x2 * x0, x2 * x1
+  LZZ2 := LZZ2 + LX2 * LX0;
+  LW := UInt32(LZZ2);
+  AZZ[2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ3 := LZZ3 + (LZZ2 shr 32) + LX2 * LX1;
+  LZZ4 := LZZ4 + (LZZ3 shr 32);
+  LZZ3 := LZZ3 and M;
+
+  LX3 := AX[3];
+  LZZ5 := AZZ[5] + (LZZ4 shr 32);
+  LZZ4 := LZZ4 and M;
+  LZZ6 := AZZ[6] + (LZZ5 shr 32);
+  LZZ5 := LZZ5 and M;
+
+  // x3 terms
+  LZZ3 := LZZ3 + LX3 * LX0;
+  LW := UInt32(LZZ3);
+  AZZ[3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ4 := LZZ4 + (LZZ3 shr 32) + LX3 * LX1;
+  LZZ5 := LZZ5 + (LZZ4 shr 32) + LX3 * LX2;
+  LZZ4 := LZZ4 and M;
+  LZZ6 := LZZ6 + (LZZ5 shr 32);
+  LZZ5 := LZZ5 and M;
+
+  LX4 := AX[4];
+  LZZ7 := AZZ[7] + (LZZ6 shr 32);
+  LZZ6 := LZZ6 and M;
+  LZZ8 := AZZ[8] + (LZZ7 shr 32);
+  LZZ7 := LZZ7 and M;
+
+  // x4 terms
+  LZZ4 := LZZ4 + LX4 * LX0;
+  LW := UInt32(LZZ4);
+  AZZ[4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ5 := LZZ5 + (LZZ4 shr 32) + LX4 * LX1;
+  LZZ6 := LZZ6 + (LZZ5 shr 32) + LX4 * LX2;
+  LZZ7 := LZZ7 + (LZZ6 shr 32) + LX4 * LX3;
+  LZZ8 := LZZ8 + (LZZ7 shr 32);
+
+  LW := UInt32(LZZ5);
+  AZZ[5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ6);
+  AZZ[6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ7);
+  AZZ[7] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ8);
+  AZZ[8] := (LW shl 1) or LC;
+  LC := LW shr 31;
+
+  LW := AZZ[9] + UInt32(LZZ8 shr 32);
+  AZZ[9] := (LW shl 1) or LC;
+end;
+
+class procedure TNat160.Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZZ: TCryptoLibUInt32Array; AZZOff: Int32);
+var
+  LX0, LX1, LX2, LX3, LX4: UInt64;
+  LZZ1, LZZ2, LZZ3, LZZ4, LZZ5, LZZ6, LZZ7, LZZ8: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI, LJ: Int32;
+  LXVal, LP: UInt64;
+begin
+  LX0 := AX[AXOff + 0];
+
+  LC := 0;
+  LI := 4;
+  LJ := 10;
+  repeat
+    LXVal := AX[AXOff + LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZZ[AZZOff + LJ] := (LC shl 31) or UInt32(LP shr 33);
+    Dec(LJ);
+    AZZ[AZZOff + LJ] := UInt32(LP shr 1);
+    LC := UInt32(LP);
+  until LI <= 0;
+
+  LP := LX0 * LX0;
+  LZZ1 := UInt64(LC shl 31) or (LP shr 33);
+  AZZ[AZZOff + 0] := UInt32(LP);
+  LC := UInt32(LP shr 32) and 1;
+
+  LX1 := AX[AXOff + 1];
+  LZZ2 := AZZ[AZZOff + 2];
+
+  LZZ1 := LZZ1 + LX1 * LX0;
+  LW := UInt32(LZZ1);
+  AZZ[AZZOff + 1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ2 := LZZ2 + (LZZ1 shr 32);
+
+  LX2 := AX[AXOff + 2];
+  LZZ3 := AZZ[AZZOff + 3];
+  LZZ4 := AZZ[AZZOff + 4];
+
+  LZZ2 := LZZ2 + LX2 * LX0;
+  LW := UInt32(LZZ2);
+  AZZ[AZZOff + 2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ3 := LZZ3 + (LZZ2 shr 32) + LX2 * LX1;
+  LZZ4 := LZZ4 + (LZZ3 shr 32);
+  LZZ3 := LZZ3 and M;
+
+  LX3 := AX[AXOff + 3];
+  LZZ5 := AZZ[AZZOff + 5] + (LZZ4 shr 32);
+  LZZ4 := LZZ4 and M;
+  LZZ6 := AZZ[AZZOff + 6] + (LZZ5 shr 32);
+  LZZ5 := LZZ5 and M;
+
+  LZZ3 := LZZ3 + LX3 * LX0;
+  LW := UInt32(LZZ3);
+  AZZ[AZZOff + 3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ4 := LZZ4 + (LZZ3 shr 32) + LX3 * LX1;
+  LZZ5 := LZZ5 + (LZZ4 shr 32) + LX3 * LX2;
+  LZZ4 := LZZ4 and M;
+  LZZ6 := LZZ6 + (LZZ5 shr 32);
+  LZZ5 := LZZ5 and M;
+
+  LX4 := AX[AXOff + 4];
+  LZZ7 := AZZ[AZZOff + 7] + (LZZ6 shr 32);
+  LZZ6 := LZZ6 and M;
+  LZZ8 := AZZ[AZZOff + 8] + (LZZ7 shr 32);
+  LZZ7 := LZZ7 and M;
+
+  LZZ4 := LZZ4 + LX4 * LX0;
+  LW := UInt32(LZZ4);
+  AZZ[AZZOff + 4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZZ5 := LZZ5 + (LZZ4 shr 32) + LX4 * LX1;
+  LZZ6 := LZZ6 + (LZZ5 shr 32) + LX4 * LX2;
+  LZZ7 := LZZ7 + (LZZ6 shr 32) + LX4 * LX3;
+  LZZ8 := LZZ8 + (LZZ7 shr 32);
+
+  LW := UInt32(LZZ5);
+  AZZ[AZZOff + 5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ6);
+  AZZ[AZZOff + 6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ7);
+  AZZ[AZZOff + 7] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZZ8);
+  AZZ[AZZOff + 8] := (LW shl 1) or LC;
+  LC := LW shr 31;
+
+  LW := AZZ[AZZOff + 9] + UInt32(LZZ8 shr 32);
+  AZZ[AZZOff + 9] := (LW shl 1) or LC;
+end;
+
+class function TNat160.Sub(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AX[0]) - AY[0];
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[1]) - AY[1];
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[2]) - AY[2];
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[3]) - AY[3];
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[4]) - AY[4];
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat160.Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32;
+  const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AX[AXOff + 0]) - AY[AYOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 1]) - AY[AYOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 2]) - AY[AYOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 3]) - AY[AYOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AX[AXOff + 4]) - AY[AYOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat160.SubBothFrom(const AX, AY: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AZ[0]) - AX[0] - AY[0];
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[1]) - AX[1] - AY[1];
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[2]) - AX[2] - AY[2];
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[3]) - AX[3] - AY[3];
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[4]) - AX[4] - AY[4];
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat160.SubFrom(const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AZ[0]) - AX[0];
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[1]) - AX[1];
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[2]) - AX[2];
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[3]) - AX[3];
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[4]) - AX[4];
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat160.SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + Int64(AZ[AZOff + 0]) - AX[AXOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 1]) - AX[AXOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 2]) - AX[AXOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 3]) - AX[AXOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + Int64(AZ[AZOff + 4]) - AX[AXOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat160.ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger;
+var
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXI: UInt32;
+begin
+  System.SetLength(LBs, 20);
+  for LI := 0 to 4 do
+  begin
+    LXI := AX[LI];
+    if LXI <> 0 then
+      TPack.UInt32_To_BE(LXI, LBs, (4 - LI) shl 2);
+  end;
+
+  Result := TBigInteger.Create(1, LBs);
+end;
+
+class procedure TNat160.Zero(const AZ: TCryptoLibUInt32Array);
+begin
+  TArrayUtilities.Fill<UInt32>(AZ, 0, 5, UInt32(0));
+end;
+
+end.

+ 987 - 1160
CryptoLib/src/Math/Raw/ClpNat192.pas

@@ -22,1406 +22,1233 @@ unit ClpNat192;
 interface
 
 uses
-  ClpBitUtilities,
+  SysUtils,
+  ClpArrayUtilities,
   ClpNat,
+  ClpPack,
   ClpBigInteger,
-  ClpConverters,
-  ClpArrayUtilities,
+  ClpBitUtilities,
   ClpCryptoLibTypes;
 
 type
-  TNat192 = class sealed(TObject)
-
+  TNat192 = class sealed
   strict private
-  const
-    M = UInt64($FFFFFFFF);
-
+    const M: UInt64 = $FFFFFFFF;
   public
-    class function Add(const x, y, z: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-
-    class function AddBothTo(const x, y, z: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-
-    class function AddTo(const x, z: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-    class function AddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32; cIn: UInt32): UInt32;
-      overload; static;
-    class function AddToEachOther(const u: TCryptoLibUInt32Array; uOff: Int32;
-      const v: TCryptoLibUInt32Array; vOff: Int32): UInt32; static;
-
-    class procedure Copy(const x, z: TCryptoLibUInt32Array); overload;
-      static; inline;
-    class procedure Copy(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32); overload; static; inline;
-
-    class procedure Copy64(const x, z: TCryptoLibUInt64Array); overload;
-      static; inline;
-
-    class procedure Copy64(const x: TCryptoLibUInt64Array; xOff: Int32;
-      const z: TCryptoLibUInt64Array; zOff: Int32); overload; static; inline;
-
-    class function Create(): TCryptoLibUInt32Array; static; inline;
-
-    class function Create64(): TCryptoLibUInt64Array; static; inline;
-
-    class function CreateExt(): TCryptoLibUInt32Array; static; inline;
-
-    class function CreateExt64(): TCryptoLibUInt64Array; static; inline;
-
-    class function Diff(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): Boolean; static; inline;
-
-    class function Eq(const x, y: TCryptoLibUInt32Array): Boolean; static;
-
-    class function Eq64(const x, y: TCryptoLibUInt64Array): Boolean; static;
-
-    class function FromBigInteger(const x: TBigInteger)
-      : TCryptoLibUInt32Array; static;
-
-    class function FromBigInteger64(const x: TBigInteger)
-      : TCryptoLibUInt64Array; static;
-
-    class function GetBit(const x: TCryptoLibUInt32Array; bit: Int32): UInt32;
-      static; inline;
-
-    class function Gte(const x, y: TCryptoLibUInt32Array): Boolean;
-      overload; static;
-
-    class function Gte(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32): Boolean; overload; static;
-
-    class function IsOne(const x: TCryptoLibUInt32Array): Boolean; static;
-
-    class function IsOne64(const x: TCryptoLibUInt64Array): Boolean; static;
-
-    class function IsZero(const x: TCryptoLibUInt32Array): Boolean; static;
-
-    class function IsZero64(const x: TCryptoLibUInt64Array): Boolean; static;
-
-    class procedure Mul(const x, y, zz: TCryptoLibUInt32Array);
-      overload; static;
-
-    class procedure Mul(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const zz: TCryptoLibUInt32Array; zzOff: Int32); overload; static;
-
-    class function MulAddTo(const x, y, zz: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-
-    class function MulAddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const zz: TCryptoLibUInt32Array; zzOff: Int32): UInt32; overload; static;
-
-    class function Mul33Add(w: UInt32; const x: TCryptoLibUInt32Array;
-      xOff: Int32; const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt64; static;
-
-    class function MulWordAddExt(x: UInt32; const yy: TCryptoLibUInt32Array;
-      yyOff: Int32; const zz: TCryptoLibUInt32Array; zzOff: Int32)
-      : UInt32; static;
-
-    class function Mul33DWordAdd(x: UInt32; y: UInt64;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; static;
-
-    class function Mul33WordAdd(x, y: UInt32; const z: TCryptoLibUInt32Array;
-      zOff: Int32): UInt32; static;
-
-    class function MulWordDwordAdd(x: UInt32; y: UInt64;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; static;
-
-    class function MulWord(x: UInt32; const y, z: TCryptoLibUInt32Array;
-      zOff: Int32): UInt32; static;
-
-    class procedure Square(const x, zz: TCryptoLibUInt32Array);
-      overload; static;
-
-    class procedure Square(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const zz: TCryptoLibUInt32Array; zzOff: Int32); overload; static;
-
-    class function Sub(const x, y, z: TCryptoLibUInt32Array): Int32;
-      overload; static;
-
-    class function Sub(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): Int32; overload; static;
-
-    class function SubBothFrom(const x, y, z: TCryptoLibUInt32Array)
-      : Int32; static;
-
-    class function SubFrom(const x, z: TCryptoLibUInt32Array): Int32;
-      overload; static;
-
-    class function SubFrom(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): Int32; overload; static;
-
-    class function ToBigInteger(const x: TCryptoLibUInt32Array)
-      : TBigInteger; static;
-
-    class function ToBigInteger64(const x: TCryptoLibUInt64Array)
-      : TBigInteger; static;
-
-    class procedure Zero(const z: TCryptoLibUInt32Array); static; inline;
-
+    class function Add(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function AddBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: UInt32): UInt32; overload; static;
+    class function AddToEachOther(AU: TCryptoLibUInt32Array; AUOff: Int32; AV: TCryptoLibUInt32Array; AVOff: Int32): UInt32; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+    class function Create(): TCryptoLibUInt32Array; static;
+    class function Create64(): TCryptoLibUInt64Array; static;
+    class function CreateExt(): TCryptoLibUInt32Array; static;
+    class function CreateExt64(): TCryptoLibUInt64Array; static;
+    class function Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean; static;
+    class function Eq(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean; static;
+    class function Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean; static;
+    class function GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean; overload; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean; overload; static;
+    class function IsOne(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class function IsOne64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); overload; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32); overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32; overload; static;
+    class function Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64; static;
+    class function MulWordAddExt(AX: UInt32; const AYy: TCryptoLibUInt32Array; AYyOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32; static;
+    class function Mul33DWordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; overload; static;
+    class function Mul33WordAdd(AX: UInt32; AY: UInt32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; overload; static;
+    class function MulWordDwordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32); overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+    class function SubBothFrom(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+    class function ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger; static;
+    class function ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger; static;
+    class procedure Zero(AZ: TCryptoLibUInt32Array); static;
   end;
 
 implementation
 
-{ TNat192 }
-
-class function TNat192.Add(const x, y, z: TCryptoLibUInt32Array): UInt32;
+class function TNat192.Add(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[0]) + y[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[1]) + y[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[2]) + y[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[3]) + y[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[4]) + y[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[5]) + y[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AY[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[5]) + AY[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat192.AddBothTo(const x, y, z: TCryptoLibUInt32Array): UInt32;
+class function TNat192.AddBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[0]) + y[0] + z[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[1]) + y[1] + z[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[2]) + y[2] + z[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[3]) + y[3] + z[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[4]) + y[4] + z[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[5]) + y[5] + z[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0] + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1] + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2] + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3] + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AY[4] + AZ[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[5]) + AY[5] + AZ[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat192.AddTo(const x, z: TCryptoLibUInt32Array): UInt32;
+class function TNat192.AddTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[0]) + z[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[1]) + z[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[2]) + z[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[3]) + z[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[4]) + z[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[5]) + z[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AZ[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[5]) + AZ[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat192.AddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32; cIn: UInt32): UInt32;
+class function TNat192.AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: UInt32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := cIn;
-  c := c + (UInt64(x[xOff + 0]) + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 1]) + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 2]) + z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 3]) + z[zOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 4]) + z[zOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 5]) + z[zOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := ACIn;
+  LC := LC + UInt64(AX[AXOff + 0]) + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 1]) + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 2]) + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 3]) + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 4]) + AZ[AZOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 5]) + AZ[AZOff + 5];
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat192.AddToEachOther(const u: TCryptoLibUInt32Array;
-  uOff: Int32; const v: TCryptoLibUInt32Array; vOff: Int32): UInt32;
+class function TNat192.AddToEachOther(AU: TCryptoLibUInt32Array; AUOff: Int32; AV: TCryptoLibUInt32Array; AVOff: Int32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(u[uOff + 0]) + v[vOff + 0]);
-  u[uOff + 0] := UInt32(c);
-  v[vOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 1]) + v[vOff + 1]);
-  u[uOff + 1] := UInt32(c);
-  v[vOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 2]) + v[vOff + 2]);
-  u[uOff + 2] := UInt32(c);
-  v[vOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 3]) + v[vOff + 3]);
-  u[uOff + 3] := UInt32(c);
-  v[vOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 4]) + v[vOff + 4]);
-  u[uOff + 4] := UInt32(c);
-  v[vOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 5]) + v[vOff + 5]);
-  u[uOff + 5] := UInt32(c);
-  v[vOff + 5] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + UInt64(AU[AUOff + 0]) + AV[AVOff + 0];
+  AU[AUOff + 0] := UInt32(LC);
+  AV[AVOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 1]) + AV[AVOff + 1];
+  AU[AUOff + 1] := UInt32(LC);
+  AV[AVOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 2]) + AV[AVOff + 2];
+  AU[AUOff + 2] := UInt32(LC);
+  AV[AVOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 3]) + AV[AVOff + 3];
+  AU[AUOff + 3] := UInt32(LC);
+  AV[AVOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 4]) + AV[AVOff + 4];
+  AU[AUOff + 4] := UInt32(LC);
+  AV[AVOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 5]) + AV[AVOff + 5];
+  AU[AUOff + 5] := UInt32(LC);
+  AV[AVOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class procedure TNat192.Copy(const x, z: TCryptoLibUInt32Array);
+class procedure TNat192.Copy(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array);
 begin
-  System.Move(x[0], z[0], 6 * System.SizeOf(UInt32));
+  System.Move(AX[0], AZ[0], 6 * System.SizeOf(UInt32));
 end;
 
-class procedure TNat192.Copy(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32);
+class procedure TNat192.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
 begin
-  System.Move(x[xOff], z[zOff], 6 * System.SizeOf(UInt32));
+  System.Move(AX[AXOff], AZ[AZOff], 6 * System.SizeOf(UInt32));
 end;
 
-class procedure TNat192.Copy64(const x, z: TCryptoLibUInt64Array);
+class procedure TNat192.Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
 begin
-  System.Move(x[0], z[0], 3 * System.SizeOf(UInt64));
+  AZ[0] := AX[0];
+  AZ[1] := AX[1];
+  AZ[2] := AX[2];
 end;
 
-class procedure TNat192.Copy64(const x: TCryptoLibUInt64Array; xOff: Int32;
-  const z: TCryptoLibUInt64Array; zOff: Int32);
+class procedure TNat192.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
 begin
-  System.Move(x[xOff], z[zOff], 3 * System.SizeOf(UInt64));
+  System.Move(AX[AXOff], AZ[AZOff], 3 * System.SizeOf(UInt64));
 end;
 
-class function TNat192.Create: TCryptoLibUInt32Array;
+class function TNat192.Create(): TCryptoLibUInt32Array;
 begin
-  System.SetLength(result, 6);
+  SetLength(Result, 6);
+  Exit;
 end;
 
-class function TNat192.Create64: TCryptoLibUInt64Array;
+class function TNat192.Create64(): TCryptoLibUInt64Array;
 begin
-  System.SetLength(result, 3);
+  SetLength(Result, 3);
+  Exit;
 end;
 
-class function TNat192.CreateExt: TCryptoLibUInt32Array;
+class function TNat192.CreateExt(): TCryptoLibUInt32Array;
 begin
-  System.SetLength(result, 12);
+  SetLength(Result, 12);
+  Exit;
 end;
 
-class function TNat192.CreateExt64: TCryptoLibUInt64Array;
+class function TNat192.CreateExt64(): TCryptoLibUInt64Array;
 begin
-  System.SetLength(result, 6);
+  SetLength(Result, 6);
+  Exit;
 end;
 
-class function TNat192.Diff(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const z: TCryptoLibUInt32Array;
-  zOff: Int32): Boolean;
+class function TNat192.Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean;
 var
-  pos: Boolean;
+  LPos: Boolean;
 begin
-  pos := Gte(x, xOff, y, yOff);
-  if (pos) then
-  begin
-    Sub(x, xOff, y, yOff, z, zOff);
-  end
+  LPos := Gte(AX, AXOff, AY, AYOff);
+  if LPos then
+  Sub(AX, AXOff, AY, AYOff, AZ, AZOff)
   else
-  begin
-    Sub(y, yOff, x, xOff, z, zOff);
-  end;
-  result := pos;
+  Sub(AY, AYOff, AX, AXOff, AZ, AZOff);
+  Result := LPos;
 end;
 
-class function TNat192.Eq(const x, y: TCryptoLibUInt32Array): Boolean;
+class function TNat192.Eq(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 5;
-  while i >= 0 do
+  for LI := 5 downto 0 do
   begin
-    if (x[i] <> y[i]) then
+    if AX[LI] <> AY[LI] then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat192.Eq64(const x, y: TCryptoLibUInt64Array): Boolean;
+class function TNat192.Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 2;
-  while i >= 0 do
+  for LI := 2 downto 0 do
   begin
-    if (x[i] <> y[i]) then
+    if AX[LI] <> AY[LI] then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat192.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
+class function TNat192.GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32;
 var
-  i: Int32;
-  Lx: TBigInteger;
+  LW: Int32;
+  LB: Int32;
 begin
-  Lx := x;
-  if ((Lx.SignValue < 0) or (Lx.BitLength > 192)) then
+  if ABit = 0 then
   begin
-    raise EArgumentCryptoLibException.Create('');
-  end;
-
-  result := Create();
-  i := 0;
-  while (Lx.SignValue <> 0) do
-  begin
-    result[i] := UInt32(Lx.Int32Value);
-    System.Inc(i);
-    Lx := Lx.ShiftRight(32);
-  end;
-end;
-
-class function TNat192.FromBigInteger64(const x: TBigInteger)
-  : TCryptoLibUInt64Array;
-var
-  i: Int32;
-  Lx: TBigInteger;
-begin
-  Lx := x;
-  if ((Lx.SignValue < 0) or (Lx.BitLength > 192)) then
-  begin
-    raise EArgumentCryptoLibException.Create('');
-  end;
-
-  result := Create64();
-  i := 0;
-  while (Lx.SignValue <> 0) do
-  begin
-    result[i] := UInt64(Lx.Int64Value);
-    System.Inc(i);
-    Lx := Lx.ShiftRight(64);
-  end;
-end;
-
-class function TNat192.GetBit(const x: TCryptoLibUInt32Array;
-  bit: Int32): UInt32;
-var
-  w, b: Int32;
-begin
-  if (bit = 0) then
-  begin
-    result := x[0] and 1;
+    Result := AX[0] and 1;
     Exit;
   end;
-  w := TBitUtilities.Asr32(bit, 5);
-  if ((w < 0) or (w >= 6)) then
+  LW := TBitUtilities.Asr32(ABit, 5);
+  if (LW < 0) or (LW >= 6) then
   begin
-    result := 0;
+    Result := 0;
     Exit;
   end;
-  b := bit and 31;
-  result := (x[w] shr b) and 1;
+  LB := ABit and 31;
+  Result := (AX[LW] shr LB) and 1;
 end;
 
-class function TNat192.Gte(const x, y: TCryptoLibUInt32Array): Boolean;
+class function TNat192.Gte(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
-  x_i, y_i: UInt32;
+  LI: Int32;
+  LXI: UInt32;
+  LYI: UInt32;
 begin
-  i := 5;
-  while i >= 0 do
+  for LI := 5 downto 0 do
   begin
-    x_i := x[i];
-    y_i := y[i];
-
-    if (x_i < y_i) then
+    LXI := AX[LI];
+    LYI := AY[LI];
+    if LXI < LYI then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-
-    if (x_i > y_i) then
+    if LXI > LYI then
     begin
-      result := true;
+      Result := True;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat192.Gte(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32): Boolean;
+class function TNat192.Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean;
 var
-  i: Int32;
-  x_i, y_i: UInt32;
+  LI: Int32;
+  LXI: UInt32;
+  LYI: UInt32;
 begin
-  i := 5;
-  while i >= 0 do
+  for LI := 5 downto 0 do
   begin
-    x_i := x[xOff + i];
-    y_i := y[yOff + i];
-
-    if (x_i < y_i) then
+    LXI := AX[AXOff + LI];
+    LYI := AY[AYOff + LI];
+    if LXI < LYI then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-
-    if (x_i > y_i) then
+    if LXI > LYI then
     begin
-      result := true;
+      Result := True;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat192.IsOne(const x: TCryptoLibUInt32Array): Boolean;
+class function TNat192.IsOne(const AX: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  if (x[0] <> 1) then
+  if AX[0] <> 1 then
   begin
-    result := false;
+    Result := False;
     Exit;
   end;
-
-  i := 1;
-  while i < 6 do
+  for LI := 1 to (6) - 1 do
   begin
-    if (x[i] <> 0) then
+    if AX[LI] <> 0 then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat192.IsOne64(const x: TCryptoLibUInt64Array): Boolean;
+class function TNat192.IsOne64(const AX: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  if (x[0] <> UInt64(1)) then
+  if AX[0] <> UInt64(1) then
   begin
-    result := false;
+    Result := False;
     Exit;
   end;
-
-  i := 1;
-  while i < 3 do
-  begin
-    if (x[i] <> UInt64(0)) then
-    begin
-      result := false;
-      Exit;
-    end;
-    System.Inc(i);
-  end;
-  result := true;
-end;
-
-class function TNat192.IsZero(const x: TCryptoLibUInt32Array): Boolean;
-var
-  i: Int32;
-begin
-  i := 0;
-  while i < 6 do
+  for LI := 1 to (3) - 1 do
   begin
-    if (x[i] <> 0) then
+    if AX[LI] <> UInt64(0) then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat192.IsZero64(const x: TCryptoLibUInt64Array): Boolean;
+class function TNat192.IsZero(const AX: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 0;
-  while i < 3 do
+  for LI := 0 to (6) - 1 do
   begin
-    if (x[i] <> UInt64(0)) then
+    if AX[LI] <> 0 then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class procedure TNat192.Mul(const x, y, zz: TCryptoLibUInt32Array);
+class procedure TNat192.Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  c, x_0, x_i, y_0, y_1, y_2, y_3, y_4, y_5: UInt64;
-  i: Int32;
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LC: UInt64;
+  LX0: UInt64;
+  LI: Int32;
+  LXI: UInt64;
 begin
-  y_0 := y[0];
-  y_1 := y[1];
-  y_2 := y[2];
-  y_3 := y[3];
-  y_4 := y[4];
-  y_5 := y[5];
-
-  c := 0;
-  x_0 := x[0];
-  c := c + (x_0 * y_0);
-  zz[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_1);
-  zz[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_2);
-  zz[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_3);
-  zz[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_4);
-  zz[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_5);
-  zz[5] := UInt32(c);
-  c := c shr 32;
-  zz[6] := UInt32(c);
-
-  for i := 1 to System.Pred(6) do
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+  LY4 := AY[4];
+  LY5 := AY[5];
+  LC := 0;
+  LX0 := AX[0];
+  LC := LC + (LX0 * LY0);
+  AZz[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY1);
+  AZz[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY2);
+  AZz[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY3);
+  AZz[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY4);
+  AZz[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY5);
+  AZz[5] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[6] := UInt32(LC);
+  for LI := 1 to (6) - 1 do
   begin
-    c := 0;
-    x_i := x[i];
-    c := c + (x_i * y_0 + zz[i + 0]);
-    zz[i + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[i + 1]);
-    zz[i + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[i + 2]);
-    zz[i + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[i + 3]);
-    zz[i + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[i + 4]);
-    zz[i + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[i + 5]);
-    zz[i + 5] := UInt32(c);
-    c := c shr 32;
-    zz[i + 6] := UInt32(c);
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + (LXI * LY0 + AZz[LI + 0]);
+    AZz[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[LI + 1]);
+    AZz[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[LI + 2]);
+    AZz[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[LI + 3]);
+    AZz[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[LI + 4]);
+    AZz[LI + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[LI + 5]);
+    AZz[LI + 5] := UInt32(LC);
+    LC := LC shr 32;
+    AZz[LI + 6] := UInt32(LC);
   end;
 end;
 
-class procedure TNat192.Mul(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const zz: TCryptoLibUInt32Array;
-  zzOff: Int32);
+class procedure TNat192.Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32);
 var
-  c, x_0, x_i, y_0, y_1, y_2, y_3, y_4, y_5: UInt64;
-  i: Int32;
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LC: UInt64;
+  LX0: UInt64;
+  LI: Int32;
+  LXI: UInt64;
 begin
-  y_0 := y[yOff + 0];
-  y_1 := y[yOff + 1];
-  y_2 := y[yOff + 2];
-  y_3 := y[yOff + 3];
-  y_4 := y[yOff + 4];
-  y_5 := y[yOff + 5];
-
-  c := 0;
-  x_0 := x[xOff + 0];
-  c := c + (x_0 * y_0);
-  zz[zzOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_1);
-  zz[zzOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_2);
-  zz[zzOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_3);
-  zz[zzOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_4);
-  zz[zzOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_5);
-  zz[zzOff + 5] := UInt32(c);
-  c := c shr 32;
-  zz[zzOff + 6] := UInt32(c);
-
-  for i := 1 to System.Pred(6) do
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+  LY4 := AY[AYOff + 4];
+  LY5 := AY[AYOff + 5];
+  LC := 0;
+  LX0 := AX[AXOff + 0];
+  LC := LC + (LX0 * LY0);
+  AZz[AZzOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY1);
+  AZz[AZzOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY2);
+  AZz[AZzOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY3);
+  AZz[AZzOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY4);
+  AZz[AZzOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY5);
+  AZz[AZzOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[AZzOff + 6] := UInt32(LC);
+  for LI := 1 to (6) - 1 do
   begin
-    System.Inc(zzOff);
-    c := 0;
-    x_i := x[xOff + i];
-    c := c + (x_i * y_0 + zz[zzOff + 0]);
-    zz[zzOff + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[zzOff + 1]);
-    zz[zzOff + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[zzOff + 2]);
-    zz[zzOff + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[zzOff + 3]);
-    zz[zzOff + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[zzOff + 4]);
-    zz[zzOff + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[zzOff + 5]);
-    zz[zzOff + 5] := UInt32(c);
-    c := c shr 32;
-    zz[zzOff + 6] := UInt32(c);
+    Inc(AZzOff);
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + (LXI * LY0 + AZz[AZzOff + 0]);
+    AZz[AZzOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[AZzOff + 1]);
+    AZz[AZzOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[AZzOff + 2]);
+    AZz[AZzOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[AZzOff + 3]);
+    AZz[AZzOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[AZzOff + 4]);
+    AZz[AZzOff + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[AZzOff + 5]);
+    AZz[AZzOff + 5] := UInt32(LC);
+    LC := LC shr 32;
+    AZz[AZzOff + 6] := UInt32(LC);
   end;
 end;
 
-class function TNat192.MulAddTo(const x, y, zz: TCryptoLibUInt32Array): UInt32;
+class function TNat192.MulAddTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array): UInt32;
 var
-  c, x_i, y_0, y_1, y_2, y_3, y_4, y_5, zc: UInt64;
-  i: Int32;
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LZc: UInt64;
+  LI: Int32;
+  LC: UInt64;
+  LXI: UInt64;
 begin
-  y_0 := y[0];
-  y_1 := y[1];
-  y_2 := y[2];
-  y_3 := y[3];
-  y_4 := y[4];
-  y_5 := y[5];
-
-  zc := 0;
-  for i := 0 to System.Pred(6) do
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+  LY4 := AY[4];
+  LY5 := AY[5];
+  LZc := 0;
+  for LI := 0 to (6) - 1 do
   begin
-    c := 0;
-    x_i := x[i];
-    c := c + (x_i * y_0 + zz[i + 0]);
-    zz[i + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[i + 1]);
-    zz[i + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[i + 2]);
-    zz[i + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[i + 3]);
-    zz[i + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[i + 4]);
-    zz[i + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[i + 5]);
-    zz[i + 5] := UInt32(c);
-    c := c shr 32;
-    zc := zc + (c + (zz[i + 6] and M));
-    zz[i + 6] := UInt32(zc);
-    zc := zc shr 32;
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + (LXI * LY0 + AZz[LI + 0]);
+    AZz[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[LI + 1]);
+    AZz[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[LI + 2]);
+    AZz[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[LI + 3]);
+    AZz[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[LI + 4]);
+    AZz[LI + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[LI + 5]);
+    AZz[LI + 5] := UInt32(LC);
+    LC := LC shr 32;
+    LZc := LZc + (LC + AZz[LI + 6]);
+    AZz[LI + 6] := UInt32(LZc);
+    LZc := LZc shr 32;
   end;
-  result := UInt32(zc);
+  Result := UInt32(LZc);
 end;
 
-class function TNat192.MulAddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const zz: TCryptoLibUInt32Array;
-  zzOff: Int32): UInt32;
+class function TNat192.MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32;
 var
-  c, x_i, y_0, y_1, y_2, y_3, y_4, y_5, zc: UInt64;
-  i: Int32;
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LZc: UInt64;
+  LI: Int32;
+  LC: UInt64;
+  LXI: UInt64;
 begin
-  y_0 := y[yOff + 0];
-  y_1 := y[yOff + 1];
-  y_2 := y[yOff + 2];
-  y_3 := y[yOff + 3];
-  y_4 := y[yOff + 4];
-  y_5 := y[yOff + 5];
-
-  zc := 0;
-  for i := 0 to System.Pred(6) do
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+  LY4 := AY[AYOff + 4];
+  LY5 := AY[AYOff + 5];
+  LZc := 0;
+  for LI := 0 to (6) - 1 do
   begin
-    c := 0;
-    x_i := x[xOff + i];
-    c := c + (x_i * y_0 + zz[zzOff + 0]);
-    zz[zzOff + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[zzOff + 1]);
-    zz[zzOff + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[zzOff + 2]);
-    zz[zzOff + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[zzOff + 3]);
-    zz[zzOff + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[zzOff + 4]);
-    zz[zzOff + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[zzOff + 5]);
-    zz[zzOff + 5] := UInt32(c);
-    c := c shr 32;
-    zc := zc + (c + (zz[zzOff + 6] and M));
-    zz[zzOff + 6] := UInt32(zc);
-    zc := zc shr 32;
-    System.Inc(zzOff);
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + (LXI * LY0 + AZz[AZzOff + 0]);
+    AZz[AZzOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[AZzOff + 1]);
+    AZz[AZzOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[AZzOff + 2]);
+    AZz[AZzOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[AZzOff + 3]);
+    AZz[AZzOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[AZzOff + 4]);
+    AZz[AZzOff + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[AZzOff + 5]);
+    AZz[AZzOff + 5] := UInt32(LC);
+    LC := LC shr 32;
+    LZc := LZc + (LC + AZz[AZzOff + 6]);
+    AZz[AZzOff + 6] := UInt32(LZc);
+    LZc := LZc shr 32;
+    Inc(AZzOff);
   end;
-  result := UInt32(zc);
+  Result := UInt32(LZc);
 end;
 
-class function TNat192.Mul33Add(w: UInt32; const x: TCryptoLibUInt32Array;
-  xOff: Int32; const y: TCryptoLibUInt32Array; yOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt64;
+class function TNat192.Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64;
 var
-  c, wVal, x0, x1, x2, x3, x4, x5: UInt64;
+  LC: UInt64;
+  LWVal: UInt64;
+  LX0: UInt64;
+  LX1: UInt64;
+  LX2: UInt64;
+  LX3: UInt64;
+  LX4: UInt64;
+  LX5: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(w shr 31 = 0);
-{$ENDIF DEBUG}
-  c := 0;
-  wVal := w;
-  x0 := x[xOff + 0];
-  c := c + (wVal * x0 + y[yOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  x1 := x[xOff + 1];
-  c := c + (wVal * x1 + x0 + y[yOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  x2 := x[xOff + 2];
-  c := c + (wVal * x2 + x1 + y[yOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  x3 := x[xOff + 3];
-  c := c + (wVal * x3 + x2 + y[yOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  x4 := x[xOff + 4];
-  c := c + (wVal * x4 + x3 + y[yOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  x5 := x[xOff + 5];
-  c := c + (wVal * x5 + x4 + y[yOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + x5;
-  result := c;
+  {$IFDEF DEBUG}
+  System.Assert(AW shr 31 = 0);
+  {$ENDIF}
+  LC := 0;
+  LWVal := AW;
+  LX0 := AX[AXOff + 0];
+  LC := LC + (LWVal * LX0 + AY[AYOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LX1 := AX[AXOff + 1];
+  LC := LC + (LWVal * LX1 + LX0 + AY[AYOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LX2 := AX[AXOff + 2];
+  LC := LC + (LWVal * LX2 + LX1 + AY[AYOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LX3 := AX[AXOff + 3];
+  LC := LC + (LWVal * LX3 + LX2 + AY[AYOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LX4 := AX[AXOff + 4];
+  LC := LC + (LWVal * LX4 + LX3 + AY[AYOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LX5 := AX[AXOff + 5];
+  LC := LC + (LWVal * LX5 + LX4 + AY[AYOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX5);
+  Result := LC;
 end;
 
-class function TNat192.MulWordAddExt(x: UInt32; const yy: TCryptoLibUInt32Array;
-  yyOff: Int32; const zz: TCryptoLibUInt32Array; zzOff: Int32): UInt32;
+class function TNat192.MulWordAddExt(AX: UInt32; const AYy: TCryptoLibUInt32Array; AYyOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32;
 var
-  c, xVal: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(yyOff <= 6);
-  System.Assert(zzOff <= 6);
-{$ENDIF DEBUG}
-  c := 0;
-  xVal := x;
-  c := c + (xVal * yy[yyOff + 0] + zz[zzOff + 0]);
-  zz[zzOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * yy[yyOff + 1] + zz[zzOff + 1]);
-  zz[zzOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * yy[yyOff + 2] + zz[zzOff + 2]);
-  zz[zzOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * yy[yyOff + 3] + zz[zzOff + 3]);
-  zz[zzOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * yy[yyOff + 4] + zz[zzOff + 4]);
-  zz[zzOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * yy[yyOff + 5] + zz[zzOff + 5]);
-  zz[zzOff + 5] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  {$IFDEF DEBUG}
+  System.Assert(AYyOff <= 6);
+  System.Assert(AZzOff <= 6);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * AYy[AYyOff + 0] + AZz[AZzOff + 0]);
+  AZz[AZzOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AYy[AYyOff + 1] + AZz[AZzOff + 1]);
+  AZz[AZzOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AYy[AYyOff + 2] + AZz[AZzOff + 2]);
+  AZz[AZzOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AYy[AYyOff + 3] + AZz[AZzOff + 3]);
+  AZz[AZzOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AYy[AYyOff + 4] + AZz[AZzOff + 4]);
+  AZz[AZzOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AYy[AYyOff + 5] + AZz[AZzOff + 5]);
+  AZz[AZzOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat192.Mul33DWordAdd(x: UInt32; y: UInt64;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat192.Mul33DWordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal, y00, y01: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
+  LY00: UInt64;
+  LY01: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(x shr 31 = 0);
-  System.Assert(zOff <= 2);
-{$ENDIF DEBUG}
-  c := 0;
-  xVal := x;
-  y00 := y and M;
-  c := c + (xVal * y00 + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  y01 := y shr 32;
-  c := c + (xVal * y01 + y00 + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (y01 + z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (z[zOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  if c = 0 then
-  begin
-    result := 0;
-  end
+  {$IFDEF DEBUG}
+  System.Assert(AX shr 31 = 0);
+  System.Assert(AZOff <= 2);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LY00 := AY and M;
+  LC := LC + (LXVal * LY00 + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LY01 := AY shr 32;
+  LC := LC + (LXVal * LY01 + LY00 + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY01 + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  if LC = 0 then
+    Result := 0
   else
-  begin
-    result := TNat.IncAt(6, z, zOff, 4);
-  end;
+    Result := TNat.IncAt(6, AZ, AZOff, 4);
 end;
 
-class function TNat192.Mul33WordAdd(x, y: UInt32;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat192.Mul33WordAdd(AX: UInt32; AY: UInt32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, yVal: UInt64;
+  LC: UInt64;
+  LYVal: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(x shr 31 = 0);
-  System.Assert(zOff <= 3);
-{$ENDIF DEBUG}
-  c := 0;
-  yVal := y;
-  c := c + (yVal * x + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (yVal + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  if c = 0 then
-  begin
-    result := 0;
-  end
+  {$IFDEF DEBUG}
+  System.Assert(AX shr 31 = 0);
+  System.Assert(AZOff <= 3);
+  {$ENDIF}
+  LC := 0;
+  LYVal := AY;
+  LC := LC + (LYVal * AX + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LYVal + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  if LC = 0 then
+    Result := 0
   else
-  begin
-    result := TNat.IncAt(6, z, zOff, 3);
-  end;
+    Result := TNat.IncAt(6, AZ, AZOff, 3);
 end;
 
-class function TNat192.MulWordDwordAdd(x: UInt32; y: UInt64;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat192.MulWordDwordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(zOff <= 3);
-{$ENDIF DEBUG}
-  c := 0;
-  xVal := x;
-  c := c + (xVal * y + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * (y shr 32) + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  if c = 0 then
-  begin
-    result := 0;
-  end
+  {$IFDEF DEBUG}
+  System.Assert(AZOff <= 3);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * AY + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * (AY shr 32) + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  if LC = 0 then
+    Result := 0
   else
-  begin
-    result := TNat.IncAt(6, z, zOff, 3);
-  end;
+    Result := TNat.IncAt(6, AZ, AZOff, 3);
 end;
 
-class function TNat192.MulWord(x: UInt32; const y, z: TCryptoLibUInt32Array;
-  zOff: Int32): UInt32;
+class function TNat192.MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal: UInt64;
-  i: Int32;
+  LC: UInt64;
+  LXVal: UInt64;
+  LI: Int32;
 begin
-  c := 0;
-  xVal := x;
-  i := 0;
+  LC := 0;
+  LXVal := AX;
+  LI := 0;
   repeat
-    c := c + (xVal * y[i]);
-    z[zOff + i] := UInt32(c);
-    c := c shr 32;
-    System.Inc(i);
-  until not(i < 6);
-  result := UInt32(c);
+    LC := LC + (LXVal * AY[LI]);
+    AZ[AZOff + LI] := UInt32(LC);
+    LC := LC shr 32;
+    Inc(LI);
+  until not (LI < 6);
+  Result := UInt32(LC);
 end;
 
-class procedure TNat192.Square(const x, zz: TCryptoLibUInt32Array);
+class procedure TNat192.Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  x_0, zz_1, xVal, p, x_1, zz_2, x_2, zz_3, zz_4, x_3, zz_5, zz_6, x_4, zz_7,
-    zz_8, x_5, zz_9, zz_10: UInt64;
-  c, w: UInt32;
-  i, j: Int32;
+  LX0: UInt64;
+  LZz1: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI: Int32;
+  LJ: Int32;
+  LXVal: UInt64;
+  LP: UInt64;
+  LX1: UInt64;
+  LZz2: UInt64;
+  LX2: UInt64;
+  LZz3: UInt64;
+  LZz4: UInt64;
+  LX3: UInt64;
+  LZz5: UInt64;
+  LZz6: UInt64;
+  LX4: UInt64;
+  LZz7: UInt64;
+  LZz8: UInt64;
+  LX5: UInt64;
+  LZz9: UInt64;
+  LZz10: UInt64;
 begin
-  x_0 := x[0];
-  c := 0;
-  i := 5;
-  j := 12;
-
+  LX0 := AX[0];
+  LC := 0;
+  LI := 5;
+  LJ := 12;
   repeat
-    xVal := x[i];
-    System.Dec(i);
-    p := xVal * xVal;
-    System.Dec(j);
-    zz[j] := (c shl 31) or UInt32(p shr 33);
-    System.Dec(j);
-    zz[j] := UInt32(p shr 1);
-    c := UInt32(p);
-  until not(i > 0);
-
-  p := x_0 * x_0;
-  zz_1 := UInt64(c shl 31) or (p shr 33);
-  zz[0] := UInt32(p);
-  c := UInt32(p shr 32) and 1;
-
-  x_1 := x[1];
-  zz_2 := zz[2];
-
-  zz_1 := zz_1 + (x_1 * x_0);
-  w := UInt32(zz_1);
-  zz[1] := (w shl 1) or c;
-  c := w shr 31;
-  zz_2 := zz_2 + (zz_1 shr 32);
-
-  x_2 := x[2];
-  zz_3 := zz[3];
-  zz_4 := zz[4];
-
-  zz_2 := zz_2 + (x_2 * x_0);
-  w := UInt32(zz_2);
-  zz[2] := (w shl 1) or c;
-  c := w shr 31;
-  zz_3 := zz_3 + ((zz_2 shr 32) + x_2 * x_1);
-  zz_4 := zz_4 + (zz_3 shr 32);
-  zz_3 := zz_3 and M;
-
-  x_3 := x[3];
-  zz_5 := zz[5] + (zz_4 shr 32);
-  zz_4 := zz_4 and M;
-  zz_6 := zz[6] + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  zz_3 := zz_3 + (x_3 * x_0);
-  w := UInt32(zz_3);
-  zz[3] := (w shl 1) or c;
-  c := w shr 31;
-  zz_4 := zz_4 + ((zz_3 shr 32) + x_3 * x_1);
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_3 * x_2);
-  zz_4 := zz_4 and M;
-  zz_6 := zz_6 + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  x_4 := x[4];
-  zz_7 := zz[7] + (zz_6 shr 32);
-  zz_6 := zz_6 and M;
-  zz_8 := zz[8] + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  zz_4 := zz_4 + (x_4 * x_0);
-  w := UInt32(zz_4);
-  zz[4] := (w shl 1) or c;
-  c := w shr 31;
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_4 * x_1);
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_4 * x_2);
-  zz_5 := zz_5 and M;
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_4 * x_3);
-  zz_6 := zz_6 and M;
-  zz_8 := zz_8 + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  x_5 := x[5];
-  zz_9 := zz[9] + (zz_8 shr 32);
-  zz_8 := zz_8 and M;
-  zz_10 := zz[10] + (zz_9 shr 32);
-  zz_9 := zz_9 and M;
-
-  zz_5 := zz_5 + (x_5 * x_0);
-  w := UInt32(zz_5);
-  zz[5] := (w shl 1) or c;
-  c := w shr 31;
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_5 * x_1);
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_5 * x_2);
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_5 * x_3);
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_5 * x_4);
-  zz_10 := zz_10 + (zz_9 shr 32);
-
-  w := UInt32(zz_6);
-  zz[6] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_7);
-  zz[7] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_8);
-  zz[8] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_9);
-  zz[9] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_10);
-  zz[10] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := zz[11] + UInt32(zz_10 shr 32);
-  zz[11] := (w shl 1) or c;
+    LXVal := AX[LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZz[LJ] := (LC shl 31) or UInt32((LP ) shr 33);
+    Dec(LJ);
+    AZz[LJ] := UInt32((LP ) shr 1);
+    LC := UInt32(LP);
+  until not (LI > 0);
+  LP := LX0 * LX0;
+  LZz1 := UInt64((LC ) shl 31) or (LP shr 33);
+  AZz[0] := UInt32(LP);
+  LC := UInt32((LP ) shr 32) and 1;
+  LX1 := AX[1];
+  LZz2 := AZz[2];
+  LZz1 := LZz1 + (LX1 * LX0);
+  LW := UInt32(LZz1);
+  AZz[1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz2 := LZz2 + (LZz1 shr 32);
+  LX2 := AX[2];
+  LZz3 := AZz[3];
+  LZz4 := AZz[4];
+  LZz2 := LZz2 + (LX2 * LX0);
+  LW := UInt32(LZz2);
+  AZz[2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz3 := LZz3 + ((LZz2 shr 32) + LX2 * LX1);
+  LZz4 := LZz4 + (LZz3 shr 32);
+  LZz3 := LZz3 and M;
+  LX3 := AX[3];
+  LZz5 := AZz[5] + (LZz4 shr 32);
+  LZz4 := LZz4 and M;
+  LZz6 := AZz[6] + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LZz3 := LZz3 + (LX3 * LX0);
+  LW := UInt32(LZz3);
+  AZz[3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz4 := LZz4 + ((LZz3 shr 32) + LX3 * LX1);
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX3 * LX2);
+  LZz4 := LZz4 and M;
+  LZz6 := LZz6 + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LX4 := AX[4];
+  LZz7 := AZz[7] + (LZz6 shr 32);
+  LZz6 := LZz6 and M;
+  LZz8 := AZz[8] + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LZz4 := LZz4 + (LX4 * LX0);
+  LW := UInt32(LZz4);
+  AZz[4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX4 * LX1);
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX4 * LX2);
+  LZz5 := LZz5 and M;
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX4 * LX3);
+  LZz6 := LZz6 and M;
+  LZz8 := LZz8 + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LX5 := AX[5];
+  LZz9 := AZz[9] + (LZz8 shr 32);
+  LZz8 := LZz8 and M;
+  LZz10 := AZz[10] + (LZz9 shr 32);
+  LZz9 := LZz9 and M;
+  LZz5 := LZz5 + (LX5 * LX0);
+  LW := UInt32(LZz5);
+  AZz[5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX5 * LX1);
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX5 * LX2);
+  LZz8 := LZz8 + ((LZz7 shr 32) + LX5 * LX3);
+  LZz9 := LZz9 + ((LZz8 shr 32) + LX5 * LX4);
+  LZz10 := LZz10 + (LZz9 shr 32);
+  LW := UInt32(LZz6);
+  AZz[6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz7);
+  AZz[7] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz8);
+  AZz[8] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz9);
+  AZz[9] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz10);
+  AZz[10] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := AZz[11] + UInt32((LZz10 ) shr 32);
+  AZz[11] := (LW shl 1) or LC;
 end;
 
-class procedure TNat192.Square(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const zz: TCryptoLibUInt32Array; zzOff: Int32);
+class procedure TNat192.Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32);
 var
-  x_0, zz_1, xVal, p, x_1, zz_2, x_2, zz_3, zz_4, x_3, zz_5, zz_6, x_4, zz_7,
-    zz_8, x_5, zz_9, zz_10: UInt64;
-  c, w: UInt32;
-  i, j: Int32;
+  LX0: UInt64;
+  LZz1: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI: Int32;
+  LJ: Int32;
+  LXVal: UInt64;
+  LP: UInt64;
+  LX1: UInt64;
+  LZz2: UInt64;
+  LX2: UInt64;
+  LZz3: UInt64;
+  LZz4: UInt64;
+  LX3: UInt64;
+  LZz5: UInt64;
+  LZz6: UInt64;
+  LX4: UInt64;
+  LZz7: UInt64;
+  LZz8: UInt64;
+  LX5: UInt64;
+  LZz9: UInt64;
+  LZz10: UInt64;
 begin
-  x_0 := x[xOff + 0];
-  c := 0;
-  i := 5;
-  j := 12;
-
+  LX0 := AX[AXOff + 0];
+  LC := 0;
+  LI := 5;
+  LJ := 12;
   repeat
-    xVal := x[xOff + i];
-    System.Dec(i);
-    p := xVal * xVal;
-    System.Dec(j);
-    zz[zzOff + j] := (c shl 31) or UInt32(p shr 33);
-    System.Dec(j);
-    zz[zzOff + j] := UInt32(p shr 1);
-    c := UInt32(p);
-  until not(i > 0);
-
-  p := x_0 * x_0;
-  zz_1 := UInt64(c shl 31) or (p shr 33);
-  zz[zzOff + 0] := UInt32(p);
-  c := UInt32(p shr 32) and 1;
-
-  x_1 := x[xOff + 1];
-  zz_2 := zz[zzOff + 2];
-
-  zz_1 := zz_1 + (x_1 * x_0);
-  w := UInt32(zz_1);
-  zz[zzOff + 1] := (w shl 1) or c;
-  c := w shr 31;
-  zz_2 := zz_2 + (zz_1 shr 32);
-
-  x_2 := x[xOff + 2];
-  zz_3 := zz[zzOff + 3];
-  zz_4 := zz[zzOff + 4];
-
-  zz_2 := zz_2 + (x_2 * x_0);
-  w := UInt32(zz_2);
-  zz[zzOff + 2] := (w shl 1) or c;
-  c := w shr 31;
-  zz_3 := zz_3 + ((zz_2 shr 32) + x_2 * x_1);
-  zz_4 := zz_4 + (zz_3 shr 32);
-  zz_3 := zz_3 and M;
-
-  x_3 := x[xOff + 3];
-  zz_5 := zz[zzOff + 5] + (zz_4 shr 32);
-  zz_4 := zz_4 and M;
-  zz_6 := zz[zzOff + 6] + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  zz_3 := zz_3 + (x_3 * x_0);
-  w := UInt32(zz_3);
-  zz[zzOff + 3] := (w shl 1) or c;
-  c := w shr 31;
-  zz_4 := zz_4 + ((zz_3 shr 32) + x_3 * x_1);
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_3 * x_2);
-  zz_4 := zz_4 and M;
-  zz_6 := zz_6 + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  x_4 := x[xOff + 4];
-  zz_7 := zz[zzOff + 7] + (zz_6 shr 32);
-  zz_6 := zz_6 and M;
-  zz_8 := zz[zzOff + 8] + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  zz_4 := zz_4 + (x_4 * x_0);
-  w := UInt32(zz_4);
-  zz[zzOff + 4] := (w shl 1) or c;
-  c := w shr 31;
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_4 * x_1);
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_4 * x_2);
-  zz_5 := zz_5 and M;
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_4 * x_3);
-  zz_6 := zz_6 and M;
-  zz_8 := zz_8 + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  x_5 := x[xOff + 5];
-  zz_9 := zz[zzOff + 9] + (zz_8 shr 32);
-  zz_8 := zz_8 and M;
-  zz_10 := zz[zzOff + 10] + (zz_9 shr 32);
-  zz_9 := zz_9 and M;
-
-  zz_5 := zz_5 + (x_5 * x_0);
-  w := UInt32(zz_5);
-  zz[zzOff + 5] := (w shl 1) or c;
-  c := w shr 31;
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_5 * x_1);
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_5 * x_2);
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_5 * x_3);
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_5 * x_4);
-  zz_10 := zz_10 + (zz_9 shr 32);
-
-  w := UInt32(zz_6);
-  zz[zzOff + 6] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_7);
-  zz[zzOff + 7] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_8);
-  zz[zzOff + 8] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_9);
-  zz[zzOff + 9] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := UInt32(zz_10);
-  zz[zzOff + 10] := (w shl 1) or c;
-  c := w shr 31;
-
-  w := zz[zzOff + 11] + UInt32(zz_10 shr 32);
-  zz[zzOff + 11] := (w shl 1) or c;
+    LXVal := AX[AXOff + LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZz[AZzOff + LJ] := (LC shl 31) or UInt32((LP ) shr 33);
+    Dec(LJ);
+    AZz[AZzOff + LJ] := UInt32((LP ) shr 1);
+    LC := UInt32(LP);
+  until not (LI > 0);
+  LP := LX0 * LX0;
+  LZz1 := UInt64((LC ) shl 31) or (LP shr 33);
+  AZz[AZzOff + 0] := UInt32(LP);
+  LC := UInt32((LP ) shr 32) and 1;
+  LX1 := AX[AXOff + 1];
+  LZz2 := AZz[AZzOff + 2];
+  LZz1 := LZz1 + (LX1 * LX0);
+  LW := UInt32(LZz1);
+  AZz[AZzOff + 1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz2 := LZz2 + (LZz1 shr 32);
+  LX2 := AX[AXOff + 2];
+  LZz3 := AZz[AZzOff + 3];
+  LZz4 := AZz[AZzOff + 4];
+  LZz2 := LZz2 + (LX2 * LX0);
+  LW := UInt32(LZz2);
+  AZz[AZzOff + 2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz3 := LZz3 + ((LZz2 shr 32) + LX2 * LX1);
+  LZz4 := LZz4 + (LZz3 shr 32);
+  LZz3 := LZz3 and M;
+  LX3 := AX[AXOff + 3];
+  LZz5 := AZz[AZzOff + 5] + (LZz4 shr 32);
+  LZz4 := LZz4 and M;
+  LZz6 := AZz[AZzOff + 6] + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LZz3 := LZz3 + (LX3 * LX0);
+  LW := UInt32(LZz3);
+  AZz[AZzOff + 3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz4 := LZz4 + ((LZz3 shr 32) + LX3 * LX1);
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX3 * LX2);
+  LZz4 := LZz4 and M;
+  LZz6 := LZz6 + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LX4 := AX[AXOff + 4];
+  LZz7 := AZz[AZzOff + 7] + (LZz6 shr 32);
+  LZz6 := LZz6 and M;
+  LZz8 := AZz[AZzOff + 8] + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LZz4 := LZz4 + (LX4 * LX0);
+  LW := UInt32(LZz4);
+  AZz[AZzOff + 4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX4 * LX1);
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX4 * LX2);
+  LZz5 := LZz5 and M;
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX4 * LX3);
+  LZz6 := LZz6 and M;
+  LZz8 := LZz8 + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LX5 := AX[AXOff + 5];
+  LZz9 := AZz[AZzOff + 9] + (LZz8 shr 32);
+  LZz8 := LZz8 and M;
+  LZz10 := AZz[AZzOff + 10] + (LZz9 shr 32);
+  LZz9 := LZz9 and M;
+  LZz5 := LZz5 + (LX5 * LX0);
+  LW := UInt32(LZz5);
+  AZz[AZzOff + 5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX5 * LX1);
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX5 * LX2);
+  LZz8 := LZz8 + ((LZz7 shr 32) + LX5 * LX3);
+  LZz9 := LZz9 + ((LZz8 shr 32) + LX5 * LX4);
+  LZz10 := LZz10 + (LZz9 shr 32);
+  LW := UInt32(LZz6);
+  AZz[AZzOff + 6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz7);
+  AZz[AZzOff + 7] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz8);
+  AZz[AZzOff + 8] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz9);
+  AZz[AZzOff + 9] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz10);
+  AZz[AZzOff + 10] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := AZz[AZzOff + 11] + UInt32((LZz10 ) shr 32);
+  AZz[AZzOff + 11] := (LW shl 1) or LC;
 end;
 
-class function TNat192.Sub(const x, y, z: TCryptoLibUInt32Array): Int32;
+class function TNat192.Sub(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(x[0]) - y[0]);
-  z[0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[1]) - y[1]);
-  z[1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[2]) - y[2]);
-  z[2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[3]) - y[3]);
-  z[3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[4]) - y[4]);
-  z[4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[5]) - y[5]);
-  z[5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AX[0]) - Int64(AY[0]));
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[1]) - Int64(AY[1]));
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[2]) - Int64(AY[2]));
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[3]) - Int64(AY[3]));
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[4]) - Int64(AY[4]));
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[5]) - Int64(AY[5]));
+  AZ[5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
 end;
 
-class function TNat192.Sub(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const z: TCryptoLibUInt32Array;
-  zOff: Int32): Int32;
+class function TNat192.Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(x[xOff + 0]) - y[yOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 1]) - y[yOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 2]) - y[yOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 3]) - y[yOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 4]) - y[yOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 5]) - y[yOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AX[AXOff + 0]) - Int64(AY[AYOff + 0]));
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 1]) - Int64(AY[AYOff + 1]));
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 2]) - Int64(AY[AYOff + 2]));
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 3]) - Int64(AY[AYOff + 3]));
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 4]) - Int64(AY[AYOff + 4]));
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 5]) - Int64(AY[AYOff + 5]));
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
 end;
 
-class function TNat192.SubBothFrom(const x, y, z: TCryptoLibUInt32Array): Int32;
+class function TNat192.SubBothFrom(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(z[0]) - x[0] - y[0]);
-  z[0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[1]) - x[1] - y[1]);
-  z[1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[2]) - x[2] - y[2]);
-  z[2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[3]) - x[3] - y[3]);
-  z[3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[4]) - x[4] - y[4]);
-  z[4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[5]) - x[5] - y[5]);
-  z[5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AZ[0]) - Int64(AX[0]) - Int64(AY[0]));
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[1]) - Int64(AX[1]) - Int64(AY[1]));
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[2]) - Int64(AX[2]) - Int64(AY[2]));
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[3]) - Int64(AX[3]) - Int64(AY[3]));
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[4]) - Int64(AX[4]) - Int64(AY[4]));
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[5]) - Int64(AX[5]) - Int64(AY[5]));
+  AZ[5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
 end;
 
-class function TNat192.SubFrom(const x, z: TCryptoLibUInt32Array): Int32;
+class function TNat192.SubFrom(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(z[0]) - x[0]);
-  z[0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[1]) - x[1]);
-  z[1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[2]) - x[2]);
-  z[2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[3]) - x[3]);
-  z[3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[4]) - x[4]);
-  z[4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[5]) - x[5]);
-  z[5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AZ[0]) - Int64(AX[0]));
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[1]) - Int64(AX[1]));
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[2]) - Int64(AX[2]));
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[3]) - Int64(AX[3]));
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[4]) - Int64(AX[4]));
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[5]) - Int64(AX[5]));
+  AZ[5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
 end;
 
-class function TNat192.SubFrom(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32): Int32;
+class function TNat192.SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(z[zOff + 0]) - x[xOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 1]) - x[xOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 2]) - x[xOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 3]) - x[xOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 4]) - x[xOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 5]) - x[xOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AZ[AZOff + 0]) - Int64(AX[AXOff + 0]));
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 1]) - Int64(AX[AXOff + 1]));
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 2]) - Int64(AX[AXOff + 2]));
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 3]) - Int64(AX[AXOff + 3]));
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 4]) - Int64(AX[AXOff + 4]));
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 5]) - Int64(AX[AXOff + 5]));
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
 end;
 
-class function TNat192.ToBigInteger(const x: TCryptoLibUInt32Array)
-  : TBigInteger;
+class function TNat192.ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger;
 var
-  bs, temp: TCryptoLibByteArray;
-  i: Int32;
-  x_i: UInt32;
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXI: UInt32;
 begin
-  System.SetLength(bs, 24);
-  for i := 0 to System.Pred(6) do
-
+  SetLength(LBs, 24);
+  for LI := 0 to (6) - 1 do
   begin
-    x_i := x[i];
-    if (x_i <> 0) then
-    begin
-      temp := TConverters.ReadUInt32AsBytesBE(x_i);
-      System.Move(temp[0], bs[(5 - i) shl 2], System.Length(temp) *
-        System.SizeOf(Byte))
-    end;
+    LXI := AX[LI];
+    if LXI <> 0 then
+    TPack.UInt32_To_BE(LXI, LBs, (5 - LI) shl 2);
   end;
-  result := TBigInteger.Create(1, bs);
+  Result := TBigInteger.Create(1, LBs);
 end;
 
-class function TNat192.ToBigInteger64(const x: TCryptoLibUInt64Array)
-  : TBigInteger;
+class function TNat192.ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger;
 var
-  bs, temp: TCryptoLibByteArray;
-  i: Int32;
-  x_i: UInt64;
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXI: UInt64;
 begin
-  System.SetLength(bs, 24);
-  for i := 0 to System.Pred(3) do
-
+  SetLength(LBs, 24);
+  for LI := 0 to (3) - 1 do
   begin
-    x_i := x[i];
-    if (x_i <> Int64(0)) then
-    begin
-      temp := TConverters.ReadUInt64AsBytesBE(x_i);
-      System.Move(temp[0], bs[(2 - i) shl 3], System.Length(temp) *
-        System.SizeOf(Byte))
-    end;
+    LXI := AX[LI];
+    if LXI <> Int64(0) then
+    TPack.UInt64_To_BE(LXI, LBs, (2 - LI) shl 3);
   end;
-  result := TBigInteger.Create(1, bs);
+  Result := TBigInteger.Create(1, LBs);
 end;
 
-class procedure TNat192.Zero(const z: TCryptoLibUInt32Array);
+class procedure TNat192.Zero(AZ: TCryptoLibUInt32Array);
 begin
-  TArrayUtilities.Fill<UInt32>(z, 0, 6, UInt32(0));
+  TArrayUtilities.Fill<UInt32>(AZ, 0, 6, UInt32(0));
 end;
 
 end.

+ 1407 - 0
CryptoLib/src/Math/Raw/ClpNat224.pas

@@ -0,0 +1,1407 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpNat224;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpNat,
+  ClpPack,
+  ClpBigInteger,
+  ClpArrayUtilities,
+  ClpBitUtilities,
+  ClpCryptoLibTypes;
+
+type
+  TNat224 = class sealed
+  strict private
+    const M: UInt64 = $FFFFFFFF;
+  public
+    class function Add(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function Add(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; overload; static;
+    class function AddBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function AddBothTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; ACIn: UInt32): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: UInt32): UInt32; overload; static;
+    class function AddToEachOther(AU: TCryptoLibUInt32Array; AUOff: Int32; AV: TCryptoLibUInt32Array; AVOff: Int32): UInt32; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+    class function Create(): TCryptoLibUInt32Array; static;
+    class function CreateExt(): TCryptoLibUInt32Array; static;
+    class function Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean; static;
+    class function Eq(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean; static;
+    class function GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean; overload; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean; overload; static;
+    class function IsOne(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); overload; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32); overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32; overload; static;
+    class function Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64; static;
+    class function MulByWord(AX: UInt32; AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function MulByWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function MulWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function Mul33DWordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function Mul33WordAdd(AX: UInt32; AY: UInt32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWordDwordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32); overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+    class function SubBothFrom(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+    class function ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger; static;
+    class procedure Zero(AZ: TCryptoLibUInt32Array); static;
+  end;
+
+implementation
+
+class function TNat224.Add(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AY[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[5]) + AY[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[6]) + AY[6];
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.Add(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[AXOff + 0]) + AY[AYOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 1]) + AY[AYOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 2]) + AY[AYOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 3]) + AY[AYOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 4]) + AY[AYOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 5]) + AY[AYOff + 5];
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 6]) + AY[AYOff + 6];
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.AddBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[0]) + AY[0] + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AY[1] + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AY[2] + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AY[3] + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AY[4] + AZ[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[5]) + AY[5] + AZ[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[6]) + AY[6] + AZ[6];
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.AddBothTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AX[AXOff + 0]) + AY[AYOff + 0] + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 1]) + AY[AYOff + 1] + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 2]) + AY[AYOff + 2] + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 3]) + AY[AYOff + 3] + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 4]) + AY[AYOff + 4] + AZ[AZOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 5]) + AY[AYOff + 5] + AZ[AZOff + 5];
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 6]) + AY[AYOff + 6] + AZ[AZOff + 6];
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.AddTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; ACIn: UInt32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := ACIn;
+  LC := LC + UInt64(AX[0]) + AZ[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[1]) + AZ[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[2]) + AZ[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[3]) + AZ[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[4]) + AZ[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[5]) + AZ[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[6]) + AZ[6];
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: UInt32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := ACIn;
+  LC := LC + UInt64(AX[AXOff + 0]) + AZ[AZOff + 0];
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 1]) + AZ[AZOff + 1];
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 2]) + AZ[AZOff + 2];
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 3]) + AZ[AZOff + 3];
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 4]) + AZ[AZOff + 4];
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 5]) + AZ[AZOff + 5];
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AX[AXOff + 6]) + AZ[AZOff + 6];
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.AddToEachOther(AU: TCryptoLibUInt32Array; AUOff: Int32; AV: TCryptoLibUInt32Array; AVOff: Int32): UInt32;
+var
+  LC: UInt64;
+begin
+  LC := 0;
+  LC := LC + UInt64(AU[AUOff + 0]) + AV[AVOff + 0];
+  AU[AUOff + 0] := UInt32(LC);
+  AV[AVOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 1]) + AV[AVOff + 1];
+  AU[AUOff + 1] := UInt32(LC);
+  AV[AVOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 2]) + AV[AVOff + 2];
+  AU[AUOff + 2] := UInt32(LC);
+  AV[AVOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 3]) + AV[AVOff + 3];
+  AU[AUOff + 3] := UInt32(LC);
+  AV[AVOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 4]) + AV[AVOff + 4];
+  AU[AUOff + 4] := UInt32(LC);
+  AV[AVOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 5]) + AV[AVOff + 5];
+  AU[AUOff + 5] := UInt32(LC);
+  AV[AVOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + UInt64(AU[AUOff + 6]) + AV[AVOff + 6];
+  AU[AUOff + 6] := UInt32(LC);
+  AV[AVOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class procedure TNat224.Copy(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array);
+begin
+  System.Move(AX[0], AZ[0], 7 * System.SizeOf(UInt32));
+end;
+
+class procedure TNat224.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
+begin
+  System.Move(AX[AXOff], AZ[AZOff], 7 * System.SizeOf(UInt32));
+end;
+
+class function TNat224.Create(): TCryptoLibUInt32Array;
+begin
+  SetLength(Result, 7);
+  Exit;
+end;
+
+class function TNat224.CreateExt(): TCryptoLibUInt32Array;
+begin
+  SetLength(Result, 14);
+  Exit;
+end;
+
+class function TNat224.Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; const AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean;
+var
+  LPos: Boolean;
+begin
+  LPos := Gte(AX, AXOff, AY, AYOff);
+  if LPos then
+  Sub(AX, AXOff, AY, AYOff, AZ, AZOff)
+  else
+  Sub(AY, AYOff, AX, AXOff, AZ, AZOff);
+  Result := LPos;
+end;
+
+class function TNat224.Eq(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 6 downto 0 do
+  begin
+    if AX[LI] <> AY[LI] then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat224.GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32;
+var
+  LW: Int32;
+  LB: Int32;
+begin
+  if ABit = 0 then
+  begin
+    Result := AX[0] and 1;
+    Exit;
+  end;
+  LW := TBitUtilities.Asr32(ABit, 5);
+  if (LW < 0) or (LW >= 7) then
+  begin
+    Result := 0;
+    Exit;
+  end;
+  LB := ABit and 31;
+  Result := (AX[LW] shr LB) and 1;
+end;
+
+class function TNat224.Gte(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+  LXI: UInt32;
+  LYI: UInt32;
+begin
+  for LI := 6 downto 0 do
+  begin
+    LXI := AX[LI];
+    LYI := AY[LI];
+    if LXI < LYI then
+    begin
+      Result := False;
+      Exit;
+    end;
+    if LXI > LYI then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat224.Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean;
+var
+  LI: Int32;
+  LXI: UInt32;
+  LYI: UInt32;
+begin
+  for LI := 6 downto 0 do
+  begin
+    LXI := AX[AXOff + LI];
+    LYI := AY[AYOff + LI];
+    if LXI < LYI then
+    begin
+      Result := False;
+      Exit;
+    end;
+    if LXI > LYI then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat224.IsOne(const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  if AX[0] <> 1 then
+  begin
+    Result := False;
+    Exit;
+  end;
+  for LI := 1 to (7) - 1 do
+  begin
+    if AX[LI] <> 0 then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat224.IsZero(const AX: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 0 to (7) - 1 do
+  begin
+    if AX[LI] <> 0 then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class procedure TNat224.Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
+var
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LY6: UInt64;
+  LC: UInt64;
+  LX0: UInt64;
+  LI: Int32;
+  LXI: UInt64;
+begin
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+  LY4 := AY[4];
+  LY5 := AY[5];
+  LY6 := AY[6];
+  LC := 0;
+  LX0 := AX[0];
+  LC := LC + (LX0 * LY0);
+  AZz[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY1);
+  AZz[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY2);
+  AZz[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY3);
+  AZz[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY4);
+  AZz[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY5);
+  AZz[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY6);
+  AZz[6] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[7] := UInt32(LC);
+  for LI := 1 to (7) - 1 do
+  begin
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + (LXI * LY0 + AZz[LI + 0]);
+    AZz[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[LI + 1]);
+    AZz[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[LI + 2]);
+    AZz[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[LI + 3]);
+    AZz[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[LI + 4]);
+    AZz[LI + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[LI + 5]);
+    AZz[LI + 5] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY6 + AZz[LI + 6]);
+    AZz[LI + 6] := UInt32(LC);
+    LC := LC shr 32;
+    AZz[LI + 7] := UInt32(LC);
+  end;
+end;
+
+class procedure TNat224.Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32);
+var
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LY6: UInt64;
+  LC: UInt64;
+  LX0: UInt64;
+  LI: Int32;
+  LXI: UInt64;
+begin
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+  LY4 := AY[AYOff + 4];
+  LY5 := AY[AYOff + 5];
+  LY6 := AY[AYOff + 6];
+  LC := 0;
+  LX0 := AX[AXOff + 0];
+  LC := LC + (LX0 * LY0);
+  AZz[AZzOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY1);
+  AZz[AZzOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY2);
+  AZz[AZzOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY3);
+  AZz[AZzOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY4);
+  AZz[AZzOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY5);
+  AZz[AZzOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX0 * LY6);
+  AZz[AZzOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[AZzOff + 7] := UInt32(LC);
+  for LI := 1 to (7) - 1 do
+  begin
+    Inc(AZzOff);
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + (LXI * LY0 + AZz[AZzOff + 0]);
+    AZz[AZzOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[AZzOff + 1]);
+    AZz[AZzOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[AZzOff + 2]);
+    AZz[AZzOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[AZzOff + 3]);
+    AZz[AZzOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[AZzOff + 4]);
+    AZz[AZzOff + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[AZzOff + 5]);
+    AZz[AZzOff + 5] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY6 + AZz[AZzOff + 6]);
+    AZz[AZzOff + 6] := UInt32(LC);
+    LC := LC shr 32;
+    AZz[AZzOff + 7] := UInt32(LC);
+  end;
+end;
+
+class function TNat224.MulAddTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array): UInt32;
+var
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LY6: UInt64;
+  LZc: UInt64;
+  LI: Int32;
+  LC: UInt64;
+  LXI: UInt64;
+begin
+  LY0 := AY[0];
+  LY1 := AY[1];
+  LY2 := AY[2];
+  LY3 := AY[3];
+  LY4 := AY[4];
+  LY5 := AY[5];
+  LY6 := AY[6];
+  LZc := 0;
+  for LI := 0 to (7) - 1 do
+  begin
+    LC := 0;
+    LXI := AX[LI];
+    LC := LC + (LXI * LY0 + AZz[LI + 0]);
+    AZz[LI + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[LI + 1]);
+    AZz[LI + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[LI + 2]);
+    AZz[LI + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[LI + 3]);
+    AZz[LI + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[LI + 4]);
+    AZz[LI + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[LI + 5]);
+    AZz[LI + 5] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY6 + AZz[LI + 6]);
+    AZz[LI + 6] := UInt32(LC);
+    LC := LC shr 32;
+    LZc := LZc + (LC + AZz[LI + 7]);
+    AZz[LI + 7] := UInt32(LZc);
+    LZc := LZc shr 32;
+  end;
+  Result := UInt32(LZc);
+end;
+
+class function TNat224.MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32;
+var
+  LY0: UInt64;
+  LY1: UInt64;
+  LY2: UInt64;
+  LY3: UInt64;
+  LY4: UInt64;
+  LY5: UInt64;
+  LY6: UInt64;
+  LZc: UInt64;
+  LI: Int32;
+  LC: UInt64;
+  LXI: UInt64;
+begin
+  LY0 := AY[AYOff + 0];
+  LY1 := AY[AYOff + 1];
+  LY2 := AY[AYOff + 2];
+  LY3 := AY[AYOff + 3];
+  LY4 := AY[AYOff + 4];
+  LY5 := AY[AYOff + 5];
+  LY6 := AY[AYOff + 6];
+  LZc := 0;
+  for LI := 0 to (7) - 1 do
+  begin
+    LC := 0;
+    LXI := AX[AXOff + LI];
+    LC := LC + (LXI * LY0 + AZz[AZzOff + 0]);
+    AZz[AZzOff + 0] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY1 + AZz[AZzOff + 1]);
+    AZz[AZzOff + 1] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY2 + AZz[AZzOff + 2]);
+    AZz[AZzOff + 2] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY3 + AZz[AZzOff + 3]);
+    AZz[AZzOff + 3] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY4 + AZz[AZzOff + 4]);
+    AZz[AZzOff + 4] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY5 + AZz[AZzOff + 5]);
+    AZz[AZzOff + 5] := UInt32(LC);
+    LC := LC shr 32;
+    LC := LC + (LXI * LY6 + AZz[AZzOff + 6]);
+    AZz[AZzOff + 6] := UInt32(LC);
+    LC := LC shr 32;
+    LZc := LZc + (LC + AZz[AZzOff + 7]);
+    AZz[AZzOff + 7] := UInt32(LZc);
+    LZc := LZc shr 32;
+    Inc(AZzOff);
+  end;
+  Result := UInt32(LZc);
+end;
+
+class function TNat224.Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64;
+var
+  LC: UInt64;
+  LWVal: UInt64;
+  LX0: UInt64;
+  LX1: UInt64;
+  LX2: UInt64;
+  LX3: UInt64;
+  LX4: UInt64;
+  LX5: UInt64;
+  LX6: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AW shr 31 = 0);
+  {$ENDIF}
+  LC := 0;
+  LWVal := AW;
+  LX0 := AX[AXOff + 0];
+  LC := LC + (LWVal * LX0 + AY[AYOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LX1 := AX[AXOff + 1];
+  LC := LC + (LWVal * LX1 + LX0 + AY[AYOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LX2 := AX[AXOff + 2];
+  LC := LC + (LWVal * LX2 + LX1 + AY[AYOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LX3 := AX[AXOff + 3];
+  LC := LC + (LWVal * LX3 + LX2 + AY[AYOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LX4 := AX[AXOff + 4];
+  LC := LC + (LWVal * LX4 + LX3 + AY[AYOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LX5 := AX[AXOff + 5];
+  LC := LC + (LWVal * LX5 + LX4 + AY[AYOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LX6 := AX[AXOff + 6];
+  LC := LC + (LWVal * LX6 + LX5 + AY[AYOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX6);
+  Result := LC;
+end;
+
+class function TNat224.MulByWord(AX: UInt32; AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+  LXVal: UInt64;
+begin
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * UInt64(AZ[0]));
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[1]));
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[2]));
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[3]));
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[4]));
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[5]));
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[6]));
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.MulByWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
+var
+  LC: UInt64;
+  LXVal: UInt64;
+begin
+  LC := 0;
+  LXVal := AX;
+  LC := LC + LXVal * UInt64(AZ[0]) + AY[0];
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXVal * UInt64(AZ[1]) + AY[1];
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXVal * UInt64(AZ[2]) + AY[2];
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXVal * UInt64(AZ[3]) + AY[3];
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXVal * UInt64(AZ[4]) + AY[4];
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXVal * UInt64(AZ[5]) + AY[5];
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + LXVal * UInt64(AZ[6]) + AY[6];
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.MulWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LXVal: UInt64;
+begin
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * AY[AYOff + 0] + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 1] + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 2] + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 3] + AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 4] + AZ[AZOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 5] + AZ[AZOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 6] + AZ[AZOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
+end;
+
+class function TNat224.Mul33DWordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LXVal: UInt64;
+  LY00: UInt64;
+  LY01: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AX shr 31 = 0);
+  System.Assert(AZOff <= 3);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LY00 := AY and M;
+  LC := LC + (LXVal * LY00 + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LY01 := AY shr 32;
+  LC := LC + (LXVal * LY01 + LY00 + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY01 + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(7, AZ, AZOff, 4);
+end;
+
+class function TNat224.Mul33WordAdd(AX: UInt32; AY: UInt32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LYVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AX shr 31 = 0);
+  System.Assert(AZOff <= 4);
+  {$ENDIF}
+  LC := 0;
+  LYVal := AY;
+  LC := LC + (LYVal * AX + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LYVal + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(7, AZ, AZOff, 3);
+end;
+
+class function TNat224.MulWordDwordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LXVal: UInt64;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AZOff <= 4);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * AY + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * (AY shr 32) + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  if LC = 0 then
+    Result := 0
+  else
+    Result := TNat.IncAt(7, AZ, AZOff, 3);
+end;
+
+class function TNat224.MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
+var
+  LC: UInt64;
+  LXVal: UInt64;
+  LI: Int32;
+begin
+  LC := 0;
+  LXVal := AX;
+  LI := 0;
+  repeat
+    LC := LC + (LXVal * AY[LI]);
+    AZ[AZOff + LI] := UInt32(LC);
+    LC := LC shr 32;
+    Inc(LI);
+  until not (LI < 7);
+  Result := UInt32(LC);
+end;
+
+class procedure TNat224.Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
+var
+  LX0: UInt64;
+  LZz1: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI: Int32;
+  LJ: Int32;
+  LXVal: UInt64;
+  LP: UInt64;
+  LX1: UInt64;
+  LZz2: UInt64;
+  LX2: UInt64;
+  LZz3: UInt64;
+  LZz4: UInt64;
+  LX3: UInt64;
+  LZz5: UInt64;
+  LZz6: UInt64;
+  LX4: UInt64;
+  LZz7: UInt64;
+  LZz8: UInt64;
+  LX5: UInt64;
+  LZz9: UInt64;
+  LZz10: UInt64;
+  LX6: UInt64;
+  LZz11: UInt64;
+  LZz12: UInt64;
+begin
+  LX0 := AX[0];
+  LC := 0;
+  LI := 6;
+  LJ := 14;
+  repeat
+    LXVal := AX[LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZz[LJ] := (LC shl 31) or UInt32((LP ) shr 33);
+    Dec(LJ);
+    AZz[LJ] := UInt32((LP ) shr 1);
+    LC := UInt32(LP);
+  until not (LI > 0);
+  LP := LX0 * LX0;
+  LZz1 := UInt64((LC ) shl 31) or (LP shr 33);
+  AZz[0] := UInt32(LP);
+  LC := UInt32((LP ) shr 32) and 1;
+  LX1 := AX[1];
+  LZz2 := AZz[2];
+  LZz1 := LZz1 + (LX1 * LX0);
+  LW := UInt32(LZz1);
+  AZz[1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz2 := LZz2 + (LZz1 shr 32);
+  LX2 := AX[2];
+  LZz3 := AZz[3];
+  LZz4 := AZz[4];
+  LZz2 := LZz2 + (LX2 * LX0);
+  LW := UInt32(LZz2);
+  AZz[2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz3 := LZz3 + ((LZz2 shr 32) + LX2 * LX1);
+  LZz4 := LZz4 + (LZz3 shr 32);
+  LZz3 := LZz3 and M;
+  LX3 := AX[3];
+  LZz5 := AZz[5] + (LZz4 shr 32);
+  LZz4 := LZz4 and M;
+  LZz6 := AZz[6] + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LZz3 := LZz3 + (LX3 * LX0);
+  LW := UInt32(LZz3);
+  AZz[3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz4 := LZz4 + ((LZz3 shr 32) + LX3 * LX1);
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX3 * LX2);
+  LZz4 := LZz4 and M;
+  LZz6 := LZz6 + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LX4 := AX[4];
+  LZz7 := AZz[7] + (LZz6 shr 32);
+  LZz6 := LZz6 and M;
+  LZz8 := AZz[8] + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LZz4 := LZz4 + (LX4 * LX0);
+  LW := UInt32(LZz4);
+  AZz[4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX4 * LX1);
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX4 * LX2);
+  LZz5 := LZz5 and M;
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX4 * LX3);
+  LZz6 := LZz6 and M;
+  LZz8 := LZz8 + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LX5 := AX[5];
+  LZz9 := AZz[9] + (LZz8 shr 32);
+  LZz8 := LZz8 and M;
+  LZz10 := AZz[10] + (LZz9 shr 32);
+  LZz9 := LZz9 and M;
+  LZz5 := LZz5 + (LX5 * LX0);
+  LW := UInt32(LZz5);
+  AZz[5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX5 * LX1);
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX5 * LX2);
+  LZz6 := LZz6 and M;
+  LZz8 := LZz8 + ((LZz7 shr 32) + LX5 * LX3);
+  LZz7 := LZz7 and M;
+  LZz9 := LZz9 + ((LZz8 shr 32) + LX5 * LX4);
+  LZz8 := LZz8 and M;
+  LZz10 := LZz10 + (LZz9 shr 32);
+  LZz9 := LZz9 and M;
+  LX6 := AX[6];
+  LZz11 := AZz[11] + (LZz10 shr 32);
+  LZz10 := LZz10 and M;
+  LZz12 := AZz[12] + (LZz11 shr 32);
+  LZz11 := LZz11 and M;
+  LZz6 := LZz6 + (LX6 * LX0);
+  LW := UInt32(LZz6);
+  AZz[6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX6 * LX1);
+  LZz8 := LZz8 + ((LZz7 shr 32) + LX6 * LX2);
+  LZz9 := LZz9 + ((LZz8 shr 32) + LX6 * LX3);
+  LZz10 := LZz10 + ((LZz9 shr 32) + LX6 * LX4);
+  LZz11 := LZz11 + ((LZz10 shr 32) + LX6 * LX5);
+  LZz12 := LZz12 + (LZz11 shr 32);
+  LW := UInt32(LZz7);
+  AZz[7] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz8);
+  AZz[8] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz9);
+  AZz[9] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz10);
+  AZz[10] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz11);
+  AZz[11] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz12);
+  AZz[12] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := AZz[13] + UInt32((LZz12 ) shr 32);
+  AZz[13] := (LW shl 1) or LC;
+end;
+
+class procedure TNat224.Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32);
+var
+  LX0: UInt64;
+  LZz1: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI: Int32;
+  LJ: Int32;
+  LXVal: UInt64;
+  LP: UInt64;
+  LX1: UInt64;
+  LZz2: UInt64;
+  LX2: UInt64;
+  LZz3: UInt64;
+  LZz4: UInt64;
+  LX3: UInt64;
+  LZz5: UInt64;
+  LZz6: UInt64;
+  LX4: UInt64;
+  LZz7: UInt64;
+  LZz8: UInt64;
+  LX5: UInt64;
+  LZz9: UInt64;
+  LZz10: UInt64;
+  LX6: UInt64;
+  LZz11: UInt64;
+  LZz12: UInt64;
+begin
+  LX0 := AX[AXOff + 0];
+  LC := 0;
+  LI := 6;
+  LJ := 14;
+  repeat
+    LXVal := AX[AXOff + LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZz[AZzOff + LJ] := (LC shl 31) or UInt32((LP ) shr 33);
+    Dec(LJ);
+    AZz[AZzOff + LJ] := UInt32((LP ) shr 1);
+    LC := UInt32(LP);
+  until not (LI > 0);
+  LP := LX0 * LX0;
+  LZz1 := UInt64((LC ) shl 31) or (LP shr 33);
+  AZz[AZzOff + 0] := UInt32(LP);
+  LC := UInt32((LP ) shr 32) and 1;
+  LX1 := AX[AXOff + 1];
+  LZz2 := AZz[AZzOff + 2];
+  LZz1 := LZz1 + (LX1 * LX0);
+  LW := UInt32(LZz1);
+  AZz[AZzOff + 1] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz2 := LZz2 + (LZz1 shr 32);
+  LX2 := AX[AXOff + 2];
+  LZz3 := AZz[AZzOff + 3];
+  LZz4 := AZz[AZzOff + 4];
+  LZz2 := LZz2 + (LX2 * LX0);
+  LW := UInt32(LZz2);
+  AZz[AZzOff + 2] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz3 := LZz3 + ((LZz2 shr 32) + LX2 * LX1);
+  LZz4 := LZz4 + (LZz3 shr 32);
+  LZz3 := LZz3 and M;
+  LX3 := AX[AXOff + 3];
+  LZz5 := AZz[AZzOff + 5] + (LZz4 shr 32);
+  LZz4 := LZz4 and M;
+  LZz6 := AZz[AZzOff + 6] + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LZz3 := LZz3 + (LX3 * LX0);
+  LW := UInt32(LZz3);
+  AZz[AZzOff + 3] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz4 := LZz4 + ((LZz3 shr 32) + LX3 * LX1);
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX3 * LX2);
+  LZz4 := LZz4 and M;
+  LZz6 := LZz6 + (LZz5 shr 32);
+  LZz5 := LZz5 and M;
+  LX4 := AX[AXOff + 4];
+  LZz7 := AZz[AZzOff + 7] + (LZz6 shr 32);
+  LZz6 := LZz6 and M;
+  LZz8 := AZz[AZzOff + 8] + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LZz4 := LZz4 + (LX4 * LX0);
+  LW := UInt32(LZz4);
+  AZz[AZzOff + 4] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz5 := LZz5 + ((LZz4 shr 32) + LX4 * LX1);
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX4 * LX2);
+  LZz5 := LZz5 and M;
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX4 * LX3);
+  LZz6 := LZz6 and M;
+  LZz8 := LZz8 + (LZz7 shr 32);
+  LZz7 := LZz7 and M;
+  LX5 := AX[AXOff + 5];
+  LZz9 := AZz[AZzOff + 9] + (LZz8 shr 32);
+  LZz8 := LZz8 and M;
+  LZz10 := AZz[AZzOff + 10] + (LZz9 shr 32);
+  LZz9 := LZz9 and M;
+  LZz5 := LZz5 + (LX5 * LX0);
+  LW := UInt32(LZz5);
+  AZz[AZzOff + 5] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz6 := LZz6 + ((LZz5 shr 32) + LX5 * LX1);
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX5 * LX2);
+  LZz6 := LZz6 and M;
+  LZz8 := LZz8 + ((LZz7 shr 32) + LX5 * LX3);
+  LZz7 := LZz7 and M;
+  LZz9 := LZz9 + ((LZz8 shr 32) + LX5 * LX4);
+  LZz8 := LZz8 and M;
+  LZz10 := LZz10 + (LZz9 shr 32);
+  LZz9 := LZz9 and M;
+  LX6 := AX[AXOff + 6];
+  LZz11 := AZz[AZzOff + 11] + (LZz10 shr 32);
+  LZz10 := LZz10 and M;
+  LZz12 := AZz[AZzOff + 12] + (LZz11 shr 32);
+  LZz11 := LZz11 and M;
+  LZz6 := LZz6 + (LX6 * LX0);
+  LW := UInt32(LZz6);
+  AZz[AZzOff + 6] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LZz7 := LZz7 + ((LZz6 shr 32) + LX6 * LX1);
+  LZz8 := LZz8 + ((LZz7 shr 32) + LX6 * LX2);
+  LZz9 := LZz9 + ((LZz8 shr 32) + LX6 * LX3);
+  LZz10 := LZz10 + ((LZz9 shr 32) + LX6 * LX4);
+  LZz11 := LZz11 + ((LZz10 shr 32) + LX6 * LX5);
+  LZz12 := LZz12 + (LZz11 shr 32);
+  LW := UInt32(LZz7);
+  AZz[AZzOff + 7] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz8);
+  AZz[AZzOff + 8] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz9);
+  AZz[AZzOff + 9] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz10);
+  AZz[AZzOff + 10] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz11);
+  AZz[AZzOff + 11] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := UInt32(LZz12);
+  AZz[AZzOff + 12] := (LW shl 1) or LC;
+  LC := LW shr 31;
+  LW := AZz[AZzOff + 13] + UInt32((LZz12 ) shr 32);
+  AZz[AZzOff + 13] := (LW shl 1) or LC;
+end;
+
+class function TNat224.Sub(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + (Int64(AX[0]) - Int64(AY[0]));
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[1]) - Int64(AY[1]));
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[2]) - Int64(AY[2]));
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[3]) - Int64(AY[3]));
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[4]) - Int64(AY[4]));
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[5]) - Int64(AY[5]));
+  AZ[5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[6]) - Int64(AY[6]));
+  AZ[6] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat224.Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + (Int64(AX[AXOff + 0]) - Int64(AY[AYOff + 0]));
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 1]) - Int64(AY[AYOff + 1]));
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 2]) - Int64(AY[AYOff + 2]));
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 3]) - Int64(AY[AYOff + 3]));
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 4]) - Int64(AY[AYOff + 4]));
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 5]) - Int64(AY[AYOff + 5]));
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AX[AXOff + 6]) - Int64(AY[AYOff + 6]));
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat224.SubBothFrom(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + (Int64(AZ[0]) - Int64(AX[0]) - Int64(AY[0]));
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[1]) - Int64(AX[1]) - Int64(AY[1]));
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[2]) - Int64(AX[2]) - Int64(AY[2]));
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[3]) - Int64(AX[3]) - Int64(AY[3]));
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[4]) - Int64(AX[4]) - Int64(AY[4]));
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[5]) - Int64(AX[5]) - Int64(AY[5]));
+  AZ[5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[6]) - Int64(AX[6]) - Int64(AY[6]));
+  AZ[6] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat224.SubFrom(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + (Int64(AZ[0]) - Int64(AX[0]));
+  AZ[0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[1]) - Int64(AX[1]));
+  AZ[1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[2]) - Int64(AX[2]));
+  AZ[2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[3]) - Int64(AX[3]));
+  AZ[3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[4]) - Int64(AX[4]));
+  AZ[4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[5]) - Int64(AX[5]));
+  AZ[5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[6]) - Int64(AX[6]));
+  AZ[6] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat224.SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
+var
+  LC: Int64;
+begin
+  LC := 0;
+  LC := LC + (Int64(AZ[AZOff + 0]) - Int64(AX[AXOff + 0]));
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 1]) - Int64(AX[AXOff + 1]));
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 2]) - Int64(AX[AXOff + 2]));
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 3]) - Int64(AX[AXOff + 3]));
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 4]) - Int64(AX[AXOff + 4]));
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 5]) - Int64(AX[AXOff + 5]));
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[AZOff + 6]) - Int64(AX[AXOff + 6]));
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := TBitUtilities.Asr64(LC, 32);
+  Result := Int32(LC);
+end;
+
+class function TNat224.ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger;
+var
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXI: UInt32;
+begin
+  SetLength(LBs, 28);
+  for LI := 0 to (7) - 1 do
+  begin
+    LXI := AX[LI];
+    if LXI <> 0 then
+    TPack.UInt32_To_BE(LXI, LBs, (6 - LI) shl 2);
+  end;
+  Result := TBigInteger.Create(1, LBs);
+end;
+
+class procedure TNat224.Zero(AZ: TCryptoLibUInt32Array);
+begin
+  TArrayUtilities.Fill<UInt32>(AZ, 0, 7, UInt32(0));
+end;
+
+end.

+ 1459 - 1477
CryptoLib/src/Math/Raw/ClpNat256.pas

@@ -22,1760 +22,1742 @@ unit ClpNat256;
 interface
 
 uses
+  SysUtils,
+  ClpArrayUtilities,
   ClpNat,
-  ClpConverters,
-  ClpBitUtilities,
+  ClpPack,
   ClpBigInteger,
-  ClpArrayUtilities,
+  ClpBitUtilities,
   ClpCryptoLibTypes;
 
 type
-  TNat256 = class abstract(TObject)
-
+  TNat256 = class sealed
   strict private
   const
-    M = UInt64($FFFFFFFF);
-
+    M: UInt64 = $FFFFFFFF;
   public
-    class function Add(const x, y, z: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-    class function Add(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; overload; static;
-
-    class function AddBothTo(const x, y, z: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-    class function AddBothTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; overload; static;
-
-    class function AddTo(const x, z: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-    class function AddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32; cIn: UInt32): UInt32;
-      overload; static;
-
-    class function AddToEachOther(const u: TCryptoLibUInt32Array; uOff: Int32;
-      const v: TCryptoLibUInt32Array; vOff: Int32): UInt32; static;
-
-    class procedure Copy(const x, z: TCryptoLibUInt32Array); overload;
-      static; inline;
-    class procedure Copy(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32); overload; static; inline;
-
-    class procedure Copy64(const x, z: TCryptoLibUInt64Array); overload;
-      static; inline;
-
-    class procedure Copy64(const x: TCryptoLibUInt64Array; xOff: Int32;
-      const z: TCryptoLibUInt64Array; zOff: Int32); overload; static; inline;
-
-    class function Create(): TCryptoLibUInt32Array; static; inline;
-
-    class function Create64(): TCryptoLibUInt64Array; static; inline;
-
-    class function CreateExt(): TCryptoLibUInt32Array; static; inline;
-
-    class function CreateExt64(): TCryptoLibUInt64Array; static; inline;
-
-    class function Diff(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): Boolean; static; inline;
-
-    class function Eq(const x, y: TCryptoLibUInt32Array): Boolean; static;
-
-    class function Eq64(const x, y: TCryptoLibUInt64Array): Boolean; static;
-
-    class function FromBigInteger(const x: TBigInteger)
-      : TCryptoLibUInt32Array; static;
-
-    class function FromBigInteger64(const x: TBigInteger)
-      : TCryptoLibUInt64Array; static;
-
-    class function GetBit(const x: TCryptoLibUInt32Array; bit: Int32): UInt32;
-      static; inline;
-
-    class function Gte(const x, y: TCryptoLibUInt32Array): Boolean;
-      overload; static;
-
-    class function Gte(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32): Boolean; overload; static;
-
-    class function IsOne(const x: TCryptoLibUInt32Array): Boolean; static;
-
-    class function IsOne64(const x: TCryptoLibUInt64Array): Boolean; static;
-
-    class function IsZero(const x: TCryptoLibUInt32Array): Boolean; static;
-
-    class function IsZero64(const x: TCryptoLibUInt64Array): Boolean; static;
-
-    class procedure Mul(const x, y, zz: TCryptoLibUInt32Array);
-      overload; static;
-
-    class procedure Mul(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const zz: TCryptoLibUInt32Array; zzOff: Int32); overload; static;
-
-    class function MulAddTo(const x, y, zz: TCryptoLibUInt32Array): UInt32;
-      overload; static;
-
-    class function MulAddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const zz: TCryptoLibUInt32Array; zzOff: Int32): UInt32; overload; static;
-
-    class function Mul33Add(w: UInt32; const x: TCryptoLibUInt32Array;
-      xOff: Int32; const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt64; static;
-
-    class function MulByWord(x: UInt32; const z: TCryptoLibUInt32Array)
-      : UInt32; static;
-
-    class function MulByWordAddTo(x: UInt32; const y, z: TCryptoLibUInt32Array)
-      : UInt32; static;
-
-    class function MulWordAddTo(x: UInt32; const y: TCryptoLibUInt32Array;
-      yOff: Int32; const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; static;
-
-    class function Mul33DWordAdd(x: UInt32; y: UInt64;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; static;
-
-    class function Mul33WordAdd(x, y: UInt32; const z: TCryptoLibUInt32Array;
-      zOff: Int32): UInt32; static;
-
-    class function MulWordDwordAdd(x: UInt32; y: UInt64;
-      const z: TCryptoLibUInt32Array; zOff: Int32): UInt32; static;
-
-    class function MulWord(x: UInt32; const y, z: TCryptoLibUInt32Array;
-      zOff: Int32): UInt32; static;
-
-    class procedure Square(const x, zz: TCryptoLibUInt32Array);
-      overload; static;
-
-    class procedure Square(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const zz: TCryptoLibUInt32Array; zzOff: Int32); overload; static;
-
-    class function Sub(const x, y, z: TCryptoLibUInt32Array): Int32;
-      overload; static;
-
-    class function Sub(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const y: TCryptoLibUInt32Array; yOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): Int32; overload; static;
-
-    class function SubBothFrom(const x, y, z: TCryptoLibUInt32Array)
-      : Int32; static;
-
-    class function SubFrom(const x, z: TCryptoLibUInt32Array): Int32;
-      overload; static;
-
-    class function SubFrom(const x: TCryptoLibUInt32Array; xOff: Int32;
-      const z: TCryptoLibUInt32Array; zOff: Int32): Int32; overload; static;
-
-    class function ToBigInteger(const x: TCryptoLibUInt32Array)
-      : TBigInteger; static;
-
-    class function ToBigInteger64(const x: TCryptoLibUInt64Array)
-      : TBigInteger; static;
-
-    class procedure Zero(const z: TCryptoLibUInt32Array); static; inline;
-
+    class function Add(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function Add(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; overload; static;
+    class function AddBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function AddBothTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; ACIn: UInt32): UInt32; overload; static;
+    class function AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: UInt32): UInt32; overload; static;
+    class function AddToEachOther(const AU: TCryptoLibUInt32Array; AUOff: Int32; const AV: TCryptoLibUInt32Array; AVOff: Int32): UInt32; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+    class function Create(): TCryptoLibUInt32Array; static;
+    class function Create64(): TCryptoLibUInt64Array; static;
+    class function CreateExt(): TCryptoLibUInt32Array; static;
+    class function CreateExt64(): TCryptoLibUInt64Array; static;
+    class function Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean; static;
+    class function Eq(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean; static;
+    class function Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean; static;
+    class function GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean; overload; static;
+    class function Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean; overload; static;
+    class function IsOne(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class function IsOne64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Boolean; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); overload; static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32); overload; static;
+    class procedure Mul128(const AX: TCryptoLibUInt32Array; const AY128: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array): UInt32; overload; static;
+    class function MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32; overload; static;
+    class function Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64; static;
+    class function MulByWord(AX: UInt32; AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function MulByWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; static;
+    class function MulWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function Mul33DWordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function Mul33WordAdd(AX: UInt32; AY: UInt32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWordDwordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class function MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32); overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; overload; static;
+    class function Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32; overload; static;
+    class function SubBothFrom(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; ACIn: Int32): Int32; overload; static;
+    class function SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: Int32): Int32; overload; static;
+    class function ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger; static;
+    class function ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger; static;
+    class procedure &Xor(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); static;
+    class procedure Zero(AZ: TCryptoLibUInt32Array); static;
   end;
 
 implementation
 
-{ TNat256 }
-
-class function TNat256.Add(const x, y, z: TCryptoLibUInt32Array): UInt32;
+class function TNat256.Add(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[0]) + y[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[1]) + y[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[2]) + y[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[3]) + y[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[4]) + y[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[5]) + y[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[6]) + y[6]);
-  z[6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[7]) + y[7]);
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + (UInt64(AX[0]) + AY[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[1]) + AY[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[2]) + AY[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[3]) + AY[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[4]) + AY[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[5]) + AY[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[6]) + AY[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[7]) + AY[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.Add(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const z: TCryptoLibUInt32Array;
-  zOff: Int32): UInt32;
+class function TNat256.Add(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[xOff + 0]) + y[yOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 1]) + y[yOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 2]) + y[yOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 3]) + y[yOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 4]) + y[yOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 5]) + y[yOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 6]) + y[yOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 7]) + y[yOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + (UInt64(AX[AXOff + 0]) + AY[AYOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 1]) + AY[AYOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 2]) + AY[AYOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 3]) + AY[AYOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 4]) + AY[AYOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 5]) + AY[AYOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 6]) + AY[AYOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 7]) + AY[AYOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.AddBothTo(const x, y, z: TCryptoLibUInt32Array): UInt32;
+class function TNat256.AddBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[0]) + y[0] + z[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[1]) + y[1] + z[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[2]) + y[2] + z[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[3]) + y[3] + z[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[4]) + y[4] + z[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[5]) + y[5] + z[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[6]) + y[6] + z[6]);
-  z[6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[7]) + y[7] + z[7]);
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + (UInt64(AX[0]) + AY[0] + AZ[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[1]) + AY[1] + AZ[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[2]) + AY[2] + AZ[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[3]) + AY[3] + AZ[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[4]) + AY[4] + AZ[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[5]) + AY[5] + AZ[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[6]) + AY[6] + AZ[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[7]) + AY[7] + AZ[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.AddBothTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const z: TCryptoLibUInt32Array;
-  zOff: Int32): UInt32;
+class function TNat256.AddBothTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[xOff + 0]) + y[yOff + 0] + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 1]) + y[yOff + 1] + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 2]) + y[yOff + 2] + z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 3]) + y[yOff + 3] + z[zOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 4]) + y[yOff + 4] + z[zOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 5]) + y[yOff + 5] + z[zOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 6]) + y[yOff + 6] + z[zOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 7]) + y[yOff + 7] + z[zOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + (UInt64(AX[AXOff + 0]) + AY[AYOff + 0] + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 1]) + AY[AYOff + 1] + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 2]) + AY[AYOff + 2] + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 3]) + AY[AYOff + 3] + AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 4]) + AY[AYOff + 4] + AZ[AZOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 5]) + AY[AYOff + 5] + AZ[AZOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 6]) + AY[AYOff + 6] + AZ[AZOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 7]) + AY[AYOff + 7] + AZ[AZOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.AddTo(const x, z: TCryptoLibUInt32Array): UInt32;
+class function TNat256.AddTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; ACIn: UInt32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(x[0]) + z[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[1]) + z[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[2]) + z[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[3]) + z[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[4]) + z[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[5]) + z[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[6]) + z[6]);
-  z[6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[7]) + z[7]);
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := ACIn;
+  LC := LC + (UInt64(AX[0]) + AZ[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[1]) + AZ[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[2]) + AZ[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[3]) + AZ[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[4]) + AZ[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[5]) + AZ[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[6]) + AZ[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[7]) + AZ[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.AddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32; cIn: UInt32): UInt32;
+class function TNat256.AddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: UInt32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := cIn;
-  c := c + (UInt64(x[xOff + 0]) + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 1]) + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 2]) + z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 3]) + z[zOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 4]) + z[zOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 5]) + z[zOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 6]) + z[zOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(x[xOff + 7]) + z[zOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := ACIn;
+  LC := LC + (UInt64(AX[AXOff + 0]) + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 1]) + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 2]) + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 3]) + AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 4]) + AZ[AZOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 5]) + AZ[AZOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 6]) + AZ[AZOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AX[AXOff + 7]) + AZ[AZOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.AddToEachOther(const u: TCryptoLibUInt32Array;
-  uOff: Int32; const v: TCryptoLibUInt32Array; vOff: Int32): UInt32;
+class function TNat256.AddToEachOther(const AU: TCryptoLibUInt32Array; AUOff: Int32; const AV: TCryptoLibUInt32Array; AVOff: Int32): UInt32;
 var
-  c: UInt64;
+  LC: UInt64;
 begin
-  c := 0;
-  c := c + (UInt64(u[uOff + 0]) + v[vOff + 0]);
-  u[uOff + 0] := UInt32(c);
-  v[vOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 1]) + v[vOff + 1]);
-  u[uOff + 1] := UInt32(c);
-  v[vOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 2]) + v[vOff + 2]);
-  u[uOff + 2] := UInt32(c);
-  v[vOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 3]) + v[vOff + 3]);
-  u[uOff + 3] := UInt32(c);
-  v[vOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 4]) + v[vOff + 4]);
-  u[uOff + 4] := UInt32(c);
-  v[vOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 5]) + v[vOff + 5]);
-  u[uOff + 5] := UInt32(c);
-  v[vOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 6]) + v[vOff + 6]);
-  u[uOff + 6] := UInt32(c);
-  v[vOff + 6] := UInt32(c);
-  c := c shr 32;
-  c := c + (UInt64(u[uOff + 7]) + v[vOff + 7]);
-  u[uOff + 7] := UInt32(c);
-  v[vOff + 7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LC := LC + (UInt64(AU[AUOff + 0]) + AV[AVOff + 0]);
+  AU[AUOff + 0] := UInt32(LC);
+  AV[AVOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 1]) + AV[AVOff + 1]);
+  AU[AUOff + 1] := UInt32(LC);
+  AV[AVOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 2]) + AV[AVOff + 2]);
+  AU[AUOff + 2] := UInt32(LC);
+  AV[AVOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 3]) + AV[AVOff + 3]);
+  AU[AUOff + 3] := UInt32(LC);
+  AV[AVOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 4]) + AV[AVOff + 4]);
+  AU[AUOff + 4] := UInt32(LC);
+  AV[AVOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 5]) + AV[AVOff + 5]);
+  AU[AUOff + 5] := UInt32(LC);
+  AV[AVOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 6]) + AV[AVOff + 6]);
+  AU[AUOff + 6] := UInt32(LC);
+  AV[AVOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (UInt64(AU[AUOff + 7]) + AV[AVOff + 7]);
+  AU[AUOff + 7] := UInt32(LC);
+  AV[AVOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class procedure TNat256.Copy(const x, z: TCryptoLibUInt32Array);
+class procedure TNat256.Copy(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array);
 begin
-  System.Move(x[0], z[0], 8 * System.SizeOf(UInt32));
+  AZ[0] := AX[0];
+  AZ[1] := AX[1];
+  AZ[2] := AX[2];
+  AZ[3] := AX[3];
+  AZ[4] := AX[4];
+  AZ[5] := AX[5];
+  AZ[6] := AX[6];
+  AZ[7] := AX[7];
 end;
 
-class procedure TNat256.Copy(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32);
+class procedure TNat256.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
 begin
-  System.Move(x[xOff], z[zOff], 8 * System.SizeOf(UInt32));
+  System.Move(AX[AXOff], AZ[AZOff], 8 * System.SizeOf(UInt32));
 end;
 
-class procedure TNat256.Copy64(const x, z: TCryptoLibUInt64Array);
+class procedure TNat256.Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
 begin
-  System.Move(x[0], z[0], 4 * System.SizeOf(UInt64));
+  AZ[0] := AX[0];
+  AZ[1] := AX[1];
+  AZ[2] := AX[2];
+  AZ[3] := AX[3];
 end;
 
-class procedure TNat256.Copy64(const x: TCryptoLibUInt64Array; xOff: Int32;
-  const z: TCryptoLibUInt64Array; zOff: Int32);
+class procedure TNat256.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
 begin
-  System.Move(x[xOff], z[zOff], 4 * System.SizeOf(UInt64));
+  System.Move(AX[AXOff], AZ[AZOff], 4 * System.SizeOf(UInt64));
 end;
 
-class function TNat256.Create: TCryptoLibUInt32Array;
+class function TNat256.Create(): TCryptoLibUInt32Array;
 begin
-  System.SetLength(result, 8);
+  SetLength(Result, 8);
+  Exit;
 end;
 
-class function TNat256.Create64: TCryptoLibUInt64Array;
+class function TNat256.Create64(): TCryptoLibUInt64Array;
 begin
-  System.SetLength(result, 4);
+  SetLength(Result, 4);
+  Exit;
 end;
 
-class function TNat256.CreateExt: TCryptoLibUInt32Array;
+class function TNat256.CreateExt(): TCryptoLibUInt32Array;
 begin
-  System.SetLength(result, 16);
+  SetLength(Result, 16);
+  Exit;
 end;
 
-class function TNat256.CreateExt64: TCryptoLibUInt64Array;
+class function TNat256.CreateExt64(): TCryptoLibUInt64Array;
 begin
-  System.SetLength(result, 8);
+  SetLength(Result, 8);
+  Exit;
 end;
 
-class function TNat256.Diff(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const z: TCryptoLibUInt32Array;
-  zOff: Int32): Boolean;
+class function TNat256.Diff(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Boolean;
 var
-  pos: Boolean;
+  LPos: Boolean;
 begin
-  pos := Gte(x, xOff, y, yOff);
-  if (pos) then
+  LPos := Gte(AX, AXOff, AY, AYOff);
+  if LPos then
   begin
-    Sub(x, xOff, y, yOff, z, zOff);
+    Sub(AX, AXOff, AY, AYOff, AZ, AZOff);
   end
   else
   begin
-    Sub(y, yOff, x, xOff, z, zOff);
+    Sub(AY, AYOff, AX, AXOff, AZ, AZOff);
   end;
-  result := pos;
+  Result := LPos;
 end;
 
-class function TNat256.Eq(const x, y: TCryptoLibUInt32Array): Boolean;
+class function TNat256.Eq(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 7;
-  while i >= 0 do
+  for LI := 7 downto 0 do
   begin
-    if (x[i] <> y[i]) then
+    if AX[LI] <> AY[LI] then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat256.Eq64(const x, y: TCryptoLibUInt64Array): Boolean;
+class function TNat256.Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 3;
-  while i >= 0 do
+  for LI := 3 downto 0 do
   begin
-    if (x[i] <> y[i]) then
+    if AX[LI] <> AY[LI] then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Dec(i);
-  end;
-  result := true;
-end;
-
-class function TNat256.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
-var
-  i: Int32;
-  Lx: TBigInteger;
-begin
-  Lx := x;
-  if ((Lx.SignValue < 0) or (Lx.BitLength > 256)) then
-  begin
-    raise EArgumentCryptoLibException.Create('');
-  end;
-
-  result := Create();
-  i := 0;
-  while (Lx.SignValue <> 0) do
-  begin
-    result[i] := UInt32(Lx.Int32Value);
-    System.Inc(i);
-    Lx := Lx.ShiftRight(32);
   end;
+  Result := True;
 end;
 
-class function TNat256.FromBigInteger64(const x: TBigInteger)
-  : TCryptoLibUInt64Array;
+class function TNat256.GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32;
 var
-  i: Int32;
-  Lx: TBigInteger;
+  LW: Int32;
+  LB: Int32;
 begin
-  Lx := x;
-  if ((Lx.SignValue < 0) or (Lx.BitLength > 256)) then
+  if ABit = 0 then
   begin
-    raise EArgumentCryptoLibException.Create('');
-  end;
-
-  result := Create64();
-  i := 0;
-  while (Lx.SignValue <> 0) do
-  begin
-    result[i] := UInt64(Lx.Int64Value);
-    System.Inc(i);
-    Lx := Lx.ShiftRight(64);
-  end;
-end;
-
-class function TNat256.GetBit(const x: TCryptoLibUInt32Array;
-  bit: Int32): UInt32;
-var
-  w, b: Int32;
-begin
-  if (bit = 0) then
-  begin
-    result := x[0] and 1;
+    Result := AX[0] and 1;
     Exit;
   end;
-  if ((bit and 255) <> bit) then
+  if (ABit and 255) <> ABit then
   begin
-    result := 0;
+    Result := 0;
     Exit;
   end;
-  w := TBitUtilities.Asr32(bit, 5);
-  b := bit and 31;
-  result := (x[w] shr b) and 1;
+  LW := TBitUtilities.Asr32(ABit, 5);
+  LB := ABit and 31;
+  Result := (AX[LW] shr LB) and 1;
 end;
 
-class function TNat256.Gte(const x, y: TCryptoLibUInt32Array): Boolean;
+class function TNat256.Gte(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
-  x_i, y_i: UInt32;
+  LX_i: UInt32;
+  LY_i: UInt32;
+  LI: Int32;
 begin
-  i := 7;
-  while i >= 0 do
+  for LI := 7 downto 0 do
   begin
-    x_i := x[i];
-    y_i := y[i];
-
-    if (x_i < y_i) then
+    LX_i := AX[LI];
+    LY_i := AY[LI];
+    if LX_i < LY_i then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-
-    if (x_i > y_i) then
+    if LX_i > LY_i then
     begin
-      result := true;
+      Result := True;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat256.Gte(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32): Boolean;
+class function TNat256.Gte(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Boolean;
 var
-  i: Int32;
-  x_i, y_i: UInt32;
+  LX_i: UInt32;
+  LY_i: UInt32;
+  LI: Int32;
 begin
-  i := 7;
-  while i >= 0 do
+  for LI := 7 downto 0 do
   begin
-    x_i := x[xOff + i];
-    y_i := y[yOff + i];
-
-    if (x_i < y_i) then
+    LX_i := AX[AXOff + LI];
+    LY_i := AY[AYOff + LI];
+    if LX_i < LY_i then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-
-    if (x_i > y_i) then
+    if LX_i > LY_i then
     begin
-      result := true;
+      Result := True;
       Exit;
     end;
-    System.Dec(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat256.IsOne(const x: TCryptoLibUInt32Array): Boolean;
+class function TNat256.IsOne(const AX: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  if (x[0] <> 1) then
+  if AX[0] <> 1 then
   begin
-    result := false;
+    Result := False;
     Exit;
   end;
-
-  i := 1;
-  while i < 8 do
+  for LI := 1 to (8) - 1 do
   begin
-    if (x[i] <> 0) then
+    if AX[LI] <> 0 then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat256.IsOne64(const x: TCryptoLibUInt64Array): Boolean;
+class function TNat256.IsOne64(const AX: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  if (x[0] <> UInt64(1)) then
+  if AX[0] <> UInt64(1) then
   begin
-    result := false;
+    Result := False;
     Exit;
   end;
-
-  i := 1;
-  while i < 4 do
+  for LI := 1 to (4) - 1 do
   begin
-    if (x[i] <> UInt64(0)) then
+    if AX[LI] <> UInt64(0) then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat256.IsZero(const x: TCryptoLibUInt32Array): Boolean;
+class function TNat256.IsZero(const AX: TCryptoLibUInt32Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 0;
-  while i < 8 do
+  for LI := 0 to 7 do
   begin
-    if (x[i] <> 0) then
+    if AX[LI] <> 0 then
     begin
-      result := false;
+      Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
-  result := true;
+  Result := True;
 end;
 
-class function TNat256.IsZero64(const x: TCryptoLibUInt64Array): Boolean;
+class procedure TNat256.Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  i: Int32;
+  LY_0: UInt64;
+  LY_1: UInt64;
+  LY_2: UInt64;
+  LY_3: UInt64;
+  LY_4: UInt64;
+  LY_5: UInt64;
+  LY_6: UInt64;
+  LY_7: UInt64;
+  LC: UInt64;
+  LX_0: UInt64;
+  LX_i: UInt64;
+  LI: Int32;
 begin
-  i := 0;
-  while i < 4 do
+  LY_0 := AY[0];
+  LY_1 := AY[1];
+  LY_2 := AY[2];
+  LY_3 := AY[3];
+  LY_4 := AY[4];
+  LY_5 := AY[5];
+  LY_6 := AY[6];
+  LY_7 := AY[7];
   begin
-    if (x[i] <> UInt64(0)) then
-    begin
-      result := false;
-      Exit;
-    end;
-    System.Inc(i);
+  LC := 0;
+  LX_0 := AX[0];
+  LC := LC + (LX_0 * LY_0);
+  AZz[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_1);
+  AZz[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_2);
+  AZz[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_3);
+  AZz[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_4);
+  AZz[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_5);
+  AZz[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_6);
+  AZz[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_7);
+  AZz[7] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[8] := UInt32(LC);
+  end;
+  for LI := 1 to (8) - 1 do
+  begin
+  LC := 0;
+  LX_i := AX[LI];
+  LC := LC + (LX_i * LY_0 + AZz[LI + 0]);
+  AZz[LI + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_1 + AZz[LI + 1]);
+  AZz[LI + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_2 + AZz[LI + 2]);
+  AZz[LI + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_3 + AZz[LI + 3]);
+  AZz[LI + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_4 + AZz[LI + 4]);
+  AZz[LI + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_5 + AZz[LI + 5]);
+  AZz[LI + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_6 + AZz[LI + 6]);
+  AZz[LI + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_7 + AZz[LI + 7]);
+  AZz[LI + 7] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[LI + 8] := UInt32(LC);
   end;
-  result := true;
 end;
 
-class procedure TNat256.Mul(const x, y, zz: TCryptoLibUInt32Array);
+class procedure TNat256.Mul(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32);
 var
-  c, x_0, x_i, y_0, y_1, y_2, y_3, y_4, y_5, y_6, y_7: UInt64;
-  i: Int32;
+  LY_0: UInt64;
+  LY_1: UInt64;
+  LY_2: UInt64;
+  LY_3: UInt64;
+  LY_4: UInt64;
+  LY_5: UInt64;
+  LY_6: UInt64;
+  LY_7: UInt64;
+  LC: UInt64;
+  LX_0: UInt64;
+  LX_i: UInt64;
+  LI: Int32;
 begin
-  y_0 := y[0];
-  y_1 := y[1];
-  y_2 := y[2];
-  y_3 := y[3];
-  y_4 := y[4];
-  y_5 := y[5];
-  y_6 := y[6];
-  y_7 := y[7];
-
-  c := 0;
-  x_0 := x[0];
-  c := c + (x_0 * y_0);
-  zz[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_1);
-  zz[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_2);
-  zz[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_3);
-  zz[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_4);
-  zz[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_5);
-  zz[5] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_6);
-  zz[6] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_7);
-  zz[7] := UInt32(c);
-  c := c shr 32;
-  zz[8] := UInt32(c);
-
-  for i := 1 to System.Pred(8) do
+  LY_0 := AY[AYOff + 0];
+  LY_1 := AY[AYOff + 1];
+  LY_2 := AY[AYOff + 2];
+  LY_3 := AY[AYOff + 3];
+  LY_4 := AY[AYOff + 4];
+  LY_5 := AY[AYOff + 5];
+  LY_6 := AY[AYOff + 6];
+  LY_7 := AY[AYOff + 7];
+  begin
+  LC := 0;
+  LX_0 := AX[AXOff + 0];
+  LC := LC + (LX_0 * LY_0);
+  AZz[AZzOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_1);
+  AZz[AZzOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_2);
+  AZz[AZzOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_3);
+  AZz[AZzOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_4);
+  AZz[AZzOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_5);
+  AZz[AZzOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_6);
+  AZz[AZzOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_0 * LY_7);
+  AZz[AZzOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[AZzOff + 8] := UInt32(LC);
+  end;
+  for LI := 1 to (8) - 1 do
   begin
-    c := 0;
-    x_i := x[i];
-    c := c + (x_i * y_0 + zz[i + 0]);
-    zz[i + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[i + 1]);
-    zz[i + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[i + 2]);
-    zz[i + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[i + 3]);
-    zz[i + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[i + 4]);
-    zz[i + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[i + 5]);
-    zz[i + 5] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_6 + zz[i + 6]);
-    zz[i + 6] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_7 + zz[i + 7]);
-    zz[i + 7] := UInt32(c);
-    c := c shr 32;
-    zz[i + 8] := UInt32(c);
+  Inc(AZzOff);
+  LC := 0;
+  LX_i := AX[AXOff + LI];
+  LC := LC + (LX_i * LY_0 + AZz[AZzOff + 0]);
+  AZz[AZzOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_1 + AZz[AZzOff + 1]);
+  AZz[AZzOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_2 + AZz[AZzOff + 2]);
+  AZz[AZzOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_3 + AZz[AZzOff + 3]);
+  AZz[AZzOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_4 + AZz[AZzOff + 4]);
+  AZz[AZzOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_5 + AZz[AZzOff + 5]);
+  AZz[AZzOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_6 + AZz[AZzOff + 6]);
+  AZz[AZzOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_7 + AZz[AZzOff + 7]);
+  AZz[AZzOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[AZzOff + 8] := UInt32(LC);
   end;
 end;
 
-class procedure TNat256.Mul(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const zz: TCryptoLibUInt32Array;
-  zzOff: Int32);
+class procedure TNat256.Mul128(const AX: TCryptoLibUInt32Array; const AY128: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  c, x_0, x_i, y_0, y_1, y_2, y_3, y_4, y_5, y_6, y_7: UInt64;
-  i: Int32;
+  LX_0: UInt64;
+  LX_1: UInt64;
+  LX_2: UInt64;
+  LX_3: UInt64;
+  LX_4: UInt64;
+  LX_5: UInt64;
+  LX_6: UInt64;
+  LX_7: UInt64;
+  LC: UInt64;
+  LY_0: UInt64;
+  LY_i: UInt64;
+  LI: Int32;
 begin
-  y_0 := y[yOff + 0];
-  y_1 := y[yOff + 1];
-  y_2 := y[yOff + 2];
-  y_3 := y[yOff + 3];
-  y_4 := y[yOff + 4];
-  y_5 := y[yOff + 5];
-  y_6 := y[yOff + 6];
-  y_7 := y[yOff + 7];
-
-  c := 0;
-  x_0 := x[xOff + 0];
-  c := c + (x_0 * y_0);
-  zz[zzOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_1);
-  zz[zzOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_2);
-  zz[zzOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_3);
-  zz[zzOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_4);
-  zz[zzOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_5);
-  zz[zzOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_6);
-  zz[zzOff + 6] := UInt32(c);
-  c := c shr 32;
-  c := c + (x_0 * y_7);
-  zz[zzOff + 7] := UInt32(c);
-  c := c shr 32;
-  zz[zzOff + 8] := UInt32(c);
-
-  for i := 1 to System.Pred(8) do
+  LX_0 := AX[0];
+  LX_1 := AX[1];
+  LX_2 := AX[2];
+  LX_3 := AX[3];
+  LX_4 := AX[4];
+  LX_5 := AX[5];
+  LX_6 := AX[6];
+  LX_7 := AX[7];
   begin
-    System.Inc(zzOff);
-    c := 0;
-    x_i := x[xOff + i];
-    c := c + (x_i * y_0 + zz[zzOff + 0]);
-    zz[zzOff + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[zzOff + 1]);
-    zz[zzOff + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[zzOff + 2]);
-    zz[zzOff + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[zzOff + 3]);
-    zz[zzOff + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[zzOff + 4]);
-    zz[zzOff + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[zzOff + 5]);
-    zz[zzOff + 5] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_6 + zz[zzOff + 6]);
-    zz[zzOff + 6] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_7 + zz[zzOff + 7]);
-    zz[zzOff + 7] := UInt32(c);
-    c := c shr 32;
-    zz[zzOff + 8] := UInt32(c);
+  LC := 0;
+  LY_0 := AY128[0];
+  LC := LC + (LY_0 * LX_0);
+  AZz[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_1);
+  AZz[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_2);
+  AZz[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_3);
+  AZz[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_4);
+  AZz[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_5);
+  AZz[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_6);
+  AZz[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_0 * LX_7);
+  AZz[7] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[8] := UInt32(LC);
+  end;
+  for LI := 1 to (4) - 1 do
+  begin
+  LC := 0;
+  LY_i := AY128[LI];
+  LC := LC + (LY_i * LX_0 + AZz[LI + 0]);
+  AZz[LI + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_1 + AZz[LI + 1]);
+  AZz[LI + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_2 + AZz[LI + 2]);
+  AZz[LI + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_3 + AZz[LI + 3]);
+  AZz[LI + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_4 + AZz[LI + 4]);
+  AZz[LI + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_5 + AZz[LI + 5]);
+  AZz[LI + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_6 + AZz[LI + 6]);
+  AZz[LI + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY_i * LX_7 + AZz[LI + 7]);
+  AZz[LI + 7] := UInt32(LC);
+  LC := LC shr 32;
+  AZz[LI + 8] := UInt32(LC);
   end;
 end;
 
-class function TNat256.MulAddTo(const x, y, zz: TCryptoLibUInt32Array): UInt32;
+class function TNat256.MulAddTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array): UInt32;
 var
-  c, x_i, y_0, y_1, y_2, y_3, y_4, y_5, y_6, y_7, zc: UInt64;
-  i: Int32;
+  LY_0: UInt64;
+  LY_1: UInt64;
+  LY_2: UInt64;
+  LY_3: UInt64;
+  LY_4: UInt64;
+  LY_5: UInt64;
+  LY_6: UInt64;
+  LY_7: UInt64;
+  LZc: UInt64;
+  LC: UInt64;
+  LX_i: UInt64;
+  LI: Int32;
 begin
-  y_0 := y[0];
-  y_1 := y[1];
-  y_2 := y[2];
-  y_3 := y[3];
-  y_4 := y[4];
-  y_5 := y[5];
-  y_6 := y[6];
-  y_7 := y[7];
-
-  zc := 0;
-  for i := 0 to System.Pred(8) do
+  LY_0 := AY[0];
+  LY_1 := AY[1];
+  LY_2 := AY[2];
+  LY_3 := AY[3];
+  LY_4 := AY[4];
+  LY_5 := AY[5];
+  LY_6 := AY[6];
+  LY_7 := AY[7];
+  LZc := 0;
+  for LI := 0 to (8) - 1 do
   begin
-    c := 0;
-    x_i := x[i];
-    c := c + (x_i * y_0 + zz[i + 0]);
-    zz[i + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[i + 1]);
-    zz[i + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[i + 2]);
-    zz[i + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[i + 3]);
-    zz[i + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[i + 4]);
-    zz[i + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[i + 5]);
-    zz[i + 5] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_6 + zz[i + 6]);
-    zz[i + 6] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_7 + zz[i + 7]);
-    zz[i + 7] := UInt32(c);
-    c := c shr 32;
-    zc := zc + (c + (zz[i + 8] and M));
-    zz[i + 8] := UInt32(zc);
-    zc := zc shr 32;
+  LC := 0;
+  LX_i := AX[LI];
+  LC := LC + (LX_i * LY_0 + AZz[LI + 0]);
+  AZz[LI + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_1 + AZz[LI + 1]);
+  AZz[LI + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_2 + AZz[LI + 2]);
+  AZz[LI + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_3 + AZz[LI + 3]);
+  AZz[LI + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_4 + AZz[LI + 4]);
+  AZz[LI + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_5 + AZz[LI + 5]);
+  AZz[LI + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_6 + AZz[LI + 6]);
+  AZz[LI + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_7 + AZz[LI + 7]);
+  AZz[LI + 7] := UInt32(LC);
+  LC := LC shr 32;
+  LZc := LZc + (LC + AZz[LI + 8]);
+  AZz[LI + 8] := UInt32(LZc);
+  LZc := LZc shr (32);
   end;
-  result := UInt32(zc);
+  Result := UInt32(LZc);
 end;
 
-class function TNat256.MulAddTo(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const zz: TCryptoLibUInt32Array;
-  zzOff: Int32): UInt32;
+class function TNat256.MulAddTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32): UInt32;
 var
-  c, x_i, y_0, y_1, y_2, y_3, y_4, y_5, y_6, y_7, zc: UInt64;
-  i: Int32;
+  LY_0: UInt64;
+  LY_1: UInt64;
+  LY_2: UInt64;
+  LY_3: UInt64;
+  LY_4: UInt64;
+  LY_5: UInt64;
+  LY_6: UInt64;
+  LY_7: UInt64;
+  LZc: UInt64;
+  LC: UInt64;
+  LX_i: UInt64;
+  LI: Int32;
 begin
-  y_0 := y[yOff + 0];
-  y_1 := y[yOff + 1];
-  y_2 := y[yOff + 2];
-  y_3 := y[yOff + 3];
-  y_4 := y[yOff + 4];
-  y_5 := y[yOff + 5];
-  y_6 := y[yOff + 6];
-  y_7 := y[yOff + 7];
-
-  zc := 0;
-  for i := 0 to System.Pred(8) do
+  LY_0 := AY[AYOff + 0];
+  LY_1 := AY[AYOff + 1];
+  LY_2 := AY[AYOff + 2];
+  LY_3 := AY[AYOff + 3];
+  LY_4 := AY[AYOff + 4];
+  LY_5 := AY[AYOff + 5];
+  LY_6 := AY[AYOff + 6];
+  LY_7 := AY[AYOff + 7];
+  LZc := 0;
+  for LI := 0 to (8) - 1 do
   begin
-    c := 0;
-    x_i := x[xOff + i];
-    c := c + (x_i * y_0 + zz[zzOff + 0]);
-    zz[zzOff + 0] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_1 + zz[zzOff + 1]);
-    zz[zzOff + 1] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_2 + zz[zzOff + 2]);
-    zz[zzOff + 2] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_3 + zz[zzOff + 3]);
-    zz[zzOff + 3] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_4 + zz[zzOff + 4]);
-    zz[zzOff + 4] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_5 + zz[zzOff + 5]);
-    zz[zzOff + 5] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_6 + zz[zzOff + 6]);
-    zz[zzOff + 6] := UInt32(c);
-    c := c shr 32;
-    c := c + (x_i * y_7 + zz[zzOff + 7]);
-    zz[zzOff + 7] := UInt32(c);
-    c := c shr 32;
-    zc := zc + (c + (zz[zzOff + 8] and M));
-    zz[zzOff + 8] := UInt32(zc);
-    zc := zc shr 32;
-    System.Inc(zzOff);
+  LC := 0;
+  LX_i := AX[AXOff + LI];
+  LC := LC + (LX_i * LY_0 + AZz[AZzOff + 0]);
+  AZz[AZzOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_1 + AZz[AZzOff + 1]);
+  AZz[AZzOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_2 + AZz[AZzOff + 2]);
+  AZz[AZzOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_3 + AZz[AZzOff + 3]);
+  AZz[AZzOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_4 + AZz[AZzOff + 4]);
+  AZz[AZzOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_5 + AZz[AZzOff + 5]);
+  AZz[AZzOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_6 + AZz[AZzOff + 6]);
+  AZz[AZzOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX_i * LY_7 + AZz[AZzOff + 7]);
+  AZz[AZzOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  LZc := LZc + (LC + AZz[AZzOff + 8]);
+  AZz[AZzOff + 8] := UInt32(LZc);
+  LZc := LZc shr (32);
+  Inc(AZzOff);
   end;
-  result := UInt32(zc);
+  Result := UInt32(LZc);
 end;
 
-class function TNat256.Mul33Add(w: UInt32; const x: TCryptoLibUInt32Array;
-  xOff: Int32; const y: TCryptoLibUInt32Array; yOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt64;
+class function TNat256.Mul33Add(AW: UInt32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt64;
 var
-  c, wVal, x0, x1, x2, x3, x4, x5, x6, x7: UInt64;
+  LC: UInt64;
+  LWVal: UInt64;
+  LX0: UInt64;
+  LX1: UInt64;
+  LX2: UInt64;
+  LX3: UInt64;
+  LX4: UInt64;
+  LX5: UInt64;
+  LX6: UInt64;
+  LX7: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(w shr 31 = 0);
-{$ENDIF DEBUG}
-  c := 0;
-  wVal := w;
-  x0 := x[xOff + 0];
-  c := c + (wVal * x0 + y[yOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  x1 := x[xOff + 1];
-  c := c + (wVal * x1 + x0 + y[yOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  x2 := x[xOff + 2];
-  c := c + (wVal * x2 + x1 + y[yOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  x3 := x[xOff + 3];
-  c := c + (wVal * x3 + x2 + y[yOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  x4 := x[xOff + 4];
-  c := c + (wVal * x4 + x3 + y[yOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  x5 := x[xOff + 5];
-  c := c + (wVal * x5 + x4 + y[yOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  x6 := x[xOff + 6];
-  c := c + (wVal * x6 + x5 + y[yOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := c shr 32;
-  x7 := x[xOff + 7];
-  c := c + (wVal * x7 + x6 + y[yOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := c shr 32;
-  c := c + x7;
-  result := c;
+  System.Assert(AW shr 31 = 0);
+  LC := 0;
+  LWVal := AW;
+  LX0 := AX[AXOff + 0];
+  LC := LC + (LWVal * LX0 + AY[AYOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LX1 := AX[AXOff + 1];
+  LC := LC + (LWVal * LX1 + LX0 + AY[AYOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LX2 := AX[AXOff + 2];
+  LC := LC + (LWVal * LX2 + LX1 + AY[AYOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LX3 := AX[AXOff + 3];
+  LC := LC + (LWVal * LX3 + LX2 + AY[AYOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LX4 := AX[AXOff + 4];
+  LC := LC + (LWVal * LX4 + LX3 + AY[AYOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LX5 := AX[AXOff + 5];
+  LC := LC + (LWVal * LX5 + LX4 + AY[AYOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LX6 := AX[AXOff + 6];
+  LC := LC + (LWVal * LX6 + LX5 + AY[AYOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LX7 := AX[AXOff + 7];
+  LC := LC + (LWVal * LX7 + LX6 + AY[AYOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LX7);
+  Result := LC;
 end;
 
-class function TNat256.MulByWord(x: UInt32;
-  const z: TCryptoLibUInt32Array): UInt32;
+class function TNat256.MulByWord(AX: UInt32; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c, xVal: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
 begin
-  c := 0;
-  xVal := x;
-  c := c + (xVal * UInt64(z[0]));
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[1]));
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[2]));
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[3]));
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[4]));
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[5]));
-  z[5] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[6]));
-  z[6] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[7]));
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * UInt64(AZ[0]));
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[1]));
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[2]));
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[3]));
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[4]));
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[5]));
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[6]));
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[7]));
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.MulByWordAddTo(x: UInt32;
-  const y, z: TCryptoLibUInt32Array): UInt32;
+class function TNat256.MulByWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32;
 var
-  c, xVal: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
 begin
-  c := 0;
-  xVal := x;
-  c := c + (xVal * UInt64(z[0]) + y[0]);
-  z[0] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[1]) + y[1]);
-  z[1] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[2]) + y[2]);
-  z[2] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[3]) + y[3]);
-  z[3] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[4]) + y[4]);
-  z[4] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[5]) + y[5]);
-  z[5] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[6]) + y[6]);
-  z[6] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * UInt64(z[7]) + y[7]);
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * UInt64(AZ[0]) + AY[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[1]) + AY[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[2]) + AY[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[3]) + AY[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[4]) + AY[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[5]) + AY[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[6]) + AY[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * UInt64(AZ[7]) + AY[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.MulWordAddTo(x: UInt32; const y: TCryptoLibUInt32Array;
-  yOff: Int32; const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat256.MulWordAddTo(AX: UInt32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
 begin
-  c := 0;
-  xVal := x;
-  c := c + (xVal * y[yOff + 0] + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 1] + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 2] + z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 3] + z[zOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 4] + z[zOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 5] + z[zOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 6] + z[zOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * y[yOff + 7] + z[zOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * AY[AYOff + 0] + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 1] + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 2] + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 3] + AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 4] + AZ[AZOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 5] + AZ[AZOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 6] + AZ[AZOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * AY[AYOff + 7] + AZ[AZOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := UInt32(LC);
 end;
 
-class function TNat256.Mul33DWordAdd(x: UInt32; y: UInt64;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat256.Mul33DWordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal, y00, y01: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
+  LY00: UInt64;
+  LY01: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(x shr 31 = 0);
-  System.Assert(zOff <= 4);
-{$ENDIF DEBUG}
-  c := 0;
-  xVal := x;
-  y00 := y and M;
-  c := c + (xVal * y00 + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  y01 := y shr 32;
-  c := c + (xVal * y01 + y00 + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (y01 + z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  c := c + (z[zOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := c shr 32;
-  if c = 0 then
+  {$IFDEF DEBUG}
+  System.Assert(AX shr 31 = 0);
+  System.Assert(AZOff <= 4);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LY00 := AY and M;
+  LC := LC + (LXVal * LY00 + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LY01 := AY shr 32;
+  LC := LC + (LXVal * LY01 + LY00 + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LY01 + AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  if (LC = 0) then
   begin
-    result := 0;
+    Result := 0;
   end
   else
   begin
-    result := TNat.IncAt(8, z, zOff, 4);
+    Result := TNat.IncAt(8, AZ, AZOff, 4);
   end;
 end;
 
-class function TNat256.Mul33WordAdd(x, y: UInt32;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat256.Mul33WordAdd(AX: UInt32; AY: UInt32; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, yVal: UInt64;
+  LC: UInt64;
+  LYVal: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(x shr 31 = 0);
-  System.Assert(zOff <= 5);
-{$ENDIF DEBUG}
-  c := 0;
-  yVal := y;
-  c := c + (yVal * x + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (yVal + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  if c = 0 then
+  {$IFDEF DEBUG}
+  System.Assert(AX shr 31 = 0);
+  System.Assert(AZOff <= 5);
+  {$ENDIF}
+  LC := 0;
+  LYVal := AY;
+  LC := LC + (LYVal * AX + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LYVal + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  if (LC = 0) then
   begin
-    result := 0;
+    Result := 0;
   end
   else
   begin
-    result := TNat.IncAt(8, z, zOff, 3);
+    Result := TNat.IncAt(8, AZ, AZOff, 3);
   end;
 end;
 
-class function TNat256.MulWordDwordAdd(x: UInt32; y: UInt64;
-  const z: TCryptoLibUInt32Array; zOff: Int32): UInt32;
+class function TNat256.MulWordDwordAdd(AX: UInt32; AY: UInt64; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal: UInt64;
+  LC: UInt64;
+  LXVal: UInt64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(zOff <= 5);
-{$ENDIF DEBUG}
-  c := 0;
-  xVal := x;
-  c := c + (xVal * y + z[zOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := c shr 32;
-  c := c + (xVal * (y shr 32) + z[zOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := c shr 32;
-  c := c + (z[zOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := c shr 32;
-  if c = 0 then
+  {$IFDEF DEBUG}
+  System.Assert(AZOff <= 5);
+  {$ENDIF}
+  LC := 0;
+  LXVal := AX;
+  LC := LC + (LXVal * AY + AZ[AZOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (LXVal * (AY shr 32) + AZ[AZOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (AZ[AZOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  if (LC = 0) then
   begin
-    result := 0;
+    Result := 0;
   end
   else
   begin
-    result := TNat.IncAt(8, z, zOff, 3);
+    Result := TNat.IncAt(8, AZ, AZOff, 3);
   end;
 end;
 
-class function TNat256.MulWord(x: UInt32; const y, z: TCryptoLibUInt32Array;
-  zOff: Int32): UInt32;
+class function TNat256.MulWord(AX: UInt32; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; AZOff: Int32): UInt32;
 var
-  c, xVal: UInt64;
-  i: Int32;
+  LC: UInt64;
+  LXVal: UInt64;
+  LI: Int32;
 begin
-  c := 0;
-  xVal := x;
-  i := 0;
-  repeat
-    c := c + (xVal * y[i]);
-    z[zOff + i] := UInt32(c);
-    c := c shr 32;
-    System.Inc(i);
-  until not(i < 8);
-  result := UInt32(c);
+  LC := 0;
+  LXVal := AX;
+  LI := 0;
+  while LI < 8 do
+  begin
+    LC := LC + (LXVal * AY[LI]);
+    AZ[AZOff + LI] := UInt32(LC);
+    LC := LC shr 32;
+    Inc(LI);
+  end;
+  Result := UInt32(LC);
 end;
 
-class procedure TNat256.Square(const x, zz: TCryptoLibUInt32Array);
+class procedure TNat256.Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  x_0, zz_1, xVal, p, x_1, zz_2, x_2, zz_3, zz_4, x_3, zz_5, zz_6, x_4, zz_7,
-    zz_8, x_5, zz_9, zz_10, x_6, zz_11, zz_12, x_7, zz_13, zz_14: UInt64;
-  c, w: UInt32;
-  i, j: Int32;
+  LX_0: UInt64;
+  LZz_1: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI: Int32;
+  LJ: Int32;
+  LXVal: UInt64;
+  LP: UInt64;
+  LX_1: UInt64;
+  LZz_2: UInt64;
+  LX_2: UInt64;
+  LZz_3: UInt64;
+  LZz_4: UInt64;
+  LX_3: UInt64;
+  LZz_5: UInt64;
+  LZz_6: UInt64;
+  LX_4: UInt64;
+  LZz_7: UInt64;
+  LZz_8: UInt64;
+  LX_5: UInt64;
+  LZz_9: UInt64;
+  LZz_10: UInt64;
+  LX_6: UInt64;
+  LZz_11: UInt64;
+  LZz_12: UInt64;
+  LX_7: UInt64;
+  LZz_13: UInt64;
+  LZz_14: UInt64;
 begin
-  x_0 := x[0];
-  c := 0;
-  i := 7;
-  j := 16;
-
-  repeat
-    xVal := x[i];
-    System.Dec(i);
-    p := xVal * xVal;
-    System.Dec(j);
-    zz[j] := (c shl 31) or UInt32(p shr 33);
-    System.Dec(j);
-    zz[j] := UInt32(p shr 1);
-    c := UInt32(p);
-  until not(i > 0);
-
-  p := x_0 * x_0;
-  zz_1 := UInt64(c shl 31) or (p shr 33);
-  zz[0] := UInt32(p);
-  c := UInt32(p shr 32) and 1;
-
-  x_1 := x[1];
-  zz_2 := zz[2];
-
-  zz_1 := zz_1 + (x_1 * x_0);
-  w := UInt32(zz_1);
-  zz[1] := (w shl 1) or c;
-  c := w shr 31;
-  zz_2 := zz_2 + (zz_1 shr 32);
-
-  x_2 := x[2];
-  zz_3 := zz[3];
-  zz_4 := zz[4];
-
-  zz_2 := zz_2 + (x_2 * x_0);
-  w := UInt32(zz_2);
-  zz[2] := (w shl 1) or c;
-  c := w shr 31;
-  zz_3 := zz_3 + ((zz_2 shr 32) + x_2 * x_1);
-  zz_4 := zz_4 + (zz_3 shr 32);
-  zz_3 := zz_3 and M;
-
-  x_3 := x[3];
-  zz_5 := zz[5] + (zz_4 shr 32);
-  zz_4 := zz_4 and M;
-  zz_6 := zz[6] + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  zz_3 := zz_3 + (x_3 * x_0);
-  w := UInt32(zz_3);
-  zz[3] := (w shl 1) or c;
-  c := w shr 31;
-  zz_4 := zz_4 + ((zz_3 shr 32) + x_3 * x_1);
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_3 * x_2);
-  zz_4 := zz_4 and M;
-  zz_6 := zz_6 + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  x_4 := x[4];
-  zz_7 := zz[7] + (zz_6 shr 32);
-  zz_6 := zz_6 and M;
-  zz_8 := zz[8] + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  zz_4 := zz_4 + (x_4 * x_0);
-  w := UInt32(zz_4);
-  zz[4] := (w shl 1) or c;
-  c := w shr 31;
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_4 * x_1);
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_4 * x_2);
-  zz_5 := zz_5 and M;
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_4 * x_3);
-  zz_6 := zz_6 and M;
-  zz_8 := zz_8 + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  x_5 := x[5];
-  zz_9 := zz[9] + (zz_8 shr 32);
-  zz_8 := zz_8 and M;
-  zz_10 := zz[10] + (zz_9 shr 32);
-  zz_9 := zz_9 and M;
-
-  zz_5 := zz_5 + (x_5 * x_0);
-  w := UInt32(zz_5);
-  zz[5] := (w shl 1) or c;
-  c := w shr 31;
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_5 * x_1);
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_5 * x_2);
-  zz_6 := zz_6 and M;
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_5 * x_3);
-  zz_7 := zz_7 and M;
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_5 * x_4);
-  zz_8 := zz_8 and M;
-  zz_10 := zz_10 + (zz_9 shr 32);
-  zz_9 := zz_9 and M;
-
-  x_6 := x[6];
-  zz_11 := zz[11] + (zz_10 shr 32);
-  zz_10 := zz_10 and M;
-  zz_12 := zz[12] + (zz_11 shr 32);
-  zz_11 := zz_11 and M;
-
-  zz_6 := zz_6 + (x_6 * x_0);
-  w := UInt32(zz_6);
-  zz[6] := (w shl 1) or c;
-  c := w shr 31;
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_6 * x_1);
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_6 * x_2);
-  zz_7 := zz_7 and M;
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_6 * x_3);
-  zz_8 := zz_8 and M;
-  zz_10 := zz_10 + ((zz_9 shr 32) + x_6 * x_4);
-  zz_9 := zz_9 and M;
-  zz_11 := zz_11 + ((zz_10 shr 32) + x_6 * x_5);
-  zz_10 := zz_10 and M;
-  zz_12 := zz_12 + (zz_11 shr 32);
-  zz_11 := zz_11 and M;
-
-  x_7 := x[7];
-  zz_13 := zz[13] + (zz_12 shr 32);
-  zz_12 := zz_12 and M;
-  zz_14 := zz[14] + (zz_13 shr 32);
-  zz_13 := zz_13 and M;
-
-  zz_7 := zz_7 + (x_7 * x_0);
-  w := UInt32(zz_7);
-  zz[7] := (w shl 1) or c;
-  c := w shr 31;
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_7 * x_1);
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_7 * x_2);
-  zz_10 := zz_10 + ((zz_9 shr 32) + x_7 * x_3);
-  zz_11 := zz_11 + ((zz_10 shr 32) + x_7 * x_4);
-  zz_12 := zz_12 + ((zz_11 shr 32) + x_7 * x_5);
-  zz_13 := zz_13 + ((zz_12 shr 32) + x_7 * x_6);
-  zz_14 := zz_14 + (zz_13 shr 32);
-
-  w := UInt32(zz_8);
-  zz[8] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_9);
-  zz[9] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_10);
-  zz[10] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_11);
-  zz[11] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_12);
-  zz[12] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_13);
-  zz[13] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_14);
-  zz[14] := (w shl 1) or c;
-  c := w shr 31;
-  w := zz[15] + UInt32(zz_14 shr 32);
-  zz[15] := (w shl 1) or c;
+  LX_0 := AX[0];
+  LC := 0;
+  LI := 7;
+  LJ := 16;
+  while LI > 0 do
+  begin
+    LXVal := AX[LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZz[LJ] := (LC shl 31) or UInt32(LP shr 33);
+    Dec(LJ);
+    AZz[LJ] := UInt32(LP shr 1);
+    LC := UInt32(LP);
+  end;
+  LP := LX_0 * LX_0;
+  LZz_1 := UInt64(LC shl 31) or (LP shr 33);
+  AZz[0] := UInt32(LP);
+  LC := UInt32(LP shr 32) and 1;
+  LX_1 := AX[1];
+  LZz_2 := AZz[2];
+  begin
+  LZz_1 := LZz_1 + (LX_1 * LX_0);
+  LW := UInt32(LZz_1);
+  AZz[1] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_2 := LZz_2 + (LZz_1  shr 32);
+  end;
+  LX_2 := AX[2];
+  LZz_3 := AZz[3];
+  LZz_4 := AZz[4];
+  begin
+  LZz_2 := LZz_2 + (LX_2 * LX_0);
+  LW := UInt32(LZz_2);
+  AZz[2] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_3 := LZz_3 + ((LZz_2  shr 32) + LX_2 * LX_1);
+  LZz_4 := LZz_4 + (LZz_3  shr 32);
+  LZz_3 := LZz_3 and M;
+  end;
+  LX_3 := AX[3];
+  LZz_5 := AZz[5] + (LZz_4 shr 32); LZz_4 := LZz_4 and M;
+  LZz_6 := AZz[6] + (LZz_5 shr 32); LZz_5 := LZz_5 and M;
+  begin
+  LZz_3 := LZz_3 + (LX_3 * LX_0);
+  LW := UInt32(LZz_3);
+  AZz[3] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_4 := LZz_4 + ((LZz_3  shr 32) + LX_3 * LX_1);
+  LZz_5 := LZz_5 + ((LZz_4  shr 32) + LX_3 * LX_2);
+  LZz_4 := LZz_4 and M;
+  LZz_6 := LZz_6 + (LZz_5  shr 32);
+  LZz_5 := LZz_5 and M;
+  end;
+  LX_4 := AX[4];
+  LZz_7 := AZz[7] + (LZz_6 shr 32); LZz_6 := LZz_6 and M;
+  LZz_8 := AZz[8] + (LZz_7 shr 32); LZz_7 := LZz_7 and M;
+  begin
+  LZz_4 := LZz_4 + (LX_4 * LX_0);
+  LW := UInt32(LZz_4);
+  AZz[4] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_5 := LZz_5 + ((LZz_4  shr 32) + LX_4 * LX_1);
+  LZz_6 := LZz_6 + ((LZz_5  shr 32) + LX_4 * LX_2);
+  LZz_5 := LZz_5 and M;
+  LZz_7 := LZz_7 + ((LZz_6  shr 32) + LX_4 * LX_3);
+  LZz_6 := LZz_6 and M;
+  LZz_8 := LZz_8 + (LZz_7  shr 32);
+  LZz_7 := LZz_7 and M;
+  end;
+  LX_5 := AX[5];
+  LZz_9 := AZz[9] + (LZz_8 shr 32); LZz_8 := LZz_8 and M;
+  LZz_10 := AZz[10] + (LZz_9 shr 32); LZz_9 := LZz_9 and M;
+  begin
+  LZz_5 := LZz_5 + (LX_5 * LX_0);
+  LW := UInt32(LZz_5);
+  AZz[5] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_6 := LZz_6 + ((LZz_5  shr 32) + LX_5 * LX_1);
+  LZz_7 := LZz_7 + ((LZz_6  shr 32) + LX_5 * LX_2);
+  LZz_6 := LZz_6 and M;
+  LZz_8 := LZz_8 + ((LZz_7  shr 32) + LX_5 * LX_3);
+  LZz_7 := LZz_7 and M;
+  LZz_9 := LZz_9 + ((LZz_8  shr 32) + LX_5 * LX_4);
+  LZz_8 := LZz_8 and M;
+  LZz_10 := LZz_10 + (LZz_9  shr 32);
+  LZz_9 := LZz_9 and M;
+  end;
+  LX_6 := AX[6];
+  LZz_11 := AZz[11] + (LZz_10 shr 32); LZz_10 := LZz_10 and M;
+  LZz_12 := AZz[12] + (LZz_11 shr 32); LZz_11 := LZz_11 and M;
+  begin
+  LZz_6 := LZz_6 + (LX_6 * LX_0);
+  LW := UInt32(LZz_6);
+  AZz[6] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_7 := LZz_7 + ((LZz_6  shr 32) + LX_6 * LX_1);
+  LZz_8 := LZz_8 + ((LZz_7  shr 32) + LX_6 * LX_2);
+  LZz_7 := LZz_7 and M;
+  LZz_9 := LZz_9 + ((LZz_8  shr 32) + LX_6 * LX_3);
+  LZz_8 := LZz_8 and M;
+  LZz_10 := LZz_10 + ((LZz_9  shr 32) + LX_6 * LX_4);
+  LZz_9 := LZz_9 and M;
+  LZz_11 := LZz_11 + ((LZz_10  shr 32) + LX_6 * LX_5);
+  LZz_10 := LZz_10 and M;
+  LZz_12 := LZz_12 + (LZz_11  shr 32);
+  LZz_11 := LZz_11 and M;
+  end;
+  LX_7 := AX[7];
+  LZz_13 := AZz[13] + (LZz_12 shr 32); LZz_12 := LZz_12 and M;
+  LZz_14 := AZz[14] + (LZz_13 shr 32); LZz_13 := LZz_13 and M;
+  begin
+  LZz_7 := LZz_7 + (LX_7 * LX_0);
+  LW := UInt32(LZz_7);
+  AZz[7] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_8 := LZz_8 + ((LZz_7  shr 32) + LX_7 * LX_1);
+  LZz_9 := LZz_9 + ((LZz_8  shr 32) + LX_7 * LX_2);
+  LZz_10 := LZz_10 + ((LZz_9  shr 32) + LX_7 * LX_3);
+  LZz_11 := LZz_11 + ((LZz_10  shr 32) + LX_7 * LX_4);
+  LZz_12 := LZz_12 + ((LZz_11  shr 32) + LX_7 * LX_5);
+  LZz_13 := LZz_13 + ((LZz_12  shr 32) + LX_7 * LX_6);
+  LZz_14 := LZz_14 + (LZz_13  shr 32);
+  end;
+  LW := UInt32(LZz_8);
+  AZz[8] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_9);
+  AZz[9] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_10);
+  AZz[10] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_11);
+  AZz[11] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_12);
+  AZz[12] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_13);
+  AZz[13] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_14);
+  AZz[14] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := AZz[15] + UInt32(LZz_14  shr 32);
+  AZz[15] := (LW  shl 1)  or LC;
 end;
 
-class procedure TNat256.Square(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const zz: TCryptoLibUInt32Array; zzOff: Int32);
+class procedure TNat256.Square(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZz: TCryptoLibUInt32Array; AZzOff: Int32);
 var
-  x_0, zz_1, xVal, p, x_1, zz_2, x_2, zz_3, zz_4, x_3, zz_5, zz_6, x_4, zz_7,
-    zz_8, x_5, zz_9, zz_10, x_6, zz_11, zz_12, x_7, zz_13, zz_14: UInt64;
-  c, w: UInt32;
-  i, j: Int32;
+  LX_0: UInt64;
+  LZz_1: UInt64;
+  LC: UInt32;
+  LW: UInt32;
+  LI: Int32;
+  LJ: Int32;
+  LXVal: UInt64;
+  LP: UInt64;
+  LX_1: UInt64;
+  LZz_2: UInt64;
+  LX_2: UInt64;
+  LZz_3: UInt64;
+  LZz_4: UInt64;
+  LX_3: UInt64;
+  LZz_5: UInt64;
+  LZz_6: UInt64;
+  LX_4: UInt64;
+  LZz_7: UInt64;
+  LZz_8: UInt64;
+  LX_5: UInt64;
+  LZz_9: UInt64;
+  LZz_10: UInt64;
+  LX_6: UInt64;
+  LZz_11: UInt64;
+  LZz_12: UInt64;
+  LX_7: UInt64;
+  LZz_13: UInt64;
+  LZz_14: UInt64;
 begin
-  x_0 := x[xOff + 0];
-  c := 0;
-  i := 7;
-  j := 16;
-
-  repeat
-    xVal := x[xOff + i];
-    System.Dec(i);
-    p := xVal * xVal;
-    System.Dec(j);
-    zz[zzOff + j] := (c shl 31) or UInt32(p shr 33);
-    System.Dec(j);
-    zz[zzOff + j] := UInt32(p shr 1);
-    c := UInt32(p);
-  until not(i > 0);
-
-  p := x_0 * x_0;
-  zz_1 := UInt64(c shl 31) or (p shr 33);
-  zz[zzOff + 0] := UInt32(p);
-  c := UInt32(p shr 32) and 1;
-
-  x_1 := x[xOff + 1];
-  zz_2 := zz[zzOff + 2];
-
-  zz_1 := zz_1 + (x_1 * x_0);
-  w := UInt32(zz_1);
-  zz[zzOff + 1] := (w shl 1) or c;
-  c := w shr 31;
-  zz_2 := zz_2 + (zz_1 shr 32);
-
-  x_2 := x[xOff + 2];
-  zz_3 := zz[zzOff + 3];
-  zz_4 := zz[zzOff + 4];
-
-  zz_2 := zz_2 + (x_2 * x_0);
-  w := UInt32(zz_2);
-  zz[zzOff + 2] := (w shl 1) or c;
-  c := w shr 31;
-  zz_3 := zz_3 + ((zz_2 shr 32) + x_2 * x_1);
-  zz_4 := zz_4 + (zz_3 shr 32);
-  zz_3 := zz_3 and M;
-
-  x_3 := x[xOff + 3];
-  zz_5 := zz[zzOff + 5] + (zz_4 shr 32);
-  zz_4 := zz_4 and M;
-  zz_6 := zz[zzOff + 6] + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  zz_3 := zz_3 + (x_3 * x_0);
-  w := UInt32(zz_3);
-  zz[zzOff + 3] := (w shl 1) or c;
-  c := w shr 31;
-  zz_4 := zz_4 + ((zz_3 shr 32) + x_3 * x_1);
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_3 * x_2);
-  zz_4 := zz_4 and M;
-  zz_6 := zz_6 + (zz_5 shr 32);
-  zz_5 := zz_5 and M;
-
-  x_4 := x[xOff + 4];
-  zz_7 := zz[zzOff + 7] + (zz_6 shr 32);
-  zz_6 := zz_6 and M;
-  zz_8 := zz[zzOff + 8] + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  zz_4 := zz_4 + (x_4 * x_0);
-  w := UInt32(zz_4);
-  zz[zzOff + 4] := (w shl 1) or c;
-  c := w shr 31;
-  zz_5 := zz_5 + ((zz_4 shr 32) + x_4 * x_1);
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_4 * x_2);
-  zz_5 := zz_5 and M;
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_4 * x_3);
-  zz_6 := zz_6 and M;
-  zz_8 := zz_8 + (zz_7 shr 32);
-  zz_7 := zz_7 and M;
-
-  x_5 := x[xOff + 5];
-  zz_9 := zz[zzOff + 9] + (zz_8 shr 32);
-  zz_8 := zz_8 and M;
-  zz_10 := zz[zzOff + 10] + (zz_9 shr 32);
-  zz_9 := zz_9 and M;
-
-  zz_5 := zz_5 + (x_5 * x_0);
-  w := UInt32(zz_5);
-  zz[zzOff + 5] := (w shl 1) or c;
-  c := w shr 31;
-  zz_6 := zz_6 + ((zz_5 shr 32) + x_5 * x_1);
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_5 * x_2);
-  zz_6 := zz_6 and M;
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_5 * x_3);
-  zz_7 := zz_7 and M;
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_5 * x_4);
-  zz_8 := zz_8 and M;
-  zz_10 := zz_10 + (zz_9 shr 32);
-  zz_9 := zz_9 and M;
-
-  x_6 := x[xOff + 6];
-  zz_11 := zz[zzOff + 11] + (zz_10 shr 32);
-  zz_10 := zz_10 and M;
-  zz_12 := zz[zzOff + 12] + (zz_11 shr 32);
-  zz_11 := zz_11 and M;
-
-  zz_6 := zz_6 + (x_6 * x_0);
-  w := UInt32(zz_6);
-  zz[zzOff + 6] := (w shl 1) or c;
-  c := w shr 31;
-  zz_7 := zz_7 + ((zz_6 shr 32) + x_6 * x_1);
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_6 * x_2);
-  zz_7 := zz_7 and M;
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_6 * x_3);
-  zz_8 := zz_8 and M;
-  zz_10 := zz_10 + ((zz_9 shr 32) + x_6 * x_4);
-  zz_9 := zz_9 and M;
-  zz_11 := zz_11 + ((zz_10 shr 32) + x_6 * x_5);
-  zz_10 := zz_10 and M;
-  zz_12 := zz_12 + (zz_11 shr 32);
-  zz_11 := zz_11 and M;
-
-  x_7 := x[xOff + 7];
-  zz_13 := zz[zzOff + 13] + (zz_12 shr 32);
-  zz_12 := zz_12 and M;
-  zz_14 := zz[zzOff + 14] + (zz_13 shr 32);
-  zz_13 := zz_13 and M;
-
-  zz_7 := zz_7 + (x_7 * x_0);
-  w := UInt32(zz_7);
-  zz[zzOff + 7] := (w shl 1) or c;
-  c := w shr 31;
-  zz_8 := zz_8 + ((zz_7 shr 32) + x_7 * x_1);
-  zz_9 := zz_9 + ((zz_8 shr 32) + x_7 * x_2);
-  zz_10 := zz_10 + ((zz_9 shr 32) + x_7 * x_3);
-  zz_11 := zz_11 + ((zz_10 shr 32) + x_7 * x_4);
-  zz_12 := zz_12 + ((zz_11 shr 32) + x_7 * x_5);
-  zz_13 := zz_13 + ((zz_12 shr 32) + x_7 * x_6);
-  zz_14 := zz_14 + (zz_13 shr 32);
-
-  w := UInt32(zz_8);
-  zz[zzOff + 8] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_9);
-  zz[zzOff + 9] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_10);
-  zz[zzOff + 10] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_11);
-  zz[zzOff + 11] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_12);
-  zz[zzOff + 12] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_13);
-  zz[zzOff + 13] := (w shl 1) or c;
-  c := w shr 31;
-  w := UInt32(zz_14);
-  zz[zzOff + 14] := (w shl 1) or c;
-  c := w shr 31;
-  w := zz[zzOff + 15] + UInt32(zz_14 shr 32);
-  zz[zzOff + 15] := (w shl 1) or c;
+  LX_0 := AX[AXOff + 0];
+  LC := 0;
+  LI := 7;
+  LJ := 16;
+  while LI > 0 do
+  begin
+    LXVal := AX[AXOff + LI];
+    Dec(LI);
+    LP := LXVal * LXVal;
+    Dec(LJ);
+    AZz[AZzOff + LJ] := (LC shl 31) or UInt32(LP shr 33);
+    Dec(LJ);
+    AZz[AZzOff + LJ] := UInt32(LP shr 1);
+    LC := UInt32(LP);
+  end;
+  LP := LX_0 * LX_0;
+  LZz_1 := UInt64(LC shl 31) or (LP shr 33);
+  AZz[AZzOff + 0] := UInt32(LP);
+  LC := UInt32(LP shr 32) and 1;
+  LX_1 := AX[AXOff + 1];
+  LZz_2 := AZz[AZzOff + 2];
+  begin
+  LZz_1 := LZz_1 + (LX_1 * LX_0);
+  LW := UInt32(LZz_1);
+  AZz[AZzOff + 1] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_2 := LZz_2 + (LZz_1  shr 32);
+  end;
+  LX_2 := AX[AXOff + 2];
+  LZz_3 := AZz[AZzOff + 3];
+  LZz_4 := AZz[AZzOff + 4];
+  begin
+  LZz_2 := LZz_2 + (LX_2 * LX_0);
+  LW := UInt32(LZz_2);
+  AZz[AZzOff + 2] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_3 := LZz_3 + ((LZz_2  shr 32) + LX_2 * LX_1);
+  LZz_4 := LZz_4 + (LZz_3  shr 32);
+  LZz_3 := LZz_3 and M;
+  end;
+  LX_3 := AX[AXOff + 3];
+  LZz_5 := AZz[AZzOff + 5] + (LZz_4 shr 32); LZz_4 := LZz_4 and M;
+  LZz_6 := AZz[AZzOff + 6] + (LZz_5 shr 32); LZz_5 := LZz_5 and M;
+  begin
+  LZz_3 := LZz_3 + (LX_3 * LX_0);
+  LW := UInt32(LZz_3);
+  AZz[AZzOff + 3] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_4 := LZz_4 + ((LZz_3  shr 32) + LX_3 * LX_1);
+  LZz_5 := LZz_5 + ((LZz_4  shr 32) + LX_3 * LX_2);
+  LZz_4 := LZz_4 and M;
+  LZz_6 := LZz_6 + (LZz_5  shr 32);
+  LZz_5 := LZz_5 and M;
+  end;
+  LX_4 := AX[AXOff + 4];
+  LZz_7 := AZz[AZzOff + 7] + (LZz_6 shr 32); LZz_6 := LZz_6 and M;
+  LZz_8 := AZz[AZzOff + 8] + (LZz_7 shr 32); LZz_7 := LZz_7 and M;
+  begin
+  LZz_4 := LZz_4 + (LX_4 * LX_0);
+  LW := UInt32(LZz_4);
+  AZz[AZzOff + 4] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_5 := LZz_5 + ((LZz_4  shr 32) + LX_4 * LX_1);
+  LZz_6 := LZz_6 + ((LZz_5  shr 32) + LX_4 * LX_2);
+  LZz_5 := LZz_5 and M;
+  LZz_7 := LZz_7 + ((LZz_6  shr 32) + LX_4 * LX_3);
+  LZz_6 := LZz_6 and M;
+  LZz_8 := LZz_8 + (LZz_7  shr 32);
+  LZz_7 := LZz_7 and M;
+  end;
+  LX_5 := AX[AXOff + 5];
+  LZz_9 := AZz[AZzOff + 9] + (LZz_8 shr 32); LZz_8 := LZz_8 and M;
+  LZz_10 := AZz[AZzOff + 10] + (LZz_9 shr 32); LZz_9 := LZz_9 and M;
+  begin
+  LZz_5 := LZz_5 + (LX_5 * LX_0);
+  LW := UInt32(LZz_5);
+  AZz[AZzOff + 5] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_6 := LZz_6 + ((LZz_5  shr 32) + LX_5 * LX_1);
+  LZz_7 := LZz_7 + ((LZz_6  shr 32) + LX_5 * LX_2);
+  LZz_6 := LZz_6 and M;
+  LZz_8 := LZz_8 + ((LZz_7  shr 32) + LX_5 * LX_3);
+  LZz_7 := LZz_7 and M;
+  LZz_9 := LZz_9 + ((LZz_8  shr 32) + LX_5 * LX_4);
+  LZz_8 := LZz_8 and M;
+  LZz_10 := LZz_10 + (LZz_9  shr 32);
+  LZz_9 := LZz_9 and M;
+  end;
+  LX_6 := AX[AXOff + 6];
+  LZz_11 := AZz[AZzOff + 11] + (LZz_10 shr 32); LZz_10 := LZz_10 and M;
+  LZz_12 := AZz[AZzOff + 12] + (LZz_11 shr 32); LZz_11 := LZz_11 and M;
+  begin
+  LZz_6 := LZz_6 + (LX_6 * LX_0);
+  LW := UInt32(LZz_6);
+  AZz[AZzOff + 6] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_7 := LZz_7 + ((LZz_6  shr 32) + LX_6 * LX_1);
+  LZz_8 := LZz_8 + ((LZz_7  shr 32) + LX_6 * LX_2);
+  LZz_7 := LZz_7 and M;
+  LZz_9 := LZz_9 + ((LZz_8  shr 32) + LX_6 * LX_3);
+  LZz_8 := LZz_8 and M;
+  LZz_10 := LZz_10 + ((LZz_9  shr 32) + LX_6 * LX_4);
+  LZz_9 := LZz_9 and M;
+  LZz_11 := LZz_11 + ((LZz_10  shr 32) + LX_6 * LX_5);
+  LZz_10 := LZz_10 and M;
+  LZz_12 := LZz_12 + (LZz_11  shr 32);
+  LZz_11 := LZz_11 and M;
+  end;
+  LX_7 := AX[AXOff + 7];
+  LZz_13 := AZz[AZzOff + 13] + (LZz_12 shr 32); LZz_12 := LZz_12 and M;
+  LZz_14 := AZz[AZzOff + 14] + (LZz_13 shr 32); LZz_13 := LZz_13 and M;
+  begin
+  LZz_7 := LZz_7 + (LX_7 * LX_0);
+  LW := UInt32(LZz_7);
+  AZz[AZzOff + 7] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LZz_8 := LZz_8 + ((LZz_7  shr 32) + LX_7 * LX_1);
+  LZz_9 := LZz_9 + ((LZz_8  shr 32) + LX_7 * LX_2);
+  LZz_10 := LZz_10 + ((LZz_9  shr 32) + LX_7 * LX_3);
+  LZz_11 := LZz_11 + ((LZz_10  shr 32) + LX_7 * LX_4);
+  LZz_12 := LZz_12 + ((LZz_11  shr 32) + LX_7 * LX_5);
+  LZz_13 := LZz_13 + ((LZz_12  shr 32) + LX_7 * LX_6);
+  LZz_14 := LZz_14 + (LZz_13  shr 32);
+  end;
+  LW := UInt32(LZz_8);
+  AZz[AZzOff + 8] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_9);
+  AZz[AZzOff + 9] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_10);
+  AZz[AZzOff + 10] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_11);
+  AZz[AZzOff + 11] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_12);
+  AZz[AZzOff + 12] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_13);
+  AZz[AZzOff + 13] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := UInt32(LZz_14);
+  AZz[AZzOff + 14] := (LW  shl 1)  or LC;
+  LC := LW  shr 31;
+  LW := AZz[AZzOff + 15] + UInt32(LZz_14  shr 32);
+  AZz[AZzOff + 15] := (LW  shl 1)  or LC;
 end;
 
-class function TNat256.Sub(const x, y, z: TCryptoLibUInt32Array): Int32;
+class function TNat256.Sub(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(x[0]) - y[0]);
-  z[0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[1]) - y[1]);
-  z[1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[2]) - y[2]);
-  z[2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[3]) - y[3]);
-  z[3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[4]) - y[4]);
-  z[4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[5]) - y[5]);
-  z[5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[6]) - y[6]);
-  z[6] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[7]) - y[7]);
-  z[7] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AX[0]) - AY[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[1]) - AY[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[2]) - AY[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[3]) - AY[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[4]) - AY[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[5]) - AY[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[6]) - AY[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[7]) - AY[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := Int32(LC);
 end;
 
-class function TNat256.Sub(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const y: TCryptoLibUInt32Array; yOff: Int32; const z: TCryptoLibUInt32Array;
-  zOff: Int32): Int32;
+class function TNat256.Sub(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(x[xOff + 0]) - y[yOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 1]) - y[yOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 2]) - y[yOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 3]) - y[yOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 4]) - y[yOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 5]) - y[yOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 6]) - y[yOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(x[xOff + 7]) - y[yOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AX[AXOff + 0]) - AY[AYOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 1]) - AY[AYOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 2]) - AY[AYOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 3]) - AY[AYOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 4]) - AY[AYOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 5]) - AY[AYOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 6]) - AY[AYOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AX[AXOff + 7]) - AY[AYOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := Int32(LC);
 end;
 
-class function TNat256.SubBothFrom(const x, y, z: TCryptoLibUInt32Array): Int32;
+class function TNat256.SubBothFrom(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(z[0]) - x[0] - y[0]);
-  z[0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[1]) - x[1] - y[1]);
-  z[1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[2]) - x[2] - y[2]);
-  z[2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[3]) - x[3] - y[3]);
-  z[3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[4]) - x[4] - y[4]);
-  z[4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[5]) - x[5] - y[5]);
-  z[5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[6]) - x[6] - y[6]);
-  z[6] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[7]) - x[7] - y[7]);
-  z[7] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := 0;
+  LC := LC + (Int64(AZ[0]) - AX[0] - AY[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[1]) - AX[1] - AY[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[2]) - AX[2] - AY[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[3]) - AX[3] - AY[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[4]) - AX[4] - AY[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[5]) - AX[5] - AY[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[6]) - AX[6] - AY[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[7]) - AX[7] - AY[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := Int32(LC);
 end;
 
-class function TNat256.SubFrom(const x, z: TCryptoLibUInt32Array): Int32;
+class function TNat256.SubFrom(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array; ACIn: Int32): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(z[0]) - x[0]);
-  z[0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[1]) - x[1]);
-  z[1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[2]) - x[2]);
-  z[2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[3]) - x[3]);
-  z[3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[4]) - x[4]);
-  z[4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[5]) - x[5]);
-  z[5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[6]) - x[6]);
-  z[6] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[7]) - x[7]);
-  z[7] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := ACIn;
+  LC := LC + (Int64(AZ[0]) - AX[0]);
+  AZ[0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[1]) - AX[1]);
+  AZ[1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[2]) - AX[2]);
+  AZ[2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[3]) - AX[3]);
+  AZ[3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[4]) - AX[4]);
+  AZ[4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[5]) - AX[5]);
+  AZ[5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[6]) - AX[6]);
+  AZ[6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[7]) - AX[7]);
+  AZ[7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := Int32(LC);
 end;
 
-class function TNat256.SubFrom(const x: TCryptoLibUInt32Array; xOff: Int32;
-  const z: TCryptoLibUInt32Array; zOff: Int32): Int32;
+class function TNat256.SubFrom(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32; ACIn: Int32): Int32;
 var
-  c: Int64;
+  LC: Int64;
 begin
-  c := 0;
-  c := c + (Int64(z[zOff + 0]) - x[xOff + 0]);
-  z[zOff + 0] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 1]) - x[xOff + 1]);
-  z[zOff + 1] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 2]) - x[xOff + 2]);
-  z[zOff + 2] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 3]) - x[xOff + 3]);
-  z[zOff + 3] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 4]) - x[xOff + 4]);
-  z[zOff + 4] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 5]) - x[xOff + 5]);
-  z[zOff + 5] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 6]) - x[xOff + 6]);
-  z[zOff + 6] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  c := c + (Int64(z[zOff + 7]) - x[xOff + 7]);
-  z[zOff + 7] := UInt32(c);
-  c := TBitUtilities.Asr64(c, 32);
-  result := Int32(c);
+  LC := ACIn;
+  LC := LC + (Int64(AZ[AZOff + 0]) - AX[AXOff + 0]);
+  AZ[AZOff + 0] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 1]) - AX[AXOff + 1]);
+  AZ[AZOff + 1] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 2]) - AX[AXOff + 2]);
+  AZ[AZOff + 2] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 3]) - AX[AXOff + 3]);
+  AZ[AZOff + 3] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 4]) - AX[AXOff + 4]);
+  AZ[AZOff + 4] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 5]) - AX[AXOff + 5]);
+  AZ[AZOff + 5] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 6]) - AX[AXOff + 6]);
+  AZ[AZOff + 6] := UInt32(LC);
+  LC := LC shr 32;
+  LC := LC + (Int64(AZ[AZOff + 7]) - AX[AXOff + 7]);
+  AZ[AZOff + 7] := UInt32(LC);
+  LC := LC shr 32;
+  Result := Int32(LC);
 end;
 
-class function TNat256.ToBigInteger(const x: TCryptoLibUInt32Array)
-  : TBigInteger;
+class function TNat256.ToBigInteger(const AX: TCryptoLibUInt32Array): TBigInteger;
 var
-  bs, temp: TCryptoLibByteArray;
-  i: Int32;
-  x_i: UInt32;
+  LBs: TCryptoLibByteArray;
+  LX_i: UInt32;
+  LI: Int32;
 begin
-  System.SetLength(bs, 32);
-  for i := 0 to System.Pred(8) do
-
+  SetLength(LBs, 32);
+  for LI := 0 to (8) - 1 do
   begin
-    x_i := x[i];
-    if (x_i <> 0) then
-    begin
-      temp := TConverters.ReadUInt32AsBytesBE(x_i);
-      System.Move(temp[0], bs[(7 - i) shl 2], System.Length(temp) *
-        System.SizeOf(Byte))
-    end;
+  LX_i := AX[LI];
+  if (LX_i <> 0) then
+  begin
+  TPack.UInt32_To_BE(LX_i, LBs, (7 - LI)  shl 2);
   end;
-  result := TBigInteger.Create(1, bs);
+  end;
+  Result := TBigInteger.Create(1, LBs);
 end;
 
-class function TNat256.ToBigInteger64(const x: TCryptoLibUInt64Array)
-  : TBigInteger;
+class function TNat256.ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger;
 var
-  bs, temp: TCryptoLibByteArray;
-  i: Int32;
-  x_i: UInt64;
+  LBs: TCryptoLibByteArray;
+  LX_i: UInt64;
+  LI: Int32;
 begin
-  System.SetLength(bs, 32);
-  for i := 0 to System.Pred(4) do
+  SetLength(LBs, 32);
+  for LI := 0 to (4) - 1 do
+  begin
+  LX_i := AX[LI];
+  if (LX_i <> Int64(0)) then
+  begin
+  TPack.UInt64_To_BE(LX_i, LBs, (3 - LI) shl 3);
+  end;
+  end;
+  Result := TBigInteger.Create(1, LBs);
+end;
 
+class procedure TNat256.&Xor(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
   begin
-    x_i := x[i];
-    if (x_i <> Int64(0)) then
-    begin
-      temp := TConverters.ReadUInt64AsBytesBE(x_i);
-      System.Move(temp[0], bs[(3 - i) shl 3], System.Length(temp) *
-        System.SizeOf(Byte))
-    end;
+    AZ[AZOff + LI + 0] := AX[AXOff + LI + 0] xor AY[AYOff + LI + 0];
+    AZ[AZOff + LI + 1] := AX[AXOff + LI + 1] xor AY[AYOff + LI + 1];
+    AZ[AZOff + LI + 2] := AX[AXOff + LI + 2] xor AY[AYOff + LI + 2];
+    AZ[AZOff + LI + 3] := AX[AXOff + LI + 3] xor AY[AYOff + LI + 3];
+    Inc(LI, 4);
   end;
-  result := TBigInteger.Create(1, bs);
 end;
 
-class procedure TNat256.Zero(const z: TCryptoLibUInt32Array);
+class procedure TNat256.Zero(AZ: TCryptoLibUInt32Array);
 begin
-  TArrayUtilities.Fill<UInt32>(z, 0, 8, UInt32(0));
+  TArrayUtilities.Fill<UInt32>(AZ, 0, 8, UInt32(0));
 end;
 
 end.

+ 47 - 91
CryptoLib/src/Math/Raw/ClpNat320.pas

@@ -22,161 +22,117 @@ unit ClpNat320;
 interface
 
 uses
+  SysUtils,
+  ClpNat,
+  ClpPack,
   ClpBigInteger,
-  ClpConverters,
+  ClpBitUtilities,
   ClpCryptoLibTypes;
 
 type
-  TNat320 = class abstract(TObject)
-
+  TNat320 = class sealed
+  strict private
   public
-    class procedure Copy64(const x, z: TCryptoLibUInt64Array); overload;
-      static; inline;
-
-    class procedure Copy64(const x: TCryptoLibUInt64Array; xOff: Int32;
-      const z: TCryptoLibUInt64Array; zOff: Int32); overload; static; inline;
-
-    class function Create64(): TCryptoLibUInt64Array; static; inline;
-
-    class function CreateExt64(): TCryptoLibUInt64Array; static; inline;
-
-    class function Eq64(const x, y: TCryptoLibUInt64Array): Boolean; static;
-
-    class function FromBigInteger64(const x: TBigInteger)
-      : TCryptoLibUInt64Array; static;
-
-    class function IsOne64(const x: TCryptoLibUInt64Array): Boolean; static;
-
-    class function IsZero64(const x: TCryptoLibUInt64Array): Boolean; static;
-
-    class function ToBigInteger64(const x: TCryptoLibUInt64Array)
-      : TBigInteger; static;
-
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+    class function Create64(): TCryptoLibUInt64Array; static;
+    class function CreateExt64(): TCryptoLibUInt64Array; static;
+    class function Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean; static;
+    class function IsOne64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function IsZero64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger; static;
   end;
 
 implementation
 
-{ TNat320 }
-
-class procedure TNat320.Copy64(const x, z: TCryptoLibUInt64Array);
+class procedure TNat320.Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
 begin
-  System.Move(x[0], z[0], 5 * System.SizeOf(UInt64));
+  System.Move(AX[0], AZ[0], 5 * System.SizeOf(UInt64));
 end;
 
-class procedure TNat320.Copy64(const x: TCryptoLibUInt64Array; xOff: Int32;
-  const z: TCryptoLibUInt64Array; zOff: Int32);
+class procedure TNat320.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
 begin
-  System.Move(x[xOff], z[zOff], 5 * System.SizeOf(UInt64));
+  System.Move(AX[AXOff], AZ[AZOff], 5 * System.SizeOf(UInt64));
 end;
 
-class function TNat320.Create64: TCryptoLibUInt64Array;
+class function TNat320.Create64(): TCryptoLibUInt64Array;
 begin
-  System.SetLength(Result, 5);
+  SetLength(Result, 5);
+  Exit;
 end;
 
-class function TNat320.CreateExt64: TCryptoLibUInt64Array;
+class function TNat320.CreateExt64(): TCryptoLibUInt64Array;
 begin
-  System.SetLength(Result, 10);
+  SetLength(Result, 10);
+  Exit;
 end;
 
-class function TNat320.Eq64(const x, y: TCryptoLibUInt64Array): Boolean;
+class function TNat320.Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 4;
-  while i >= 0 do
+  for LI := 4 downto 0 do
   begin
-    if (x[i] <> y[i]) then
+    if AX[LI] <> AY[LI] then
     begin
       Result := False;
       Exit;
     end;
-    System.Dec(i);
   end;
   Result := True;
 end;
 
-class function TNat320.FromBigInteger64(const x: TBigInteger)
-  : TCryptoLibUInt64Array;
+class function TNat320.IsOne64(const AX: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
-  Lx: TBigInteger;
+  LI: Int32;
 begin
-  Lx := x;
-  if ((Lx.SignValue < 0) or (Lx.BitLength > 320)) then
-  begin
-    raise EArgumentCryptoLibException.Create('');
-  end;
-
-  Result := Create64();
-  i := 0;
-  while (Lx.SignValue <> 0) do
-  begin
-    Result[i] := UInt64(Lx.Int64Value);
-    System.Inc(i);
-    Lx := Lx.ShiftRight(64);
-  end;
-end;
-
-class function TNat320.IsOne64(const x: TCryptoLibUInt64Array): Boolean;
-var
-  i: Int32;
-begin
-  if (x[0] <> UInt64(1)) then
+  if AX[0] <> UInt64(1) then
   begin
     Result := False;
     Exit;
   end;
-  i := 1;
-  while i < 5 do
+  for LI := 1 to (5) - 1 do
   begin
-    if (x[i] <> UInt64(0)) then
+    if AX[LI] <> UInt64(0) then
     begin
       Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
   Result := True;
 end;
 
-class function TNat320.IsZero64(const x: TCryptoLibUInt64Array): Boolean;
+class function TNat320.IsZero64(const AX: TCryptoLibUInt64Array): Boolean;
 var
-  i: Int32;
+  LI: Int32;
 begin
-  i := 0;
-  while i < 5 do
+  for LI := 0 to (5) - 1 do
   begin
-    if (x[i] <> UInt64(0)) then
+    if AX[LI] <> UInt64(0) then
     begin
       Result := False;
       Exit;
     end;
-    System.Inc(i);
   end;
   Result := True;
 end;
 
-class function TNat320.ToBigInteger64(const x: TCryptoLibUInt64Array)
-  : TBigInteger;
+class function TNat320.ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger;
 var
-  bs, temp: TCryptoLibByteArray;
-  i: Int32;
-  x_i: UInt64;
+  LBs: TBytes;
+  LX_i: UInt64;
+  LI: Int32;
 begin
-  System.SetLength(bs, 40);
-  for i := 0 to System.Pred(5) do
-
+  SetLength(LBs, 40);
+  for LI := 0 to (5) - 1 do
   begin
-    x_i := x[i];
-    if (x_i <> Int64(0)) then
+    LX_i := AX[LI];
+    if (LX_i <> Int64(0)) then
     begin
-      temp := TConverters.ReadUInt64AsBytesBE(x_i);
-      System.Move(temp[0], bs[(4 - i) shl 3], System.Length(temp) *
-        System.SizeOf(Byte))
+      TPack.UInt64_To_BE(LX_i, LBs, (4 - LI) shl 3);
     end;
   end;
-  Result := TBigInteger.Create(1, bs);
+  Result := TBigInteger.Create(1, LBs);
 end;
 
 end.

+ 41 - 36
CryptoLib/src/Math/Raw/ClpNat384.pas

@@ -22,74 +22,79 @@ unit ClpNat384;
 interface
 
 uses
+  SysUtils,
   ClpNat,
   ClpNat192,
+  ClpPack,
+  ClpBigInteger,
+  ClpBitUtilities,
   ClpCryptoLibTypes;
 
 type
-  TNat384 = class sealed(TObject)
-
+  TNat384 = class sealed
   public
-    class procedure Mul(const x, y, zz: TCryptoLibUInt32Array); static;
-    class procedure Square(const x, zz: TCryptoLibUInt32Array); static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
 
+    class procedure Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
   end;
 
 implementation
 
 { TNat384 }
 
-class procedure TNat384.Mul(const x, y, zz: TCryptoLibUInt32Array);
+class procedure TNat384.Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array;
+  AZz: TCryptoLibUInt32Array);
 var
-  c18, c12: UInt32;
-  dx, dy, tt: TCryptoLibUInt32Array;
-  neg: Boolean;
+  LC18, LC12: UInt32;
+  LDx, LDy, LTt: TCryptoLibUInt32Array;
+  LNeg: Boolean;
 begin
-  TNat192.Mul(x, y, zz);
-  TNat192.Mul(x, 6, y, 6, zz, 12);
+  TNat192.Mul(AX, AY, AZz);
+  TNat192.Mul(AX, 6, AY, 6, AZz, 12);
 
-  c18 := TNat192.AddToEachOther(zz, 6, zz, 12);
-  c12 := c18 + TNat192.AddTo(zz, 0, zz, 6, 0);
-  c18 := c18 + (TNat192.AddTo(zz, 18, zz, 12, c12));
+  LC18 := TNat192.AddToEachOther(AZz, 6, AZz, 12);
+  LC12 := LC18 + TNat192.AddTo(AZz, 0, AZz, 6, 0);
+  LC18 := LC18 + TNat192.AddTo(AZz, 18, AZz, 12, LC12);
 
-  dx := TNat192.Create();
-  dy := TNat192.Create();
-  neg := TNat192.Diff(x, 6, x, 0, dx, 0) <> TNat192.Diff(y, 6, y, 0, dy, 0);
+  LDx := TNat192.Create();
+  LDy := TNat192.Create();
+  LNeg := (TNat192.Diff(AX, 6, AX, 0, LDx, 0) <> TNat192.Diff(AY, 6, AY, 0, LDy, 0));
 
-  tt := TNat192.CreateExt();
-  TNat192.Mul(dx, dy, tt);
+  LTt := TNat192.CreateExt();
+  TNat192.Mul(LDx, LDy, LTt);
 
-  if neg then
+  if LNeg then
   begin
-    c18 := c18 + TNat.AddTo(12, tt, 0, zz, 6);
+    LC18 := LC18 + TNat.AddTo(12, LTt, 0, AZz, 6);
   end
   else
   begin
-    c18 := c18 + UInt32(TNat.SubFrom(12, tt, 0, zz, 6));
+    LC18 := LC18 + UInt32(TNat.SubFrom(12, LTt, 0, AZz, 6));
   end;
-  TNat.AddWordAt(24, c18, zz, 18);
+
+  TNat.AddWordAt(24, LC18, AZz, 18);
 end;
 
-class procedure TNat384.Square(const x, zz: TCryptoLibUInt32Array);
+class procedure TNat384.Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  c18, c12: UInt32;
-  dx, m: TCryptoLibUInt32Array;
+  LC18, LC12: UInt32;
+  LDx, LM: TCryptoLibUInt32Array;
 begin
-  TNat192.Square(x, zz);
-  TNat192.Square(x, 6, zz, 12);
+  TNat192.Square(AX, AZz);
+  TNat192.Square(AX, 6, AZz, 12);
 
-  c18 := TNat192.AddToEachOther(zz, 6, zz, 12);
-  c12 := c18 + TNat192.AddTo(zz, 0, zz, 6, 0);
-  c18 := c18 + TNat192.AddTo(zz, 18, zz, 12, c12);
+  LC18 := TNat192.AddToEachOther(AZz, 6, AZz, 12);
+  LC12 := LC18 + TNat192.AddTo(AZz, 0, AZz, 6, 0);
+  LC18 := LC18 + TNat192.AddTo(AZz, 18, AZz, 12, LC12);
 
-  dx := TNat192.Create();
-  TNat192.Diff(x, 6, x, 0, dx, 0);
+  LDx := TNat192.Create();
+  TNat192.Diff(AX, 6, AX, 0, LDx, 0);
 
-  m := TNat192.CreateExt();
-  TNat192.Square(dx, m);
+  LM := TNat192.CreateExt();
+  TNat192.Square(LDx, LM);
 
-  c18 := c18 + UInt32(TNat.SubFrom(12, m, 0, zz, 6));
-  TNat.AddWordAt(24, c18, zz, 18);
+  LC18 := LC18 + UInt32(TNat.SubFrom(12, LM, 0, AZz, 6));
+  TNat.AddWordAt(24, LC18, AZz, 18);
 end;
 
 end.

+ 205 - 0
CryptoLib/src/Math/Raw/ClpNat448.pas

@@ -0,0 +1,205 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpNat448;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpNat,
+  ClpNat224,
+  ClpPack,
+  ClpBigInteger,
+  ClpBitUtilities,
+  ClpCryptoLibTypes;
+
+type
+  TNat448 = class sealed
+  public
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+
+    class function Create64(): TCryptoLibUInt64Array; static;
+    class function CreateExt64(): TCryptoLibUInt64Array; static;
+
+    class function Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean; static;
+    class function IsOne64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function IsZero64(const AX: TCryptoLibUInt64Array): Boolean; static;
+
+    class procedure Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
+
+    class procedure Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
+
+    class function ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger; static;
+  end;
+
+implementation
+
+{ TNat448 }
+
+class procedure TNat448.Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
+begin
+  System.Move(AX[0], AZ[0], 7 * System.SizeOf(UInt64));
+end;
+
+class procedure TNat448.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array;
+  AZOff: Int32);
+begin
+  System.Move(AX[AXOff], AZ[AZOff], 7 * System.SizeOf(UInt64));
+end;
+
+class function TNat448.Create64(): TCryptoLibUInt64Array;
+begin
+  System.SetLength(Result, 7);
+end;
+
+class function TNat448.CreateExt64(): TCryptoLibUInt64Array;
+begin
+  System.SetLength(Result, 14);
+end;
+
+class function TNat448.Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 6 downto 0 do
+  begin
+    if AX[LI] <> AY[LI] then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat448.IsOne64(const AX: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  if AX[0] <> UInt64(1) then
+  begin
+    Result := False;
+    Exit;
+  end;
+
+  for LI := 1 to 6 do
+  begin
+    if AX[LI] <> UInt64(0) then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  Result := True;
+end;
+
+class function TNat448.IsZero64(const AX: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 0 to 6 do
+  begin
+    if AX[LI] <> UInt64(0) then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  Result := True;
+end;
+
+class procedure TNat448.Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array;
+  AZz: TCryptoLibUInt32Array);
+var
+  LC21, LC14: UInt32;
+  LDx, LDy, LTt: TCryptoLibUInt32Array;
+  LNeg: Boolean;
+begin
+  TNat224.Mul(AX, AY, AZz);
+  TNat224.Mul(AX, 7, AY, 7, AZz, 14);
+
+  LC21 := TNat224.AddToEachOther(AZz, 7, AZz, 14);
+  LC14 := LC21 + TNat224.AddTo(AZz, 0, AZz, 7, UInt32(0));
+  LC21 := LC21 + TNat224.AddTo(AZz, 21, AZz, 14, LC14);
+
+  LDx := TNat224.Create();
+  LDy := TNat224.Create();
+  LNeg := (TNat224.Diff(AX, 7, AX, 0, LDx, 0) <> TNat224.Diff(AY, 7, AY, 0, LDy, 0));
+
+  LTt := TNat224.CreateExt();
+  TNat224.Mul(LDx, LDy, LTt);
+
+  if LNeg then
+  begin
+    LC21 := LC21 + TNat.AddTo(14, LTt, 0, AZz, 7);
+  end
+  else
+  begin
+    LC21 := LC21 + UInt32(TNat.SubFrom(14, LTt, 0, AZz, 7));
+  end;
+
+  TNat.AddWordAt(28, LC21, AZz, 21);
+end;
+
+class procedure TNat448.Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
+var
+  LC21, LC14: UInt32;
+  LDx, LTt: TCryptoLibUInt32Array;
+begin
+  TNat224.Square(AX, AZz);
+  TNat224.Square(AX, 7, AZz, 14);
+
+  LC21 := TNat224.AddToEachOther(AZz, 7, AZz, 14);
+  LC14 := LC21 + TNat224.AddTo(AZz, 0, AZz, 7, UInt32(0));
+  LC21 := LC21 + TNat224.AddTo(AZz, 21, AZz, 14, LC14);
+
+  LDx := TNat224.Create();
+  TNat224.Diff(AX, 7, AX, 0, LDx, 0);
+
+  LTt := TNat224.CreateExt();
+  TNat224.Square(LDx, LTt);
+
+  LC21 := LC21 + UInt32(TNat.SubFrom(14, LTt, 0, AZz, 7));
+  TNat.AddWordAt(28, LC21, AZz, 21);
+end;
+
+class function TNat448.ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger;
+var
+  LBs: TCryptoLibByteArray;
+  LI: Int32;
+  LXi: UInt64;
+begin
+  System.SetLength(LBs, 56);
+  for LI := 0 to 6 do
+  begin
+    LXi := AX[LI];
+    if LXi <> UInt64(0) then
+    begin
+      TPack.UInt64_To_BE(LXi, LBs, (6 - LI) shl 3);
+    end;
+  end;
+
+  Result := TBigInteger.Create(1, LBs);
+end;
+
+end.

+ 233 - 36
CryptoLib/src/Math/Raw/ClpNat512.pas

@@ -22,75 +22,272 @@ unit ClpNat512;
 interface
 
 uses
+  SysUtils,
   ClpNat,
   ClpNat256,
   ClpCryptoLibTypes;
 
 type
-  TNat512 = class sealed(TObject)
-
+  TNat512 = class sealed
   public
-    class procedure Mul(const x, y, zz: TCryptoLibUInt32Array); static;
-    class procedure Square(const x, zz: TCryptoLibUInt32Array); static;
+    class procedure Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
+    class procedure Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array); static;
+
+    class procedure &Xor(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure &Xor(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+
+    class procedure Xor64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Xor64(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+
+    class procedure XorBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure XorBothTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+
+    class procedure XorBothTo64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure XorBothTo64(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
 
+    class procedure XorTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure XorTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+
+    class procedure XorTo64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure XorTo64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
   end;
 
 implementation
 
 { TNat512 }
 
-class procedure TNat512.Mul(const x, y, zz: TCryptoLibUInt32Array);
+class procedure TNat512.Mul(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
 var
-  c24, c16: UInt32;
-  dx, dy, tt: TCryptoLibUInt32Array;
-  neg: Boolean;
+  LC24, LC16: UInt32;
+  LDx, LDy, LTt: TCryptoLibUInt32Array;
+  LNeg: Boolean;
 begin
-  TNat256.Mul(x, y, zz);
-  TNat256.Mul(x, 8, y, 8, zz, 16);
+  TNat256.Mul(AX, AY, AZz);
+  TNat256.Mul(AX, 8, AY, 8, AZz, 16);
 
-  c24 := TNat256.AddToEachOther(zz, 8, zz, 16);
-  c16 := c24 + TNat256.AddTo(zz, 0, zz, 8, 0);
-  c24 := c24 + (TNat256.AddTo(zz, 24, zz, 16, c16));
+  LC24 := TNat256.AddToEachOther(AZz, 8, AZz, 16);
+  LC16 := LC24 + TNat256.AddTo(AZz, 0, AZz, 8, 0);
+  LC24 := LC24 + TNat256.AddTo(AZz, 24, AZz, 16, LC16);
 
-  dx := TNat256.Create();
-  dy := TNat256.Create();
-  neg := TNat256.Diff(x, 8, x, 0, dx, 0) <> TNat256.Diff(y, 8, y, 0, dy, 0);
+  LDx := TNat256.Create();
+  LDy := TNat256.Create();
+  LNeg := TNat256.Diff(AX, 8, AX, 0, LDx, 0) <> TNat256.Diff(AY, 8, AY, 0, LDy, 0);
 
-  tt := TNat256.CreateExt();
-  TNat256.Mul(dx, dy, tt);
+  LTt := TNat256.CreateExt();
+  TNat256.Mul(LDx, LDy, LTt);
 
-  if neg then
+  if LNeg then
   begin
-    c24 := c24 + TNat.AddTo(16, tt, 0, zz, 8);
+    LC24 := LC24 + TNat.AddTo(16, LTt, 0, AZz, 8);
   end
   else
   begin
-    c24 := c24 + UInt32(TNat.SubFrom(16, tt, 0, zz, 8));
+    LC24 := LC24 + UInt32(TNat.SubFrom(16, LTt, 0, AZz, 8));
+  end;
+
+  TNat.AddWordAt(32, LC24, AZz, 24);
+end;
+
+class procedure TNat512.Square(const AX: TCryptoLibUInt32Array; AZz: TCryptoLibUInt32Array);
+var
+  LC24, LC16: UInt32;
+  LDx, LM: TCryptoLibUInt32Array;
+begin
+  TNat256.Square(AX, AZz);
+  TNat256.Square(AX, 8, AZz, 16);
+
+  LC24 := TNat256.AddToEachOther(AZz, 8, AZz, 16);
+  LC16 := LC24 + TNat256.AddTo(AZz, 0, AZz, 8, 0);
+  LC24 := LC24 + TNat256.AddTo(AZz, 24, AZz, 16, LC16);
+
+  LDx := TNat256.Create();
+  TNat256.Diff(AX, 8, AX, 0, LDx, 0);
+
+  LM := TNat256.CreateExt();
+  TNat256.Square(LDx, LM);
+
+  LC24 := LC24 + UInt32(TNat.SubFrom(16, LM, 0, AZz, 8));
+  TNat.AddWordAt(32, LC24, AZz, 24);
+end;
+
+class procedure TNat512.&Xor(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 16 do
+  begin
+    AZ[LI + 0] := AX[LI + 0] xor AY[LI + 0];
+    AZ[LI + 1] := AX[LI + 1] xor AY[LI + 1];
+    AZ[LI + 2] := AX[LI + 2] xor AY[LI + 2];
+    AZ[LI + 3] := AX[LI + 3] xor AY[LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
+
+class procedure TNat512.&Xor(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 16 do
+  begin
+    AZ[AZOff + LI + 0] := AX[AXOff + LI + 0] xor AY[AYOff + LI + 0];
+    AZ[AZOff + LI + 1] := AX[AXOff + LI + 1] xor AY[AYOff + LI + 1];
+    AZ[AZOff + LI + 2] := AX[AXOff + LI + 2] xor AY[AYOff + LI + 2];
+    AZ[AZOff + LI + 3] := AX[AXOff + LI + 3] xor AY[AYOff + LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
+
+class procedure TNat512.Xor64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
+  begin
+    AZ[LI + 0] := AX[LI + 0] xor AY[LI + 0];
+    AZ[LI + 1] := AX[LI + 1] xor AY[LI + 1];
+    AZ[LI + 2] := AX[LI + 2] xor AY[LI + 2];
+    AZ[LI + 3] := AX[LI + 3] xor AY[LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
+
+class procedure TNat512.Xor64(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
+  begin
+    AZ[AZOff + LI + 0] := AX[AXOff + LI + 0] xor AY[AYOff + LI + 0];
+    AZ[AZOff + LI + 1] := AX[AXOff + LI + 1] xor AY[AYOff + LI + 1];
+    AZ[AZOff + LI + 2] := AX[AXOff + LI + 2] xor AY[AYOff + LI + 2];
+    AZ[AZOff + LI + 3] := AX[AXOff + LI + 3] xor AY[AYOff + LI + 3];
+    System.Inc(LI, 4);
   end;
+end;
 
-  TNat.AddWordAt(32, c24, zz, 24);
+class procedure TNat512.XorBothTo(const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 16 do
+  begin
+    AZ[LI + 0] := AZ[LI + 0] xor AX[LI + 0] xor AY[LI + 0];
+    AZ[LI + 1] := AZ[LI + 1] xor AX[LI + 1] xor AY[LI + 1];
+    AZ[LI + 2] := AZ[LI + 2] xor AX[LI + 2] xor AY[LI + 2];
+    AZ[LI + 3] := AZ[LI + 3] xor AX[LI + 3] xor AY[LI + 3];
+    System.Inc(LI, 4);
+  end;
 end;
 
-class procedure TNat512.Square(const x, zz: TCryptoLibUInt32Array);
+class procedure TNat512.XorBothTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
 var
-  c24, c16: UInt32;
-  dx, m: TCryptoLibUInt32Array;
+  LI: Int32;
 begin
-  TNat256.Square(x, zz);
-  TNat256.Square(x, 8, zz, 16);
+  LI := 0;
+  while LI < 16 do
+  begin
+    AZ[AZOff + LI + 0] := AZ[AZOff + LI + 0] xor AX[AXOff + LI + 0] xor AY[AYOff + LI + 0];
+    AZ[AZOff + LI + 1] := AZ[AZOff + LI + 1] xor AX[AXOff + LI + 1] xor AY[AYOff + LI + 1];
+    AZ[AZOff + LI + 2] := AZ[AZOff + LI + 2] xor AX[AXOff + LI + 2] xor AY[AYOff + LI + 2];
+    AZ[AZOff + LI + 3] := AZ[AZOff + LI + 3] xor AX[AXOff + LI + 3] xor AY[AYOff + LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
 
-  c24 := TNat256.AddToEachOther(zz, 8, zz, 16);
-  c16 := c24 + TNat256.AddTo(zz, 0, zz, 8, 0);
-  c24 := c24 + (TNat256.AddTo(zz, 24, zz, 16, c16));
+class procedure TNat512.XorBothTo64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
+  begin
+    AZ[LI + 0] := AZ[LI + 0] xor AX[LI + 0] xor AY[LI + 0];
+    AZ[LI + 1] := AZ[LI + 1] xor AX[LI + 1] xor AY[LI + 1];
+    AZ[LI + 2] := AZ[LI + 2] xor AX[LI + 2] xor AY[LI + 2];
+    AZ[LI + 3] := AZ[LI + 3] xor AX[LI + 3] xor AY[LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
 
-  dx := TNat256.Create();
-  TNat256.Diff(x, 8, x, 0, dx, 0);
+class procedure TNat512.XorBothTo64(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
+  begin
+    AZ[AZOff + LI + 0] := AZ[AZOff + LI + 0] xor AX[AXOff + LI + 0] xor AY[AYOff + LI + 0];
+    AZ[AZOff + LI + 1] := AZ[AZOff + LI + 1] xor AX[AXOff + LI + 1] xor AY[AYOff + LI + 1];
+    AZ[AZOff + LI + 2] := AZ[AZOff + LI + 2] xor AX[AXOff + LI + 2] xor AY[AYOff + LI + 2];
+    AZ[AZOff + LI + 3] := AZ[AZOff + LI + 3] xor AX[AXOff + LI + 3] xor AY[AYOff + LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
 
-  m := TNat256.CreateExt();
-  TNat256.Square(dx, m);
+class procedure TNat512.XorTo(const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 16 do
+  begin
+    AZ[LI + 0] := AZ[LI + 0] xor AX[LI + 0];
+    AZ[LI + 1] := AZ[LI + 1] xor AX[LI + 1];
+    AZ[LI + 2] := AZ[LI + 2] xor AX[LI + 2];
+    AZ[LI + 3] := AZ[LI + 3] xor AX[LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
+
+class procedure TNat512.XorTo(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 16 do
+  begin
+    AZ[AZOff + LI + 0] := AZ[AZOff + LI + 0] xor AX[AXOff + LI + 0];
+    AZ[AZOff + LI + 1] := AZ[AZOff + LI + 1] xor AX[AXOff + LI + 1];
+    AZ[AZOff + LI + 2] := AZ[AZOff + LI + 2] xor AX[AXOff + LI + 2];
+    AZ[AZOff + LI + 3] := AZ[AZOff + LI + 3] xor AX[AXOff + LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
 
-  c24 := c24 + UInt32(TNat.SubFrom(16, m, 0, zz, 8));
-  TNat.AddWordAt(32, c24, zz, 24);
+class procedure TNat512.XorTo64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
+  begin
+    AZ[LI + 0] := AZ[LI + 0] xor AX[LI + 0];
+    AZ[LI + 1] := AZ[LI + 1] xor AX[LI + 1];
+    AZ[LI + 2] := AZ[LI + 2] xor AX[LI + 2];
+    AZ[LI + 3] := AZ[LI + 3] xor AX[LI + 3];
+    System.Inc(LI, 4);
+  end;
+end;
+
+class procedure TNat512.XorTo64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < 8 do
+  begin
+    AZ[AZOff + LI + 0] := AZ[AZOff + LI + 0] xor AX[AXOff + LI + 0];
+    AZ[AZOff + LI + 1] := AZ[AZOff + LI + 1] xor AX[AXOff + LI + 1];
+    AZ[AZOff + LI + 2] := AZ[AZOff + LI + 2] xor AX[AXOff + LI + 2];
+    AZ[AZOff + LI + 3] := AZ[AZOff + LI + 3] xor AX[AXOff + LI + 3];
+    System.Inc(LI, 4);
+  end;
 end;
 
 end.

+ 137 - 0
CryptoLib/src/Math/Raw/ClpNat576.pas

@@ -0,0 +1,137 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpNat576;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpPack,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
+
+type
+  TNat576 = class sealed
+  public
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); overload; static;
+    class procedure Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32); overload; static;
+    class function Create64(): TCryptoLibUInt64Array; static;
+    class function CreateExt64(): TCryptoLibUInt64Array; static;
+    class function Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean; static;
+    class function IsOne64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function IsZero64(const AX: TCryptoLibUInt64Array): Boolean; static;
+    class function ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger; static;
+  end;
+
+implementation
+
+{ TNat576 }
+
+class procedure TNat576.Copy64(const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array);
+begin
+  System.Move(AX[0], AZ[0], 9 * System.SizeOf(UInt64));
+end;
+
+class procedure TNat576.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ: TCryptoLibUInt64Array; AZOff: Int32);
+begin
+  System.Move(AX[AXOff], AZ[AZOff], 9 * System.SizeOf(UInt64));
+end;
+
+class function TNat576.Create64(): TCryptoLibUInt64Array;
+begin
+  System.SetLength(Result, 9);
+end;
+
+class function TNat576.CreateExt64(): TCryptoLibUInt64Array;
+begin
+  System.SetLength(Result, 18);
+end;
+
+class function TNat576.Eq64(const AX: TCryptoLibUInt64Array; const AY: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 8 downto 0 do
+  begin
+    if AX[LI] <> AY[LI] then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat576.IsOne64(const AX: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  if AX[0] <> UInt64(1) then
+  begin
+    Result := False;
+    Exit;
+  end;
+
+  for LI := 1 to 8 do
+  begin
+    if AX[LI] <> UInt64(0) then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  Result := True;
+end;
+
+class function TNat576.IsZero64(const AX: TCryptoLibUInt64Array): Boolean;
+var
+  LI: Int32;
+begin
+  for LI := 0 to 8 do
+  begin
+    if AX[LI] <> UInt64(0) then
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+  Result := True;
+end;
+
+class function TNat576.ToBigInteger64(const AX: TCryptoLibUInt64Array): TBigInteger;
+var
+  LBs: TBytes;
+  LI: Int32;
+  LXI: UInt64;
+begin
+  System.SetLength(LBs, 72);
+  for LI := 0 to 8 do
+  begin
+    LXI := AX[LI];
+    if LXI <> UInt64(0) then
+    begin
+      TPack.UInt64_To_BE(LXI, LBs, (8 - LI) shl 3);
+    end;
+  end;
+  Result := TBigInteger.Create(1, LBs);
+end;
+
+end.

Неке датотеке нису приказане због велике количине промена