Kaynağa Gözat

update TLongArray

Ugochukwu Mmaduekwe 1 hafta önce
ebeveyn
işleme
895bafdedc

+ 1 - 1
CryptoLib.Tests/src/Math/ECPointTests.pas

@@ -336,7 +336,7 @@ begin
   ImplTestMultiply(q, n.BitLength);
   ImplTestMultiply(infinity, n.BitLength);
 
-  logSize := 32 - TBitUtilities.NumberOfLeadingZeros(curve.FieldSize - 1);
+  logSize := 32 - TBitUtilities.NumberOfLeadingZeros32(curve.FieldSize - 1);
   rounds := Max(2, Min(10, 32 - 3 * logSize));
 
   p := q;

+ 1 - 1
CryptoLib/src/Asn1/ClpAsn1Objects.pas

@@ -6594,7 +6594,7 @@ begin
     FContents[0] := 0;
     Exit;
   end;
-  LBits := 32 - TBitUtilities.NumberOfLeadingZeros(UInt32(ANamedBits));
+  LBits := 32 - TBitUtilities.NumberOfLeadingZeros32(UInt32(ANamedBits));
   LBytes := (LBits + 7) div 8;
   System.SetLength(LData, 1 + LBytes);
   for I := 1 to LBytes - 1 do

+ 104 - 6
CryptoLib/src/BitUtilities/ClpBitUtilities.pas

@@ -124,11 +124,14 @@ type
     class function RotateRight32(AValue: UInt32; AN: Int32): UInt32; static; inline;
     class function RotateRight64(AValue: UInt64; AN: Int32): UInt64; static; inline;
 
-    class function NumberOfLeadingZeros(AValue: UInt32): Int32; static;
+    class function NumberOfLeadingZeros32(AValue: UInt32): Int32; static;
+    class function NumberOfLeadingZeros64(AValue: UInt64): Int32; static;
 
-    class function NumberOfTrailingZeros(AValue: UInt32): Int32; static;
+    class function NumberOfTrailingZeros32(AValue: UInt32): Int32; static;
+    class function NumberOfTrailingZeros64(AValue: UInt64): Int32; static;
 
-    class function PopCount(AValue: UInt32): Int32; static;
+    class function PopCount32(AValue: UInt32): Int32; static;
+    class function PopCount64(AValue: UInt64): Int32; static;
   end;
 
 implementation
@@ -344,7 +347,7 @@ begin
 {$ENDIF FPC}
 end;
 
-class function TBitUtilities.NumberOfLeadingZeros(AValue: UInt32): Int32;
+class function TBitUtilities.NumberOfLeadingZeros32(AValue: UInt32): Int32;
 {$IFNDEF FPC}
 var
   LN: UInt32;
@@ -391,7 +394,36 @@ begin
 {$ENDIF FPC}
 end;
 
-class function TBitUtilities.NumberOfTrailingZeros(AValue: UInt32): Int32;
+class function TBitUtilities.NumberOfLeadingZeros64(AValue: UInt64): Int32;
+{$IFNDEF FPC}
+var
+  LX: UInt32;
+  LN: Int32;
+{$ENDIF FPC}
+begin
+  if (AValue = 0) then
+  begin
+    Result := Int32(((not AValue) shr (63 - 6)) and (UInt64(1) shl 6));
+    Exit;
+  end;
+
+{$IFDEF FPC}
+  Result := Int32(BsrQWord(AValue) xor ((System.SizeOf(UInt64) * 8) - 1));
+  // also works:
+  // Result := Int32(((System.SizeOf(UInt64) * 8) - 1) - BsrQWord(AValue));
+{$ELSE}
+  LX := UInt32(AValue shr 32);
+  LN := 0;
+  if (LX = 0) then
+  begin
+    LN := 32;
+    LX := UInt32(AValue);
+  end;
+  Result := LN + NumberOfLeadingZeros32(LX);
+{$ENDIF FPC}
+end;
+
+class function TBitUtilities.NumberOfTrailingZeros32(AValue: UInt32): Int32;
 {$IFNDEF FPC}
 var
   LN: UInt32;
@@ -435,8 +467,58 @@ begin
 {$ENDIF FPC}
 end;
 
+class function TBitUtilities.NumberOfTrailingZeros64(AValue: UInt64): Int32;
+{$IFNDEF FPC}
+var
+  LN: UInt32;
+{$ENDIF FPC}
+begin
+  if (AValue = 0) then
+  begin
+    Result := Int32(((not AValue) shr (63 - 6)) and (UInt64(1) shl 6));
+    Exit;
+  end;
+
+{$IFDEF FPC}
+  Result := BsfQWord(AValue);
+{$ELSE}
+  LN := 0;
+
+  if ((AValue and UInt64($00000000FFFFFFFF)) = 0) then
+  begin
+    LN := LN + 32;
+    AValue := AValue shr 32;
+  end;
+
+  if ((AValue and UInt64($000000000000FFFF)) = 0) then
+  begin
+    LN := LN + 16;
+    AValue := AValue shr 16;
+  end;
 
-class function TBitUtilities.PopCount(AValue: UInt32): Int32;
+  if ((AValue and UInt64($00000000000000FF)) = 0) then
+  begin
+    LN := LN + 8;
+    AValue := AValue shr 8;
+  end;
+
+  if ((AValue and UInt64($000000000000000F)) = 0) then
+  begin
+    LN := LN + 4;
+    AValue := AValue shr 4;
+  end;
+
+  if ((AValue and UInt64($0000000000000003)) = 0) then
+  begin
+    LN := LN + 2;
+    AValue := AValue shr 2;
+  end;
+
+  Result := Int32(LN + (UInt32(AValue) and 1) xor 1);
+{$ENDIF FPC}
+end;
+
+class function TBitUtilities.PopCount32(AValue: UInt32): Int32;
 begin
 {$IFDEF FPC}
   Result := PopCnt(AValue);
@@ -451,4 +533,20 @@ begin
 {$ENDIF FPC}
 end;
 
+class function TBitUtilities.PopCount64(AValue: UInt64): Int32;
+begin
+{$IFDEF FPC}
+  Result := PopCnt(AValue);
+{$ELSE}
+  AValue := AValue - ((AValue shr 1) and UInt64($5555555555555555));
+  AValue := (AValue and UInt64($3333333333333333)) + ((AValue shr 2) and UInt64($3333333333333333));
+  AValue := (AValue + (AValue shr 4)) and UInt64($0F0F0F0F0F0F0F0F);
+  AValue := AValue + (AValue shr 8);
+  AValue := AValue + (AValue shr 16);
+  AValue := AValue + (AValue shr 32);
+  AValue := AValue and UInt64($7F);
+  Result := Int32(AValue);
+{$ENDIF FPC}
+end;
+
 end.

+ 5 - 5
CryptoLib/src/Math/ClpBigInteger.pas

@@ -445,13 +445,13 @@ end;
 
 class function TBigInteger.PopCount(const AValue: UInt32): Int32;
 begin
-  Result := TBitUtilities.PopCount(AValue);
+  Result := TBitUtilities.PopCount32(AValue);
 end;
 
 class function TBigInteger.BitLen(const AValue: Byte): Int32;
 begin
   //Result := BitLengthTable[AValue];
-  Result := 32 - TBitUtilities.NumberOfLeadingZeros(AValue);
+  Result := 32 - TBitUtilities.NumberOfLeadingZeros32(AValue);
 end;
 
 class function TBigInteger.BitLen(const AValue: UInt32): Int32;
@@ -477,7 +477,7 @@ begin
     Exit;
   end;
   Result := BitLengthTable[AValue]; *)
-  Result := 32 - TBitUtilities.NumberOfLeadingZeros(AValue);
+  Result := 32 - TBitUtilities.NumberOfLeadingZeros32(AValue);
 end;
 
 class function TBigInteger.CreateUValueOf(const AValue: UInt32): TBigInteger;
@@ -2667,7 +2667,7 @@ begin
     LOffset := LOffset + 32;
   end;
 
-  LOffset := LOffset + TBitUtilities.NumberOfTrailingZeros(LWord);
+  LOffset := LOffset + TBitUtilities.NumberOfTrailingZeros32(LWord);
  (*
   while (LWord and $FF) = 0 do
   begin
@@ -2808,7 +2808,7 @@ begin
     LMult := LMult shr 1;
     System.Inc(LZeros);
   end; *)
-  LTZ := TBitUtilities.NumberOfTrailingZeros(LMult);
+  LTZ := TBitUtilities.NumberOfTrailingZeros32(LMult);
   LMult := LMult shr LTZ;
   LZeros := LZeros + UInt32(LTZ);
   // Combine multiplier and zeros: mult | (zeros << 8)

+ 22 - 16
CryptoLib/src/Math/EC/ClpECC.pas

@@ -779,17 +779,17 @@ type
   strict private
   var
     Fm_outer: IF2mCurve;
-    Fm_table: TCryptoLibInt64Array;
+    Fm_table: TCryptoLibUInt64Array;
     Fm_size: Int32;
 
-    function CreatePoint(const x, y: TCryptoLibInt64Array): IECPoint;
+    function CreatePoint(const x, y: TCryptoLibUInt64Array): IECPoint;
 
   strict protected
     function GetSize: Int32; override;
 
   public
     constructor Create(const outer: IF2mCurve;
-      const table: TCryptoLibInt64Array; Size: Int32);
+      const table: TCryptoLibUInt64Array; Size: Int32);
 
     destructor Destroy; override;
 
@@ -1829,7 +1829,7 @@ begin
   xx := (x as IF2mFieldElement).x;
   yx := (y as IF2mFieldElement).x;
 
-  aa := ax.Square();
+  aa := ax.Square(Fm, FKs);
   xy := xx.Multiply(yx);
 
   if (aa.Equals(ax)) then
@@ -2502,7 +2502,7 @@ begin
   end;
 
   n := TBitUtilities.Asr32((m + 1), 1);
-  K := 31 - TBitUtilities.NumberOfLeadingZeros(n);
+  K := 31 - TBitUtilities.NumberOfLeadingZeros32(n);
   nk := 1;
 
   ht := Self as IECFieldElement;
@@ -2533,7 +2533,7 @@ var
 begin
   m := FieldSize;
 
-  K := 31 - TBitUtilities.NumberOfLeadingZeros(m);
+  K := 31 - TBitUtilities.NumberOfLeadingZeros32(m);
   mk := 1;
 
   tr := Self as IECFieldElement;
@@ -3457,8 +3457,11 @@ end;
 
 class function TAbstractF2mCurve.Inverse(m: Int32;
   const ks: TCryptoLibInt32Array; const x: TBigInteger): TBigInteger;
+var
+  LA: TLongArray;
 begin
-  result := TLongArray.Create(x).ModInverse(m, ks).ToBigInteger();
+  LA := TLongArray.Create(x);
+  result := LA.ModInverse(m, ks).ToBigInteger();
 end;
 
 function TAbstractF2mCurve.IsValidFieldElement(const x: TBigInteger): Boolean;
@@ -3651,7 +3654,7 @@ function TF2mCurve.CreateCacheSafeLookupTable(const points
   : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
 var
   FE_LONGS, position, i: Int32;
-  table: TCryptoLibInt64Array;
+  table: TCryptoLibUInt64Array;
   P: IECPoint;
 begin
   FE_LONGS := (m + 63) div 64;
@@ -3809,7 +3812,7 @@ end;
 { TDefaultF2mLookupTable }
 
 constructor TDefaultF2mLookupTable.Create(const outer: IF2mCurve;
-  const table: TCryptoLibInt64Array; Size: Int32);
+  const table: TCryptoLibUInt64Array; Size: Int32);
 begin
   Inherited Create();
   Fm_outer := outer;
@@ -3817,12 +3820,13 @@ begin
   Fm_size := Size;
 end;
 
-function TDefaultF2mLookupTable.CreatePoint(const x, y: TCryptoLibInt64Array)
+function TDefaultF2mLookupTable.CreatePoint(const x, y: TCryptoLibUInt64Array)
   : IECPoint;
 var
   XFieldElement, YFieldElement: IECFieldElement;
   m: Int32;
   ks: TCryptoLibInt32Array;
+  LAx, LAy: TLongArray;
 begin
   m := Fm_outer.m;
   if Fm_outer.IsTrinomial() then
@@ -3834,8 +3838,10 @@ begin
     ks := TCryptoLibInt32Array.Create(Fm_outer.k1, Fm_outer.k2, Fm_outer.k3);
   end;
 
-  XFieldElement := TF2mFieldElement.Create(m, ks, TLongArray.Create(x));
-  YFieldElement := TF2mFieldElement.Create(m, ks, TLongArray.Create(y));
+  LAx := TLongArray.Create(x);
+  LAy := TLongArray.Create(y);
+  XFieldElement := TF2mFieldElement.Create(m, ks, LAx);
+  YFieldElement := TF2mFieldElement.Create(m, ks, LAy);
   result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement, false);
 end;
 
@@ -3855,8 +3861,8 @@ end;
 function TDefaultF2mLookupTable.Lookup(index: Int32): IECPoint;
 var
   FE_LONGS, position, i, j: Int32;
-  x, y: TCryptoLibInt64Array;
-  MASK: Int64;
+  x, y: TCryptoLibUInt64Array;
+  MASK: UInt64;
 begin
   FE_LONGS := (Fm_outer.m + 63) div 64;
   System.SetLength(x, FE_LONGS);
@@ -3867,7 +3873,7 @@ begin
   for i := 0 to System.Pred(Fm_size) do
   begin
 
-    MASK := TBitUtilities.Asr32((i xor index) - 1, 31);
+    MASK := UInt64(TBitUtilities.Asr32((i xor index) - 1, 31));
 
     for j := 0 to System.Pred(FE_LONGS) do
     begin
@@ -3883,7 +3889,7 @@ end;
 function TDefaultF2mLookupTable.LookupVar(index: Int32): IECPoint;
 var
   FE_LONGS, position, j: Int32;
-  x, y: TCryptoLibInt64Array;
+  x, y: TCryptoLibUInt64Array;
 begin
   FE_LONGS := (Fm_outer.m + 63) div 64;
   System.SetLength(x, FE_LONGS);

+ 966 - 2341
CryptoLib/src/Math/EC/ClpLongArray.pas

@@ -22,2616 +22,1241 @@ unit ClpLongArray;
 interface
 
 uses
-  Classes,
   SysUtils,
-  StrUtils,
   Math,
+  ClpCryptoLibTypes,
   ClpBitUtilities,
-  ClpBigInteger,
-  ClpCryptoLibTypes;
-
-resourcestring
-  SInvalidF2MFieldValue = 'Invalid F2M Field value, "bigInt"';
+  ClpNat,
+  ClpInterleave,
+  ClpArrayUtilities,
+  ClpBigInteger;
 
 type
   TLongArray = record
-
-  strict private
-
-{$REGION 'Consts'}
-  const
-
-    /// <summary>
-    /// This expands 8 bit indices into 16 bit contents (high bit 14), by
-    /// inserting 0s between bits. In a binary field, this operation is the
-    /// same as squaring an 8 bit number.
-    /// </summary>
-    INTERLEAVE2_TABLE: array [0 .. 255] of UInt16 = ($0000, $0001, $0004, $0005,
-      $0010, $0011, $0014, $0015, $0040, $0041, $0044, $0045, $0050, $0051,
-      $0054, $0055, $0100, $0101, $0104, $0105, $0110, $0111, $0114, $0115,
-      $0140, $0141, $0144, $0145, $0150, $0151, $0154, $0155, $0400, $0401,
-      $0404, $0405, $0410, $0411, $0414, $0415, $0440, $0441, $0444, $0445,
-      $0450, $0451, $0454, $0455, $0500, $0501, $0504, $0505, $0510, $0511,
-      $0514, $0515, $0540, $0541, $0544, $0545, $0550, $0551, $0554, $0555,
-      $1000, $1001, $1004, $1005, $1010, $1011, $1014, $1015, $1040, $1041,
-      $1044, $1045, $1050, $1051, $1054, $1055, $1100, $1101, $1104, $1105,
-      $1110, $1111, $1114, $1115, $1140, $1141, $1144, $1145, $1150, $1151,
-      $1154, $1155, $1400, $1401, $1404, $1405, $1410, $1411, $1414, $1415,
-      $1440, $1441, $1444, $1445, $1450, $1451, $1454, $1455, $1500, $1501,
-      $1504, $1505, $1510, $1511, $1514, $1515, $1540, $1541, $1544, $1545,
-      $1550, $1551, $1554, $1555, $4000, $4001, $4004, $4005, $4010, $4011,
-      $4014, $4015, $4040, $4041, $4044, $4045, $4050, $4051, $4054, $4055,
-      $4100, $4101, $4104, $4105, $4110, $4111, $4114, $4115, $4140, $4141,
-      $4144, $4145, $4150, $4151, $4154, $4155, $4400, $4401, $4404, $4405,
-      $4410, $4411, $4414, $4415, $4440, $4441, $4444, $4445, $4450, $4451,
-      $4454, $4455, $4500, $4501, $4504, $4505, $4510, $4511, $4514, $4515,
-      $4540, $4541, $4544, $4545, $4550, $4551, $4554, $4555, $5000, $5001,
-      $5004, $5005, $5010, $5011, $5014, $5015, $5040, $5041, $5044, $5045,
-      $5050, $5051, $5054, $5055, $5100, $5101, $5104, $5105, $5110, $5111,
-      $5114, $5115, $5140, $5141, $5144, $5145, $5150, $5151, $5154, $5155,
-      $5400, $5401, $5404, $5405, $5410, $5411, $5414, $5415, $5440, $5441,
-      $5444, $5445, $5450, $5451, $5454, $5455, $5500, $5501, $5504, $5505,
-      $5510, $5511, $5514, $5515, $5540, $5541, $5544, $5545, $5550, $5551,
-      $5554, $5555);
-
-    /// <summary>
-    /// This expands 7 bit indices into 21 bit contents (high bit 18),
-    /// by inserting 0s between bits.
-    /// </summary>
-    INTERLEAVE3_TABLE: array [0 .. 127] of Int32 = ($00000, $00001, $00008,
-      $00009, $00040, $00041, $00048, $00049, $00200, $00201, $00208, $00209,
-      $00240, $00241, $00248, $00249, $01000, $01001, $01008, $01009, $01040,
-      $01041, $01048, $01049, $01200, $01201, $01208, $01209, $01240, $01241,
-      $01248, $01249, $08000, $08001, $08008, $08009, $08040, $08041, $08048,
-      $08049, $08200, $08201, $08208, $08209, $08240, $08241, $08248, $08249,
-      $09000, $09001, $09008, $09009, $09040, $09041, $09048, $09049, $09200,
-      $09201, $09208, $09209, $09240, $09241, $09248, $09249, $40000, $40001,
-      $40008, $40009, $40040, $40041, $40048, $40049, $40200, $40201, $40208,
-      $40209, $40240, $40241, $40248, $40249, $41000, $41001, $41008, $41009,
-      $41040, $41041, $41048, $41049, $41200, $41201, $41208, $41209, $41240,
-      $41241, $41248, $41249, $48000, $48001, $48008, $48009, $48040, $48041,
-      $48048, $48049, $48200, $48201, $48208, $48209, $48240, $48241, $48248,
-      $48249, $49000, $49001, $49008, $49009, $49040, $49041, $49048, $49049,
-      $49200, $49201, $49208, $49209, $49240, $49241, $49248, $49249);
-
-    /// <summary>
-    /// This expands 8 bit indices into 32 bit contents (high bit 28), by
-    /// inserting 0s between bits.
-    /// </summary>
-    INTERLEAVE4_TABLE: array [0 .. 255] of Int32 = ($00000000, $00000001,
-      $00000010, $00000011, $00000100, $00000101, $00000110, $00000111,
-      $00001000, $00001001, $00001010, $00001011, $00001100, $00001101,
-      $00001110, $00001111, $00010000, $00010001, $00010010, $00010011,
-      $00010100, $00010101, $00010110, $00010111, $00011000, $00011001,
-      $00011010, $00011011, $00011100, $00011101, $00011110, $00011111,
-      $00100000, $00100001, $00100010, $00100011, $00100100, $00100101,
-      $00100110, $00100111, $00101000, $00101001, $00101010, $00101011,
-      $00101100, $00101101, $00101110, $00101111, $00110000, $00110001,
-      $00110010, $00110011, $00110100, $00110101, $00110110, $00110111,
-      $00111000, $00111001, $00111010, $00111011, $00111100, $00111101,
-      $00111110, $00111111, $01000000, $01000001, $01000010, $01000011,
-      $01000100, $01000101, $01000110, $01000111, $01001000, $01001001,
-      $01001010, $01001011, $01001100, $01001101, $01001110, $01001111,
-      $01010000, $01010001, $01010010, $01010011, $01010100, $01010101,
-      $01010110, $01010111, $01011000, $01011001, $01011010, $01011011,
-      $01011100, $01011101, $01011110, $01011111, $01100000, $01100001,
-      $01100010, $01100011, $01100100, $01100101, $01100110, $01100111,
-      $01101000, $01101001, $01101010, $01101011, $01101100, $01101101,
-      $01101110, $01101111, $01110000, $01110001, $01110010, $01110011,
-      $01110100, $01110101, $01110110, $01110111, $01111000, $01111001,
-      $01111010, $01111011, $01111100, $01111101, $01111110, $01111111,
-      $10000000, $10000001, $10000010, $10000011, $10000100, $10000101,
-      $10000110, $10000111, $10001000, $10001001, $10001010, $10001011,
-      $10001100, $10001101, $10001110, $10001111, $10010000, $10010001,
-      $10010010, $10010011, $10010100, $10010101, $10010110, $10010111,
-      $10011000, $10011001, $10011010, $10011011, $10011100, $10011101,
-      $10011110, $10011111, $10100000, $10100001, $10100010, $10100011,
-      $10100100, $10100101, $10100110, $10100111, $10101000, $10101001,
-      $10101010, $10101011, $10101100, $10101101, $10101110, $10101111,
-      $10110000, $10110001, $10110010, $10110011, $10110100, $10110101,
-      $10110110, $10110111, $10111000, $10111001, $10111010, $10111011,
-      $10111100, $10111101, $10111110, $10111111, $11000000, $11000001,
-      $11000010, $11000011, $11000100, $11000101, $11000110, $11000111,
-      $11001000, $11001001, $11001010, $11001011, $11001100, $11001101,
-      $11001110, $11001111, $11010000, $11010001, $11010010, $11010011,
-      $11010100, $11010101, $11010110, $11010111, $11011000, $11011001,
-      $11011010, $11011011, $11011100, $11011101, $11011110, $11011111,
-      $11100000, $11100001, $11100010, $11100011, $11100100, $11100101,
-      $11100110, $11100111, $11101000, $11101001, $11101010, $11101011,
-      $11101100, $11101101, $11101110, $11101111, $11110000, $11110001,
-      $11110010, $11110011, $11110100, $11110101, $11110110, $11110111,
-      $11111000, $11111001, $11111010, $11111011, $11111100, $11111101,
-      $11111110, $11111111);
-
-    /// <summary>
-    /// This expands 7 bit indices into 35 bit contents (high bit 30), by
-    /// inserting 0s between bits.
-    /// </summary>
-    INTERLEAVE5_TABLE: array [0 .. 127] of Int32 = ($00000000, $00000001,
-      $00000020, $00000021, $00000400, $00000401, $00000420, $00000421,
-      $00008000, $00008001, $00008020, $00008021, $00008400, $00008401,
-      $00008420, $00008421, $00100000, $00100001, $00100020, $00100021,
-      $00100400, $00100401, $00100420, $00100421, $00108000, $00108001,
-      $00108020, $00108021, $00108400, $00108401, $00108420, $00108421,
-      $02000000, $02000001, $02000020, $02000021, $02000400, $02000401,
-      $02000420, $02000421, $02008000, $02008001, $02008020, $02008021,
-      $02008400, $02008401, $02008420, $02008421, $02100000, $02100001,
-      $02100020, $02100021, $02100400, $02100401, $02100420, $02100421,
-      $02108000, $02108001, $02108020, $02108021, $02108400, $02108401,
-      $02108420, $02108421, $40000000, $40000001, $40000020, $40000021,
-      $40000400, $40000401, $40000420, $40000421, $40008000, $40008001,
-      $40008020, $40008021, $40008400, $40008401, $40008420, $40008421,
-      $40100000, $40100001, $40100020, $40100021, $40100400, $40100401,
-      $40100420, $40100421, $40108000, $40108001, $40108020, $40108021,
-      $40108400, $40108401, $40108420, $40108421, $42000000, $42000001,
-      $42000020, $42000021, $42000400, $42000401, $42000420, $42000421,
-      $42008000, $42008001, $42008020, $42008021, $42008400, $42008401,
-      $42008420, $42008421, $42100000, $42100001, $42100020, $42100021,
-      $42100400, $42100401, $42100420, $42100421, $42108000, $42108001,
-      $42108020, $42108021, $42108400, $42108401, $42108420, $42108421);
-
-    /// <summary>
-    /// This expands 9 bit indices into 63 bit (long) contents (high bit
-    /// 56), by inserting 0s between bits.
-    /// </summary>
-    INTERLEAVE7_TABLE: array [0 .. 511] of Int64 = (Int64($0000000000000000),
-      Int64($0000000000000001), Int64($0000000000000080),
-      Int64($0000000000000081), Int64($0000000000004000),
-      Int64($0000000000004001), Int64($0000000000004080),
-      Int64($0000000000004081), Int64($0000000000200000),
-      Int64($0000000000200001), Int64($0000000000200080),
-      Int64($0000000000200081), Int64($0000000000204000),
-      Int64($0000000000204001), Int64($0000000000204080),
-      Int64($0000000000204081), Int64($0000000010000000),
-      Int64($0000000010000001), Int64($0000000010000080),
-      Int64($0000000010000081), Int64($0000000010004000),
-      Int64($0000000010004001), Int64($0000000010004080),
-      Int64($0000000010004081), Int64($0000000010200000),
-      Int64($0000000010200001), Int64($0000000010200080),
-      Int64($0000000010200081), Int64($0000000010204000),
-      Int64($0000000010204001), Int64($0000000010204080),
-      Int64($0000000010204081), Int64($0000000800000000),
-      Int64($0000000800000001), Int64($0000000800000080),
-      Int64($0000000800000081), Int64($0000000800004000),
-      Int64($0000000800004001), Int64($0000000800004080),
-      Int64($0000000800004081), Int64($0000000800200000),
-      Int64($0000000800200001), Int64($0000000800200080),
-      Int64($0000000800200081), Int64($0000000800204000),
-      Int64($0000000800204001), Int64($0000000800204080),
-      Int64($0000000800204081), Int64($0000000810000000),
-      Int64($0000000810000001), Int64($0000000810000080),
-      Int64($0000000810000081), Int64($0000000810004000),
-      Int64($0000000810004001), Int64($0000000810004080),
-      Int64($0000000810004081), Int64($0000000810200000),
-      Int64($0000000810200001), Int64($0000000810200080),
-      Int64($0000000810200081), Int64($0000000810204000),
-      Int64($0000000810204001), Int64($0000000810204080),
-      Int64($0000000810204081), Int64($0000040000000000),
-      Int64($0000040000000001), Int64($0000040000000080),
-      Int64($0000040000000081), Int64($0000040000004000),
-      Int64($0000040000004001), Int64($0000040000004080),
-      Int64($0000040000004081), Int64($0000040000200000),
-      Int64($0000040000200001), Int64($0000040000200080),
-      Int64($0000040000200081), Int64($0000040000204000),
-      Int64($0000040000204001), Int64($0000040000204080),
-      Int64($0000040000204081), Int64($0000040010000000),
-      Int64($0000040010000001), Int64($0000040010000080),
-      Int64($0000040010000081), Int64($0000040010004000),
-      Int64($0000040010004001), Int64($0000040010004080),
-      Int64($0000040010004081), Int64($0000040010200000),
-      Int64($0000040010200001), Int64($0000040010200080),
-      Int64($0000040010200081), Int64($0000040010204000),
-      Int64($0000040010204001), Int64($0000040010204080),
-      Int64($0000040010204081), Int64($0000040800000000),
-      Int64($0000040800000001), Int64($0000040800000080),
-      Int64($0000040800000081), Int64($0000040800004000),
-      Int64($0000040800004001), Int64($0000040800004080),
-      Int64($0000040800004081), Int64($0000040800200000),
-      Int64($0000040800200001), Int64($0000040800200080),
-      Int64($0000040800200081), Int64($0000040800204000),
-      Int64($0000040800204001), Int64($0000040800204080),
-      Int64($0000040800204081), Int64($0000040810000000),
-      Int64($0000040810000001), Int64($0000040810000080),
-      Int64($0000040810000081), Int64($0000040810004000),
-      Int64($0000040810004001), Int64($0000040810004080),
-      Int64($0000040810004081), Int64($0000040810200000),
-      Int64($0000040810200001), Int64($0000040810200080),
-      Int64($0000040810200081), Int64($0000040810204000),
-      Int64($0000040810204001), Int64($0000040810204080),
-      Int64($0000040810204081), Int64($0002000000000000),
-      Int64($0002000000000001), Int64($0002000000000080),
-      Int64($0002000000000081), Int64($0002000000004000),
-      Int64($0002000000004001), Int64($0002000000004080),
-      Int64($0002000000004081), Int64($0002000000200000),
-      Int64($0002000000200001), Int64($0002000000200080),
-      Int64($0002000000200081), Int64($0002000000204000),
-      Int64($0002000000204001), Int64($0002000000204080),
-      Int64($0002000000204081), Int64($0002000010000000),
-      Int64($0002000010000001), Int64($0002000010000080),
-      Int64($0002000010000081), Int64($0002000010004000),
-      Int64($0002000010004001), Int64($0002000010004080),
-      Int64($0002000010004081), Int64($0002000010200000),
-      Int64($0002000010200001), Int64($0002000010200080),
-      Int64($0002000010200081), Int64($0002000010204000),
-      Int64($0002000010204001), Int64($0002000010204080),
-      Int64($0002000010204081), Int64($0002000800000000),
-      Int64($0002000800000001), Int64($0002000800000080),
-      Int64($0002000800000081), Int64($0002000800004000),
-      Int64($0002000800004001), Int64($0002000800004080),
-      Int64($0002000800004081), Int64($0002000800200000),
-      Int64($0002000800200001), Int64($0002000800200080),
-      Int64($0002000800200081), Int64($0002000800204000),
-      Int64($0002000800204001), Int64($0002000800204080),
-      Int64($0002000800204081), Int64($0002000810000000),
-      Int64($0002000810000001), Int64($0002000810000080),
-      Int64($0002000810000081), Int64($0002000810004000),
-      Int64($0002000810004001), Int64($0002000810004080),
-      Int64($0002000810004081), Int64($0002000810200000),
-      Int64($0002000810200001), Int64($0002000810200080),
-      Int64($0002000810200081), Int64($0002000810204000),
-      Int64($0002000810204001), Int64($0002000810204080),
-      Int64($0002000810204081), Int64($0002040000000000),
-      Int64($0002040000000001), Int64($0002040000000080),
-      Int64($0002040000000081), Int64($0002040000004000),
-      Int64($0002040000004001), Int64($0002040000004080),
-      Int64($0002040000004081), Int64($0002040000200000),
-      Int64($0002040000200001), Int64($0002040000200080),
-      Int64($0002040000200081), Int64($0002040000204000),
-      Int64($0002040000204001), Int64($0002040000204080),
-      Int64($0002040000204081), Int64($0002040010000000),
-      Int64($0002040010000001), Int64($0002040010000080),
-      Int64($0002040010000081), Int64($0002040010004000),
-      Int64($0002040010004001), Int64($0002040010004080),
-      Int64($0002040010004081), Int64($0002040010200000),
-      Int64($0002040010200001), Int64($0002040010200080),
-      Int64($0002040010200081), Int64($0002040010204000),
-      Int64($0002040010204001), Int64($0002040010204080),
-      Int64($0002040010204081), Int64($0002040800000000),
-      Int64($0002040800000001), Int64($0002040800000080),
-      Int64($0002040800000081), Int64($0002040800004000),
-      Int64($0002040800004001), Int64($0002040800004080),
-      Int64($0002040800004081), Int64($0002040800200000),
-      Int64($0002040800200001), Int64($0002040800200080),
-      Int64($0002040800200081), Int64($0002040800204000),
-      Int64($0002040800204001), Int64($0002040800204080),
-      Int64($0002040800204081), Int64($0002040810000000),
-      Int64($0002040810000001), Int64($0002040810000080),
-      Int64($0002040810000081), Int64($0002040810004000),
-      Int64($0002040810004001), Int64($0002040810004080),
-      Int64($0002040810004081), Int64($0002040810200000),
-      Int64($0002040810200001), Int64($0002040810200080),
-      Int64($0002040810200081), Int64($0002040810204000),
-      Int64($0002040810204001), Int64($0002040810204080),
-      Int64($0002040810204081), Int64($0100000000000000),
-      Int64($0100000000000001), Int64($0100000000000080),
-      Int64($0100000000000081), Int64($0100000000004000),
-      Int64($0100000000004001), Int64($0100000000004080),
-      Int64($0100000000004081), Int64($0100000000200000),
-      Int64($0100000000200001), Int64($0100000000200080),
-      Int64($0100000000200081), Int64($0100000000204000),
-      Int64($0100000000204001), Int64($0100000000204080),
-      Int64($0100000000204081), Int64($0100000010000000),
-      Int64($0100000010000001), Int64($0100000010000080),
-      Int64($0100000010000081), Int64($0100000010004000),
-      Int64($0100000010004001), Int64($0100000010004080),
-      Int64($0100000010004081), Int64($0100000010200000),
-      Int64($0100000010200001), Int64($0100000010200080),
-      Int64($0100000010200081), Int64($0100000010204000),
-      Int64($0100000010204001), Int64($0100000010204080),
-      Int64($0100000010204081), Int64($0100000800000000),
-      Int64($0100000800000001), Int64($0100000800000080),
-      Int64($0100000800000081), Int64($0100000800004000),
-      Int64($0100000800004001), Int64($0100000800004080),
-      Int64($0100000800004081), Int64($0100000800200000),
-      Int64($0100000800200001), Int64($0100000800200080),
-      Int64($0100000800200081), Int64($0100000800204000),
-      Int64($0100000800204001), Int64($0100000800204080),
-      Int64($0100000800204081), Int64($0100000810000000),
-      Int64($0100000810000001), Int64($0100000810000080),
-      Int64($0100000810000081), Int64($0100000810004000),
-      Int64($0100000810004001), Int64($0100000810004080),
-      Int64($0100000810004081), Int64($0100000810200000),
-      Int64($0100000810200001), Int64($0100000810200080),
-      Int64($0100000810200081), Int64($0100000810204000),
-      Int64($0100000810204001), Int64($0100000810204080),
-      Int64($0100000810204081), Int64($0100040000000000),
-      Int64($0100040000000001), Int64($0100040000000080),
-      Int64($0100040000000081), Int64($0100040000004000),
-      Int64($0100040000004001), Int64($0100040000004080),
-      Int64($0100040000004081), Int64($0100040000200000),
-      Int64($0100040000200001), Int64($0100040000200080),
-      Int64($0100040000200081), Int64($0100040000204000),
-      Int64($0100040000204001), Int64($0100040000204080),
-      Int64($0100040000204081), Int64($0100040010000000),
-      Int64($0100040010000001), Int64($0100040010000080),
-      Int64($0100040010000081), Int64($0100040010004000),
-      Int64($0100040010004001), Int64($0100040010004080),
-      Int64($0100040010004081), Int64($0100040010200000),
-      Int64($0100040010200001), Int64($0100040010200080),
-      Int64($0100040010200081), Int64($0100040010204000),
-      Int64($0100040010204001), Int64($0100040010204080),
-      Int64($0100040010204081), Int64($0100040800000000),
-      Int64($0100040800000001), Int64($0100040800000080),
-      Int64($0100040800000081), Int64($0100040800004000),
-      Int64($0100040800004001), Int64($0100040800004080),
-      Int64($0100040800004081), Int64($0100040800200000),
-      Int64($0100040800200001), Int64($0100040800200080),
-      Int64($0100040800200081), Int64($0100040800204000),
-      Int64($0100040800204001), Int64($0100040800204080),
-      Int64($0100040800204081), Int64($0100040810000000),
-      Int64($0100040810000001), Int64($0100040810000080),
-      Int64($0100040810000081), Int64($0100040810004000),
-      Int64($0100040810004001), Int64($0100040810004080),
-      Int64($0100040810004081), Int64($0100040810200000),
-      Int64($0100040810200001), Int64($0100040810200080),
-      Int64($0100040810200081), Int64($0100040810204000),
-      Int64($0100040810204001), Int64($0100040810204080),
-      Int64($0100040810204081), Int64($0102000000000000),
-      Int64($0102000000000001), Int64($0102000000000080),
-      Int64($0102000000000081), Int64($0102000000004000),
-      Int64($0102000000004001), Int64($0102000000004080),
-      Int64($0102000000004081), Int64($0102000000200000),
-      Int64($0102000000200001), Int64($0102000000200080),
-      Int64($0102000000200081), Int64($0102000000204000),
-      Int64($0102000000204001), Int64($0102000000204080),
-      Int64($0102000000204081), Int64($0102000010000000),
-      Int64($0102000010000001), Int64($0102000010000080),
-      Int64($0102000010000081), Int64($0102000010004000),
-      Int64($0102000010004001), Int64($0102000010004080),
-      Int64($0102000010004081), Int64($0102000010200000),
-      Int64($0102000010200001), Int64($0102000010200080),
-      Int64($0102000010200081), Int64($0102000010204000),
-      Int64($0102000010204001), Int64($0102000010204080),
-      Int64($0102000010204081), Int64($0102000800000000),
-      Int64($0102000800000001), Int64($0102000800000080),
-      Int64($0102000800000081), Int64($0102000800004000),
-      Int64($0102000800004001), Int64($0102000800004080),
-      Int64($0102000800004081), Int64($0102000800200000),
-      Int64($0102000800200001), Int64($0102000800200080),
-      Int64($0102000800200081), Int64($0102000800204000),
-      Int64($0102000800204001), Int64($0102000800204080),
-      Int64($0102000800204081), Int64($0102000810000000),
-      Int64($0102000810000001), Int64($0102000810000080),
-      Int64($0102000810000081), Int64($0102000810004000),
-      Int64($0102000810004001), Int64($0102000810004080),
-      Int64($0102000810004081), Int64($0102000810200000),
-      Int64($0102000810200001), Int64($0102000810200080),
-      Int64($0102000810200081), Int64($0102000810204000),
-      Int64($0102000810204001), Int64($0102000810204080),
-      Int64($0102000810204081), Int64($0102040000000000),
-      Int64($0102040000000001), Int64($0102040000000080),
-      Int64($0102040000000081), Int64($0102040000004000),
-      Int64($0102040000004001), Int64($0102040000004080),
-      Int64($0102040000004081), Int64($0102040000200000),
-      Int64($0102040000200001), Int64($0102040000200080),
-      Int64($0102040000200081), Int64($0102040000204000),
-      Int64($0102040000204001), Int64($0102040000204080),
-      Int64($0102040000204081), Int64($0102040010000000),
-      Int64($0102040010000001), Int64($0102040010000080),
-      Int64($0102040010000081), Int64($0102040010004000),
-      Int64($0102040010004001), Int64($0102040010004080),
-      Int64($0102040010004081), Int64($0102040010200000),
-      Int64($0102040010200001), Int64($0102040010200080),
-      Int64($0102040010200081), Int64($0102040010204000),
-      Int64($0102040010204001), Int64($0102040010204080),
-      Int64($0102040010204081), Int64($0102040800000000),
-      Int64($0102040800000001), Int64($0102040800000080),
-      Int64($0102040800000081), Int64($0102040800004000),
-      Int64($0102040800004001), Int64($0102040800004080),
-      Int64($0102040800004081), Int64($0102040800200000),
-      Int64($0102040800200001), Int64($0102040800200080),
-      Int64($0102040800200081), Int64($0102040800204000),
-      Int64($0102040800204001), Int64($0102040800204080),
-      Int64($0102040800204081), Int64($0102040810000000),
-      Int64($0102040810000001), Int64($0102040810000080),
-      Int64($0102040810000081), Int64($0102040810004000),
-      Int64($0102040810004001), Int64($0102040810004080),
-      Int64($0102040810004081), Int64($0102040810200000),
-      Int64($0102040810200001), Int64($0102040810200080),
-      Int64($0102040810200081), Int64($0102040810204000),
-      Int64($0102040810204001), Int64($0102040810204080),
-      Int64($0102040810204081));
-
-    // For toString(); must have length 64
-    ZEROES: String =
-      '0000000000000000000000000000000000000000000000000000000000000000';
-
-{$ENDREGION}
-
-    // TODO make m fixed for the LongArray, and hence compute T once and for all
-
-  var
-
-    Fm_ints: TCryptoLibInt64Array;
-
-    function GetLength: Int32; inline;
-
-    function DegreeFrom(limit: Int32): Int32;
-    function ResizedInts(newLen: Int32): TCryptoLibInt64Array; inline;
-    procedure AddShiftedByBitsSafe(const other: TLongArray;
-      otherDegree, bits: Int32);
-
-    class function ShiftUp(const x: TCryptoLibInt64Array;
-      xOff, count, shift: Int32): Int64; overload; static;
-    class function ShiftUp(const x: TCryptoLibInt64Array; xOff: Int32;
-      const z: TCryptoLibInt64Array; zOff, count, shift: Int32): Int64;
-      overload; static;
-    class function BitLength(w: Int64): Int32; static;
-    class function AddShiftedUp(const x: TCryptoLibInt64Array; xOff: Int32;
-      const y: TCryptoLibInt64Array; yOff, count, shift: Int32): Int64;
-      static; inline;
-    class function AddShiftedDown(const x: TCryptoLibInt64Array; xOff: Int32;
-      const y: TCryptoLibInt64Array; yOff, count, shift: Int32): Int64;
-      static; inline;
-    class procedure Add(const x: TCryptoLibInt64Array; xOff: Int32;
-      const y: TCryptoLibInt64Array; yOff, count: Int32); overload;
-      static; inline;
-    class procedure Add(const x: TCryptoLibInt64Array; xOff: Int32;
-      const y: TCryptoLibInt64Array; yOff: Int32; const z: TCryptoLibInt64Array;
-      zOff, count: Int32); overload; static; inline;
-
-    class procedure AddBoth(const x: TCryptoLibInt64Array; xOff: Int32;
-      const y1: TCryptoLibInt64Array; y1Off: Int32;
-      const y2: TCryptoLibInt64Array; y2Off, count: Int32); static; inline;
-
-    class procedure Distribute(const x: TCryptoLibInt64Array;
-      src, dst1, dst2, count: Int32); static; inline;
-
-    class procedure FlipWord(const buf: TCryptoLibInt64Array; off, bit: Int32;
-      word: Int64); static; inline;
-
-    class function TestBit(const buf: TCryptoLibInt64Array; off, n: Int32)
-      : Boolean; static; inline;
-
-    class procedure FlipBit(const buf: TCryptoLibInt64Array; off, n: Int32);
-      static; inline;
-
-    class procedure MultiplyWord(a: Int64; const b: TCryptoLibInt64Array;
-      bLen: Int32; const c: TCryptoLibInt64Array; cOff: Int32); static; inline;
-
-    class function ReduceResult(const buf: TCryptoLibInt64Array;
-      off, len, m: Int32; const ks: TCryptoLibInt32Array): TLongArray;
-      static; inline;
-
-    class function ReduceInPlace(const buf: TCryptoLibInt64Array;
-      off, len, m: Int32; const ks: TCryptoLibInt32Array): Int32; static;
-
-    class procedure ReduceBitWise(const buf: TCryptoLibInt64Array;
-      off, BitLength, m: Int32; const ks: TCryptoLibInt32Array); static; inline;
-
-    class procedure ReduceBit(const buf: TCryptoLibInt64Array;
-      off, bit, m: Int32; const ks: TCryptoLibInt32Array); static; inline;
-
-    class procedure ReduceWordWise(const buf: TCryptoLibInt64Array;
-      off, len, toBit, m: Int32; const ks: TCryptoLibInt32Array); static;
-
-    class procedure ReduceWord(const buf: TCryptoLibInt64Array; off, bit: Int32;
-      word: Int64; m: Int32; const ks: TCryptoLibInt32Array); static; inline;
-
-    class procedure ReduceVectorWise(const buf: TCryptoLibInt64Array;
-      off, len, words, m: Int32; const ks: TCryptoLibInt32Array);
-      static; inline;
-
-    class procedure FlipVector(const x: TCryptoLibInt64Array; xOff: Int32;
-      const y: TCryptoLibInt64Array; yOff, yLen, bits: Int32); static;
-
-    class procedure SquareInPlace(const x: TCryptoLibInt64Array; xLen: Int32);
-      static; inline;
-
-    class procedure Interleave(const x: TCryptoLibInt64Array; xOff: Int32;
-      const z: TCryptoLibInt64Array; zOff, count, width: Int32); static; inline;
-
-    class procedure Interleave3(const x: TCryptoLibInt64Array; xOff: Int32;
-      const z: TCryptoLibInt64Array; zOff, count: Int32); overload;
-      static; inline;
-
-    class function Interleave3(x: Int64): Int64; overload; static; inline;
-
-    class function Interleave3_21to63(x: Int32): Int64; static; inline;
-
-    class procedure Interleave5(const x: TCryptoLibInt64Array; xOff: Int32;
-      const z: TCryptoLibInt64Array; zOff, count: Int32); overload;
-      static; inline;
-
-    class function Interleave5(x: Int64): Int64; overload; static; inline;
-
-    class function Interleave3_13to65(x: Int32): Int64; static; inline;
-
-    class procedure Interleave7(const x: TCryptoLibInt64Array; xOff: Int32;
-      const z: TCryptoLibInt64Array; zOff, count: Int32); overload;
-      static; inline;
-
-    class function Interleave7(x: Int64): Int64; overload; static; inline;
-
-    class procedure Interleave2_n(const x: TCryptoLibInt64Array; xOff: Int32;
-      const z: TCryptoLibInt64Array; zOff, count, rounds: Int32); overload;
-      static; inline;
-
-    class function Interleave2_n(x: Int64; rounds: Int32): Int64; overload;
-      static; inline;
-
-    class function Interleave4_16to64(x: Int32): Int64; static; inline;
-
-    class function Interleave2_32to64(x: Int32): Int64; static; inline;
-
-    class function Int64ToBin(input: Int64): string; static;
-
+  private
+    FData: TCryptoLibUInt64Array;
+
+    class function BitLength(AW: UInt64): Int32; overload; static;
+    class function ShiftUp(const AX: TCryptoLibUInt64Array; AXOff, ACount, AShift: Int32): UInt64; overload; static;
+    class function ShiftUp(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AZ: TCryptoLibUInt64Array; AZOff, ACount, AShift: Int32): UInt64; overload; static;
+    class function AddShiftedUp(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, ACount, AShift: Int32): UInt64; static;
+    class function AddShiftedDown(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, ACount, AShift: Int32): UInt64; static;
+    class procedure Add(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, ACount: Int32); overload; static;
+    class procedure Add(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff: Int32; const AZ: TCryptoLibUInt64Array; AZOff, ACount: Int32); overload; static;
+    class procedure AddBoth(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY1: TCryptoLibUInt64Array; AY1Off: Int32; const AY2: TCryptoLibUInt64Array; AY2Off, ACount: Int32); static;
+    class procedure FlipWord(ABuf: TCryptoLibUInt64Array; AOff, ABit: Int32; AWord: UInt64); static;
+    class function TestBit(const ABuf: TCryptoLibUInt64Array; AOff, AN: Int32): Boolean; static;
+    class procedure FlipBit(ABuf: TCryptoLibUInt64Array; AOff, AN: Int32); static;
+    class procedure MultiplyWord(AA: UInt64; const AB: TCryptoLibUInt64Array; ABLen: Int32; AC: TCryptoLibUInt64Array; ACOff: Int32); static;
+    function DegreeFrom(ALimit: Int32): Int32;
+    function ResizedData(ANewLen: Int32): TCryptoLibUInt64Array;
+    procedure AddShiftedByBitsSafe(const AOther: TLongArray; AOtherDegree, ABits: Int32);
+    class function ReduceResult(const ABuf: TCryptoLibUInt64Array; AOff, ALen, AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray; static;
+    class function ReduceInPlace(ABuf: TCryptoLibUInt64Array; AOff, ALen, AM: Int32; const AKs: TCryptoLibInt32Array): Int32; static;
+    class procedure ReduceBitWise(ABuf: TCryptoLibUInt64Array; AOff, ABitLength, AM: Int32; const AKs: TCryptoLibInt32Array); static;
+    class procedure ReduceBit(ABuf: TCryptoLibUInt64Array; AOff, ABit, AM: Int32; const AKs: TCryptoLibInt32Array); static;
+    class procedure ReduceWordWise(ABuf: TCryptoLibUInt64Array; AOff, ALen, AToBit, AM: Int32; const AKs: TCryptoLibInt32Array); static;
+    class procedure ReduceWord(ABuf: TCryptoLibUInt64Array; AOff, ABit: Int32; AWord: UInt64; AM: Int32; const AKs: TCryptoLibInt32Array); static;
+    class procedure ReduceVectorWise(ABuf: TCryptoLibUInt64Array; AOff, ALen, AWords, AM: Int32; const AKs: TCryptoLibInt32Array); static;
+    class procedure FlipVector(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, AYLen, ABits: Int32); static;
   public
-{$REGION 'Consts'}
-    const
-    BitLengths: array [0 .. 255] of Byte = (0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
-      4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
-      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-      6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8);
-
-{$ENDREGION}
-    constructor Create(intLen: Int32); overload;
-    constructor Create(const ints: TCryptoLibInt64Array); overload;
-    constructor Create(const ints: TCryptoLibInt64Array;
-      off, len: Int32); overload;
-    constructor Create(const bigInt: TBigInteger); overload;
-
-    procedure CopyTo(const z: TCryptoLibInt64Array; zOff: Int32);
-
-    function IsOne(): Boolean; inline;
-    function IsZero(): Boolean; inline;
-    function GetUsedLength(): Int32; inline;
-    function GetUsedLengthFrom(from: Int32): Int32;
-    function Degree(): Int32; inline;
+    class function AreAliased(const A, B: TLongArray): Boolean; static;
+    constructor Create(AIntLen: Int32); overload;
+    constructor Create(const AData: TCryptoLibUInt64Array); overload;
+    constructor Create(const AData: TCryptoLibUInt64Array; AOff, ALen: Int32); overload;
+    constructor Create(const ABigInt: TBigInteger); overload;
+
+    procedure CopyTo(const AZ: TCryptoLibUInt64Array; AZOff: Int32);
+    function IsOne(): Boolean;
+    function IsZero(): Boolean;
+    function GetUsedLength(): Int32;
+    function GetUsedLengthFrom(AFrom: Int32): Int32;
+    function Degree(): Int32;
+    function BitLength(): Int32; overload; inline;
     function ToBigInteger(): TBigInteger;
-    function AddOne(): TLongArray; inline;
-    procedure AddShiftedByWords(const other: TLongArray; words: Int32); inline;
-
+    function AddOne(): TLongArray;
+    procedure AddShiftedByWords(const AOther: TLongArray; AWords: Int32);
     function TestBitZero(): Boolean;
-
-    function ModMultiplyLD(const other: TLongArray; m: Int32;
-      const ks: TCryptoLibInt32Array): TLongArray;
-
-    function ModMultiply(const other: TLongArray; m: Int32;
-      const ks: TCryptoLibInt32Array): TLongArray;
-
-    function ModMultiplyAlt(const other: TLongArray; m: Int32;
-      const ks: TCryptoLibInt32Array): TLongArray;
-
-    function ModReduce(m: Int32; const ks: TCryptoLibInt32Array)
-      : TLongArray; inline;
-
-    function Multiply(const other: TLongArray): TLongArray;
-
-    procedure Reduce(m: Int32; const ks: TCryptoLibInt32Array); inline;
-
-    function ModSquare(m: Int32; const ks: TCryptoLibInt32Array)
-      : TLongArray; inline;
-
-    function ModSquareN(n, m: Int32; const ks: TCryptoLibInt32Array)
-      : TLongArray; inline;
-
-    function Square(): TLongArray; inline;
-
-    function ModInverse(m: Int32; const ks: TCryptoLibInt32Array): TLongArray;
-
-    function Copy(): TLongArray; inline;
-
-    function Equals(const other: TLongArray): Boolean; inline;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-    inline;
-{$ENDIF DELPHI}
-    function ToString(): String; inline;
-    property Length: Int32 read GetLength;
-
+    function ModMultiplyLD(const AOther: TLongArray; AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+    function ModMultiply(const AOther: TLongArray; AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+    function Multiply(const AOther: TLongArray): TLongArray; overload;
+    function Multiply(const AOther: TLongArray; AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray; overload;
+    procedure Reduce(AM: Int32; const AKs: TCryptoLibInt32Array);
+    function ModSquare(AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+    function ModSquareN(AN, AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+    function Square(AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+    function ModInverse(AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+    function Copy(): TLongArray;
+    function Equals(const AOther: TLongArray): Boolean;
+    function GetHashCode(): Int32;
+    function ToString(): String;
   end;
 
+resourcestring
+  SInvalidF2mFieldValue = 'invalid F2m field value';
+
 implementation
 
-{ TLongArray }
+uses
+  ClpBigIntegers;
 
-class function TLongArray.TestBit(const buf: TCryptoLibInt64Array;
-  off, n: Int32): Boolean;
-var
-  theInt, theBit: Int32;
-  tester: Int64;
-begin
-  // theInt = n / 64
-  theInt := Int32(UInt32(n) shr 6);
-  // theBit = n % 64
-  theBit := n and $3F;
-  tester := Int64(1) shl theBit;
-  Result := (buf[off + theInt] and tester) <> 0;
-end;
+{ TLongArray }
 
-class procedure TLongArray.FlipBit(const buf: TCryptoLibInt64Array;
-  off, n: Int32);
-var
-  theInt, theBit: Int32;
-  flipper: Int64;
+class function TLongArray.AreAliased(const A, B: TLongArray): Boolean;
 begin
-  // theInt = n / 64
-  theInt := Int32(UInt32(n) shr 6);
-  // theBit = n % 64
-  theBit := n and $3F;
-  flipper := Int64(1) shl theBit;
-  buf[off + theInt] := buf[off + theInt] xor flipper;
+  Result := A.FData = B.FData;
 end;
 
-class procedure TLongArray.ReduceBit(const buf: TCryptoLibInt64Array;
-  off, bit, m: Int32; const ks: TCryptoLibInt32Array);
-var
-  n, j: Int32;
+constructor TLongArray.Create(AIntLen: Int32);
 begin
-  FlipBit(buf, off, bit);
-  n := bit - m;
-  j := System.Length(ks);
-  System.Dec(j);
-  while (j >= 0) do
-  begin
-    FlipBit(buf, off, ks[j] + n);
-    System.Dec(j);
-  end;
-  FlipBit(buf, off, n);
+  System.SetLength(Self.FData, AIntLen);
 end;
 
-class procedure TLongArray.ReduceBitWise(const buf: TCryptoLibInt64Array;
-  off, BitLength, m: Int32; const ks: TCryptoLibInt32Array);
+constructor TLongArray.Create(const AData: TCryptoLibUInt64Array);
 begin
-  System.Dec(BitLength);
-  while (BitLength >= m) do
-  begin
-    if (TestBit(buf, off, BitLength)) then
-    begin
-      ReduceBit(buf, off, BitLength, m, ks);
-    end;
-    System.Dec(BitLength);
-  end;
+  Self.FData := AData;
 end;
 
-class procedure TLongArray.ReduceVectorWise(const buf: TCryptoLibInt64Array;
-  off, len, words, m: Int32; const ks: TCryptoLibInt32Array);
+constructor TLongArray.Create(const AData: TCryptoLibUInt64Array; AOff, ALen: Int32);
 var
-  baseBit, j: Int32;
+  LData: TCryptoLibUInt64Array;
 begin
-  // /*
-  // * NOTE: It's important we go from highest coefficient to lowest, because for the highest
-  // * one (only) we allow the ranges to partially overlap, and therefore any changes must take
-  // * effect for the subsequent lower coefficients.
-  // */
-  baseBit := (words shl 6) - m;
-  j := System.Length(ks);
-  System.Dec(j);
-  while (j >= 0) do
+  if (AOff = 0) and (ALen = System.Length(AData)) then
+    Self.FData := AData
+  else
   begin
-    FlipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]);
-    System.Dec(j);
+    LData := System.Copy(AData, AOff, ALen);
+    Self.FData := LData;
   end;
-  FlipVector(buf, off, buf, off + words, len - words, baseBit);
 end;
 
-class function TLongArray.ReduceInPlace(const buf: TCryptoLibInt64Array;
-  off, len, m: Int32; const ks: TCryptoLibInt32Array): Int32;
+constructor TLongArray.Create(const ABigInt: TBigInteger);
 var
-  mLen, numBits, excessBits, kLen, kMax, kNext, wordWiseLimit, vectorableWords,
-    vectorWiseWords: Int32;
+  LBarr: TCryptoLibByteArray;
+  LBarrLen, LBarrStart, LIntLen, LIarrJ, LRem, LBarrI, I: Int32;
+  LTemp: UInt64;
 begin
-  mLen := TBitUtilities.Asr32((m + 63), 6);
-  if (len < mLen) then
-  begin
-    Result := len;
-    Exit;
-  end;
+  if (not ABigInt.IsInitialized) or (ABigInt.SignValue < 0) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidF2mFieldValue);
 
-  numBits := Math.Min(len shl 6, (m shl 1) - 1); // TODO use actual degree?
-  excessBits := (len shl 6) - numBits;
-  while (excessBits >= 64) do
+  if ABigInt.SignValue = 0 then
   begin
-    System.Dec(len);
-    excessBits := excessBits - 64;
+    System.SetLength(Self.FData, 1);
+    Self.FData[0] := 0;
+    Exit;
   end;
 
-  kLen := System.Length(ks);
-  kMax := ks[kLen - 1];
-  if kLen > 1 then
-  begin
-    kNext := ks[kLen - 2];
-  end
-  else
+  LBarr := ABigInt.ToByteArray();
+  LBarrLen := System.Length(LBarr);
+  LBarrStart := 0;
+  if LBarr[0] = 0 then
   begin
-    kNext := 0;
+    System.Dec(LBarrLen);
+    LBarrStart := 1;
   end;
+  LIntLen := (LBarrLen + 7) div 8;
+  System.SetLength(Self.FData, LIntLen);
 
-  wordWiseLimit := Math.Max(m, kMax + 64);
-  vectorableWords := TBitUtilities.Asr32((excessBits + Math.Min(numBits - wordWiseLimit,
-    m - kNext)), 6);
-  if (vectorableWords > 1) then
+  LIarrJ := LIntLen - 1;
+  LRem := (LBarrLen mod 8) + LBarrStart;
+  LTemp := 0;
+  LBarrI := LBarrStart;
+  if LBarrStart < LRem then
   begin
-    vectorWiseWords := len - vectorableWords;
-    ReduceVectorWise(buf, off, len, vectorWiseWords, m, ks);
-    while (len > vectorWiseWords) do
+    while LBarrI < LRem do
     begin
-      System.Dec(len);
-      buf[off + len] := Int64(0);
+      LTemp := (LTemp shl 8) or UInt64(LBarr[LBarrI]);
+      System.Inc(LBarrI);
     end;
-    numBits := vectorWiseWords shl 6;
+    Self.FData[LIarrJ] := LTemp;
+    System.Dec(LIarrJ);
   end;
 
-  if (numBits > wordWiseLimit) then
+  while LIarrJ >= 0 do
   begin
-    ReduceWordWise(buf, off, len, wordWiseLimit, m, ks);
-    numBits := wordWiseLimit;
-  end;
-
-  if (numBits > m) then
-  begin
-    ReduceBitWise(buf, off, numBits, m, ks);
+    LTemp := 0;
+    for I := 0 to 7 do
+    begin
+      LTemp := (LTemp shl 8) or UInt64(LBarr[LBarrI]);
+      System.Inc(LBarrI);
+    end;
+    Self.FData[LIarrJ] := LTemp;
+    System.Dec(LIarrJ);
   end;
-
-  Result := mLen;
 end;
 
-class function TLongArray.Interleave2_32to64(x: Int32): Int64;
+procedure TLongArray.CopyTo(const AZ: TCryptoLibUInt64Array; AZOff: Int32);
 var
-  r00, r32: Int32;
+  LLen: Int32;
 begin
-  r00 := INTERLEAVE2_TABLE[x and $FF] or INTERLEAVE2_TABLE
-    [(UInt32(x) shr 8) and $FF] shl 16;
-  r32 := INTERLEAVE2_TABLE[(UInt32(x) shr 16) and $FF] or
-    INTERLEAVE2_TABLE[UInt32(x) shr 24] shl 16;
-  Result := (r32 and Int64($FFFFFFFF)) shl 32 or (r00 and Int64($FFFFFFFF));
+  LLen := System.Length(FData);
+  if LLen > 0 then
+    System.Move(FData[0], AZ[AZOff], LLen * SizeOf(UInt64));
 end;
 
-class procedure TLongArray.SquareInPlace(const x: TCryptoLibInt64Array;
-  xLen: Int32);
+function TLongArray.IsOne(): Boolean;
 var
-  pos: Int32;
-  xVal: Int64;
+  LA: TCryptoLibUInt64Array;
+  LALen, I: Int32;
 begin
-  pos := xLen shl 1;
-  System.Dec(xLen);
-
-  while (xLen >= 0) do
-  begin
-    xVal := x[xLen];
-    System.Dec(pos);
-    x[pos] := Interleave2_32to64(Int32(UInt64(xVal) shr 32));
-    System.Dec(pos);
-    x[pos] := Interleave2_32to64(Int32(xVal));
-    System.Dec(xLen);
-  end;
+  LA := FData;
+  LALen := System.Length(LA);
+  if (LALen < 1) or (LA[0] <> 1) then
+    Exit(False);
+  for I := 1 to LALen - 1 do
+    if LA[I] <> 0 then
+      Exit(False);
+  Result := True;
 end;
 
-class function TLongArray.Interleave3_21to63(x: Int32): Int64;
+function TLongArray.IsZero(): Boolean;
 var
-  r00, r21, r42: Int32;
+  LA: TCryptoLibUInt64Array;
+  I: Int32;
 begin
-  r00 := INTERLEAVE3_TABLE[x and $7F];
-  r21 := INTERLEAVE3_TABLE[(UInt32(x) shr 7) and $7F];
-  r42 := INTERLEAVE3_TABLE[UInt32(x) shr 14];
-  Result := (r42 and Int64($FFFFFFFF)) shl 42 or (r21 and Int64($FFFFFFFF))
-    shl 21 or (r00 and Int64($FFFFFFFF));
+  LA := FData;
+  for I := 0 to System.Length(LA) - 1 do
+    if LA[I] <> 0 then
+      Exit(False);
+  Result := True;
 end;
 
-class function TLongArray.Interleave3(x: Int64): Int64;
-var
-  z: Int64;
+function TLongArray.GetUsedLength(): Int32;
 begin
-  z := x and (Int64(1) shl 63);
-  Result := z or Interleave3_21to63(Int32(x) and $1FFFFF) or
-    Interleave3_21to63(Int32(UInt64(x) shr 21) and $1FFFFF) shl 1 or
-    Interleave3_21to63(Int32(UInt64(x) shr 42) and $1FFFFF) shl 2;
+  Result := GetUsedLengthFrom(System.Length(FData));
 end;
 
-class procedure TLongArray.Interleave3(const x: TCryptoLibInt64Array;
-  xOff: Int32; const z: TCryptoLibInt64Array; zOff, count: Int32);
+function TLongArray.GetUsedLengthFrom(AFrom: Int32): Int32;
 var
-  I: Int32;
+  LA: TCryptoLibUInt64Array;
 begin
-  for I := 0 to System.Pred(count) do
+  LA := FData;
+  AFrom := Min(AFrom, System.Length(LA));
+  if AFrom < 1 then
+    Exit(0);
+
+  if LA[0] <> 0 then
   begin
-    z[zOff + I] := Interleave3(x[xOff + I]);
+    repeat
+      System.Dec(AFrom);
+      if LA[AFrom] <> 0 then
+        Break;
+    until False;
+    Exit(AFrom + 1);
   end;
-end;
 
-class function TLongArray.Interleave3_13to65(x: Int32): Int64;
-var
-  r00, r35: Int32;
-begin
-  r00 := INTERLEAVE5_TABLE[x and $7F];
-  r35 := INTERLEAVE5_TABLE[UInt32(x) shr 7];
-  Result := (r35 and Int64($FFFFFFFF)) shl 35 or (r00 and Int64($FFFFFFFF));
+  repeat
+    System.Dec(AFrom);
+    if LA[AFrom] <> 0 then
+      Exit(AFrom + 1);
+  until AFrom <= 0;
+  Result := 0;
 end;
 
-class function TLongArray.Interleave5(x: Int64): Int64;
+class function TLongArray.BitLength(AW: UInt64): Int32;
 begin
-  Result := Interleave3_13to65(Int32(x) and $1FFF) or
-    Interleave3_13to65(Int32(UInt64(x) shr 13) and $1FFF) shl 1 or
-    Interleave3_13to65(Int32(UInt64(x) shr 26) and $1FFF) shl 2 or
-    Interleave3_13to65(Int32(UInt64(x) shr 39) and $1FFF) shl 3 or
-    Interleave3_13to65(Int32(UInt64(x) shr 52) and $1FFF) shl 4;
+  Result := 64 - TBitUtilities.NumberOfLeadingZeros64(AW);
 end;
 
-class procedure TLongArray.Interleave5(const x: TCryptoLibInt64Array;
-  xOff: Int32; const z: TCryptoLibInt64Array; zOff, count: Int32);
+function TLongArray.Degree(): Int32;
 var
   I: Int32;
+  LW: UInt64;
 begin
-  for I := 0 to System.Pred(count) do
-  begin
-    z[zOff + I] := Interleave5(x[xOff + I]);
-  end;
-end;
-
-class function TLongArray.Interleave7(x: Int64): Int64;
-var
-  z: Int64;
-begin
-  z := x and (Int64(1) shl 63);
-  Result := z or INTERLEAVE7_TABLE[Int32(x) and $1FF] or
-    INTERLEAVE7_TABLE[Int32(UInt64(x) shr 9) and $1FF] shl 1 or
-    INTERLEAVE7_TABLE[Int32(UInt64(x) shr 18) and $1FF] shl 2 or
-    INTERLEAVE7_TABLE[Int32(UInt64(x) shr 27) and $1FF] shl 3 or
-    INTERLEAVE7_TABLE[Int32(UInt64(x) shr 36) and $1FF] shl 4 or
-    INTERLEAVE7_TABLE[Int32(UInt64(x) shr 45) and $1FF] shl 5 or
-    INTERLEAVE7_TABLE[Int32(UInt64(x) shr 54) and $1FF] shl 6;
+  I := System.Length(FData);
+  repeat
+    if I = 0 then
+      Exit(0);
+    System.Dec(I);
+    LW := FData[I];
+  until LW <> 0;
+  Result := (I shl 6) + BitLength(LW);
 end;
 
-class procedure TLongArray.Interleave7(const x: TCryptoLibInt64Array;
-  xOff: Int32; const z: TCryptoLibInt64Array; zOff, count: Int32);
+function TLongArray.DegreeFrom(ALimit: Int32): Int32;
 var
   I: Int32;
+  LW: UInt64;
 begin
-  for I := 0 to System.Pred(count) do
-  begin
-    z[zOff + I] := Interleave7(x[xOff + I]);
-  end;
+  I := Int32((UInt32(ALimit) + 62) shr 6);
+  repeat
+    if I = 0 then
+      Exit(0);
+    System.Dec(I);
+    LW := FData[I];
+  until LW <> 0;
+  Result := (I shl 6) + BitLength(LW);
 end;
 
-class function TLongArray.Interleave4_16to64(x: Int32): Int64;
+function TLongArray.ResizedData(ANewLen: Int32): TCryptoLibUInt64Array;
 var
-  r00, r32: Int32;
+  LCount: Int32;
 begin
-  r00 := INTERLEAVE4_TABLE[x and $FF];
-  r32 := INTERLEAVE4_TABLE[UInt32(x) shr 8];
-  Result := (r32 and Int64($FFFFFFFF)) shl 32 or (r00 and Int64($FFFFFFFF));
+  System.SetLength(Result, ANewLen);
+  LCount := Min(System.Length(FData), ANewLen);
+  if LCount > 0 then
+    System.Move(FData[0], Result[0], LCount * SizeOf(UInt64));
 end;
 
-class function TLongArray.Interleave2_n(x: Int64; rounds: Int32): Int64;
-begin
-  while (rounds > 1) do
-  begin
-    rounds := rounds - 2;
-    x := Interleave4_16to64(Int32(x) and $FFFF) or
-      Interleave4_16to64(Int32(UInt64(x) shr 16) and $FFFF) shl 1 or
-      Interleave4_16to64(Int32(UInt64(x) shr 32) and $FFFF) shl 2 or
-      Interleave4_16to64(Int32(UInt64(x) shr 48) and $FFFF) shl 3;
+function TLongArray.ToBigInteger(): TBigInteger;
+var
+  LUsedLen, LBarrI, LBarrLen, LJ, LIarrJ: Int32;
+  LHighestInt: UInt64;
+  LTemp: TCryptoLibByteArray;
+  LTrailingZeroBytesDone: Boolean;
+  LThisByte: Byte;
+  LBarr: TCryptoLibByteArray;
+  LMI: UInt64;
+begin
+  LUsedLen := GetUsedLength();
+  if LUsedLen = 0 then
+    Exit(TBigIntegers.Zero);
+
+  LHighestInt := FData[LUsedLen - 1];
+  System.SetLength(LTemp, 8);
+  LBarrI := 0;
+  LTrailingZeroBytesDone := False;
+  for LJ := 7 downto 0 do
+  begin
+    LThisByte := Byte(LHighestInt shr (8 * LJ));
+    if LTrailingZeroBytesDone or (LThisByte <> 0) then
+    begin
+      LTrailingZeroBytesDone := True;
+      LTemp[LBarrI] := LThisByte;
+      System.Inc(LBarrI);
+    end;
   end;
-  if (rounds > 0) then
+
+  LBarrLen := 8 * (LUsedLen - 1) + LBarrI;
+  System.SetLength(LBarr, LBarrLen);
+  for LJ := 0 to LBarrI - 1 do
+    LBarr[LJ] := LTemp[LJ];
+
+  for LIarrJ := LUsedLen - 2 downto 0 do
   begin
-    x := Interleave2_32to64(Int32(x)) or
-      Interleave2_32to64(Int32(UInt64(x) shr 32)) shl 1;
+    LMI := FData[LIarrJ];
+    for LJ := 7 downto 0 do
+    begin
+      LBarr[LBarrI] := Byte(LMI shr (8 * LJ));
+      System.Inc(LBarrI);
+    end;
   end;
-  Result := x;
+  Result := TBigInteger.Create(1, LBarr);
 end;
 
-class procedure TLongArray.Interleave2_n(const x: TCryptoLibInt64Array;
-  xOff: Int32; const z: TCryptoLibInt64Array; zOff, count, rounds: Int32);
+class function TLongArray.ShiftUp(const AX: TCryptoLibUInt64Array; AXOff, ACount, AShift: Int32): UInt64;
 var
+  LShiftInv: Int32;
+  LPrev: UInt64;
   I: Int32;
+  LNext: UInt64;
 begin
-  for I := 0 to System.Pred(count) do
+  LShiftInv := 64 - AShift;
+  LPrev := 0;
+  for I := 0 to ACount - 1 do
   begin
-    z[zOff + I] := Interleave2_n(x[xOff + I], rounds);
+    LNext := AX[AXOff + I];
+    AX[AXOff + I] := (LNext shl AShift) or LPrev;
+    LPrev := LNext shr LShiftInv;
   end;
+  Result := LPrev;
 end;
 
-class procedure TLongArray.Add(const x: TCryptoLibInt64Array; xOff: Int32;
-  const y: TCryptoLibInt64Array; yOff: Int32; const z: TCryptoLibInt64Array;
-  zOff, count: Int32);
+class function TLongArray.ShiftUp(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AZ: TCryptoLibUInt64Array; AZOff, ACount, AShift: Int32): UInt64;
 var
+  LShiftInv: Int32;
+  LPrev: UInt64;
   I: Int32;
+  LNext: UInt64;
 begin
-  for I := 0 to System.Pred(count) do
+  LShiftInv := 64 - AShift;
+  LPrev := 0;
+  for I := 0 to ACount - 1 do
   begin
-    z[zOff + I] := x[xOff + I] xor y[yOff + I];
+    LNext := AX[AXOff + I];
+    AZ[AZOff + I] := (LNext shl AShift) or LPrev;
+    LPrev := LNext shr LShiftInv;
   end;
+  Result := LPrev;
 end;
 
-class procedure TLongArray.Add(const x: TCryptoLibInt64Array; xOff: Int32;
-  const y: TCryptoLibInt64Array; yOff, count: Int32);
+class function TLongArray.AddShiftedUp(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, ACount, AShift: Int32): UInt64;
 var
+  LShiftInv: Int32;
+  LPrev: UInt64;
   I: Int32;
+  LNext: UInt64;
 begin
-  for I := 0 to System.Pred(count) do
+  LShiftInv := 64 - AShift;
+  LPrev := 0;
+  for I := 0 to ACount - 1 do
   begin
-    x[xOff + I] := x[xOff + I] xor y[yOff + I];
+    LNext := AY[AYOff + I];
+    AX[AXOff + I] := AX[AXOff + I] xor ((LNext shl AShift) or LPrev);
+    LPrev := LNext shr LShiftInv;
   end;
+  Result := LPrev;
 end;
 
-class procedure TLongArray.AddBoth(const x: TCryptoLibInt64Array; xOff: Int32;
-  const y1: TCryptoLibInt64Array; y1Off: Int32; const y2: TCryptoLibInt64Array;
-  y2Off, count: Int32);
+class function TLongArray.AddShiftedDown(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, ACount, AShift: Int32): UInt64;
 var
+  LShiftInv: Int32;
+  LPrev: UInt64;
   I: Int32;
+  LNext: UInt64;
 begin
-  for I := 0 to System.Pred(count) do
+  LShiftInv := 64 - AShift;
+  LPrev := 0;
+  I := ACount;
+  while True do
   begin
-    x[xOff + I] := x[xOff + I] xor (y1[y1Off + I] xor y2[y2Off + I]);
+    System.Dec(I);
+    if I < 0 then
+      Break;
+    LNext := AY[AYOff + I];
+    AX[AXOff + I] := AX[AXOff + I] xor ((LNext shr AShift) or LPrev);
+    LPrev := LNext shl LShiftInv;
   end;
+  Result := LPrev;
 end;
 
-function TLongArray.GetUsedLength: Int32;
+class procedure TLongArray.Add(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, ACount: Int32);
 begin
-  Result := GetUsedLengthFrom(System.Length(Fm_ints));
+  TNat.XorTo64(ACount, AY, AYOff, AX, AXOff);
 end;
 
-function TLongArray.ResizedInts(newLen: Int32): TCryptoLibInt64Array;
+class procedure TLongArray.Add(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff: Int32; const AZ: TCryptoLibUInt64Array; AZOff, ACount: Int32);
 begin
-  System.SetLength(Result, newLen);
-  System.Move(Fm_ints[0], Result[0], Math.Min(System.Length(Fm_ints), newLen) *
-    System.SizeOf(Int64));
+  TNat.Xor64(ACount, AX, AXOff, AY, AYOff, AZ, AZOff);
 end;
 
-function TLongArray.AddOne: TLongArray;
+class procedure TLongArray.AddBoth(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY1: TCryptoLibUInt64Array; AY1Off: Int32; const AY2: TCryptoLibUInt64Array; AY2Off, ACount: Int32);
 var
-  resultLen: Int32;
-  ints: TCryptoLibInt64Array;
+  I: Int32;
 begin
-  if (System.Length(Fm_ints) = 0) then
+  for I := 0 to ACount - 1 do
+    AX[AXOff + I] := AX[AXOff + I] xor (AY1[AY1Off + I] xor AY2[AY2Off + I]);
+end;
+
+procedure TLongArray.AddShiftedByBitsSafe(const AOther: TLongArray; AOtherDegree, ABits: Int32);
+var
+  LOtherLen, LWords, LShift: Int32;
+  LCarry: UInt64;
+begin
+  LOtherLen := Int32((UInt32(AOtherDegree + 63) shr 6));
+  LWords := Int32(UInt32(ABits) shr 6);
+  LShift := ABits and $3F;
+  if LShift = 0 then
+    Add(FData, LWords, AOther.FData, 0, LOtherLen)
+  else
   begin
-    Result := TLongArray.Create(TCryptoLibInt64Array.Create(Int64(1)));
-    Exit;
+    LCarry := AddShiftedUp(FData, LWords, AOther.FData, 0, LOtherLen, LShift);
+    if LCarry <> 0 then
+      FData[LOtherLen + LWords] := FData[LOtherLen + LWords] xor LCarry;
   end;
-
-  resultLen := Math.Max(1, GetUsedLength());
-  ints := ResizedInts(resultLen);
-  ints[0] := ints[0] xor Int64(1);
-  Result := TLongArray.Create(ints);
 end;
 
-class function TLongArray.AddShiftedUp(const x: TCryptoLibInt64Array;
-  xOff: Int32; const y: TCryptoLibInt64Array; yOff, count, shift: Int32): Int64;
+procedure TLongArray.AddShiftedByWords(const AOther: TLongArray; AWords: Int32);
 var
-  shiftInv, I: Int32;
-  prev, next: Int64;
+  LOtherUsedLen, LMinLen: Int32;
 begin
-  shiftInv := 64 - shift;
-  prev := 0;
-  for I := 0 to System.Pred(count) do
+  LOtherUsedLen := AOther.GetUsedLength();
+  if LOtherUsedLen = 0 then
+    Exit;
+  LMinLen := LOtherUsedLen + AWords;
+  if LMinLen > System.Length(FData) then
+    FData := ResizedData(LMinLen);
+  Add(FData, AWords, AOther.FData, 0, LOtherUsedLen);
+end;
 
+class procedure TLongArray.FlipWord(ABuf: TCryptoLibUInt64Array; AOff, ABit: Int32; AWord: UInt64);
+var
+  LN: Int32;
+  LShift: Int32;
+begin
+  LN := AOff + Int32(UInt32(ABit) shr 6);
+  LShift := ABit and $3F;
+  if LShift = 0 then
+    ABuf[LN] := ABuf[LN] xor AWord
+  else
   begin
-    next := y[yOff + I];
-    x[xOff + I] := x[xOff + I] xor ((next shl shift) or prev);
-    prev := Int64(UInt64(next) shr shiftInv);
+    ABuf[LN] := ABuf[LN] xor (AWord shl LShift);
+    AWord := AWord shr (64 - LShift);
+    if AWord <> 0 then
+    begin
+      System.Inc(LN);
+      ABuf[LN] := ABuf[LN] xor AWord;
+    end;
   end;
-  Result := prev;
 end;
 
-procedure TLongArray.AddShiftedByBitsSafe(const other: TLongArray;
-  otherDegree, bits: Int32);
-var
-  otherLen, words, shift: Int32;
-  carry: Int64;
+function TLongArray.TestBitZero(): Boolean;
 begin
-  otherLen := Int32(UInt32(otherDegree + 63) shr 6);
+  Result := (System.Length(FData) > 0) and ((FData[0] and 1) <> 0);
+end;
 
-  words := Int32(UInt32(bits) shr 6);
-  shift := bits and $3F;
+class function TLongArray.TestBit(const ABuf: TCryptoLibUInt64Array; AOff, AN: Int32): Boolean;
+var
+  LTheInt: Int32;
+  LTheBit: Int32;
+  LTester: UInt64;
+begin
+  LTheInt := Int32(UInt32(AN) shr 6);
+  LTheBit := AN and $3F;
+  LTester := UInt64(1) shl LTheBit;
+  Result := (ABuf[AOff + LTheInt] and LTester) <> 0;
+end;
 
-  if (shift = 0) then
-  begin
-    Add(Fm_ints, words, other.Fm_ints, 0, otherLen);
-    Exit;
-  end;
+class procedure TLongArray.FlipBit(ABuf: TCryptoLibUInt64Array; AOff, AN: Int32);
+var
+  LTheInt: Int32;
+  LTheBit: Int32;
+  LFlipper: UInt64;
+begin
+  LTheInt := Int32(UInt32(AN) shr 6);
+  LTheBit := AN and $3F;
+  LFlipper := UInt64(1) shl LTheBit;
+  ABuf[AOff + LTheInt] := ABuf[AOff + LTheInt] xor LFlipper;
+end;
 
-  carry := AddShiftedUp(Fm_ints, words, other.Fm_ints, 0, otherLen, shift);
-  if (carry <> Int64(0)) then
+class procedure TLongArray.MultiplyWord(AA: UInt64; const AB: TCryptoLibUInt64Array; ABLen: Int32; AC: TCryptoLibUInt64Array; ACOff: Int32);
+var
+  LK: Int32;
+  LCarry: UInt64;
+begin
+  if (AA and 1) <> 0 then
+    Add(AC, ACOff, AB, 0, ABLen);
+  LK := 1;
+  AA := AA shr 1;
+  while AA <> 0 do
   begin
-    Fm_ints[otherLen + words] := Fm_ints[otherLen + words] xor carry;
+    if (AA and 1) <> 0 then
+    begin
+      LCarry := AddShiftedUp(AC, ACOff, AB, 0, ABLen, LK);
+      if LCarry <> 0 then
+        AC[ACOff + ABLen] := AC[ACOff + ABLen] xor LCarry;
+    end;
+    System.Inc(LK);
+    AA := AA shr 1;
   end;
 end;
 
-procedure TLongArray.AddShiftedByWords(const other: TLongArray; words: Int32);
+class procedure TLongArray.ReduceBit(ABuf: TCryptoLibUInt64Array; AOff, ABit, AM: Int32; const AKs: TCryptoLibInt32Array);
 var
-  otherUsedLen, minLen: Int32;
+  LN: Int32;
+  LJ: Int32;
 begin
-  otherUsedLen := other.GetUsedLength();
-  if (otherUsedLen = 0) then
+  FlipBit(ABuf, AOff, ABit);
+  LN := ABit - AM;
+  LJ := System.Length(AKs);
+  while True do
   begin
-    Exit;
+    System.Dec(LJ);
+    if LJ < 0 then
+      Break;
+    FlipBit(ABuf, AOff, AKs[LJ] + LN);
   end;
+  FlipBit(ABuf, AOff, LN);
+end;
 
-  minLen := otherUsedLen + words;
-  if (minLen > System.Length(Fm_ints)) then
+class procedure TLongArray.ReduceBitWise(ABuf: TCryptoLibUInt64Array; AOff, ABitLength, AM: Int32; const AKs: TCryptoLibInt32Array);
+begin
+  while True do
   begin
-    Fm_ints := ResizedInts(minLen);
+    System.Dec(ABitLength);
+    if ABitLength < AM then
+      Break;
+    if TestBit(ABuf, AOff, ABitLength) then
+      ReduceBit(ABuf, AOff, ABitLength, AM, AKs);
   end;
-
-  Add(Fm_ints, words, other.Fm_ints, 0, otherUsedLen);
 end;
 
-class function TLongArray.AddShiftedDown(const x: TCryptoLibInt64Array;
-  xOff: Int32; const y: TCryptoLibInt64Array; yOff, count, shift: Int32): Int64;
+class procedure TLongArray.ReduceWord(ABuf: TCryptoLibUInt64Array; AOff, ABit: Int32; AWord: UInt64; AM: Int32; const AKs: TCryptoLibInt32Array);
 var
-  shiftInv, I: Int32;
-  prev, next: Int64;
+  LOffset: Int32;
+  LJ: Int32;
 begin
-  shiftInv := 64 - shift;
-  prev := 0;
-  I := count;
+  LOffset := ABit - AM;
+  LJ := System.Length(AKs);
+  while True do
+  begin
+    System.Dec(LJ);
+    if LJ < 0 then
+      Break;
+    FlipWord(ABuf, AOff, LOffset + AKs[LJ], AWord);
+  end;
+  FlipWord(ABuf, AOff, LOffset, AWord);
+end;
 
-  System.Dec(I);
-  while I >= 0 do
+class procedure TLongArray.ReduceWordWise(ABuf: TCryptoLibUInt64Array; AOff, ALen, AToBit, AM: Int32; const AKs: TCryptoLibInt32Array);
+var
+  LToPos: Int32;
+  LPartial: Int32;
+  LWord: UInt64;
+begin
+  LToPos := Int32(UInt32(AToBit) shr 6);
+  while True do
+  begin
+    System.Dec(ALen);
+    if ALen <= LToPos then
+      Break;
+    LWord := ABuf[AOff + ALen];
+    if LWord <> 0 then
+    begin
+      ABuf[AOff + ALen] := 0;
+      ReduceWord(ABuf, AOff, ALen shl 6, LWord, AM, AKs);
+    end;
+  end;
+  LPartial := AToBit and $3F;
+  LWord := ABuf[AOff + LToPos] shr LPartial;
+  if LWord <> 0 then
   begin
-    next := y[yOff + I];
-    x[xOff + I] := x[xOff + I] xor (Int64(UInt64(next) shr shift) or prev);
-    prev := next shl shiftInv;
-    System.Dec(I);
+    ABuf[AOff + LToPos] := ABuf[AOff + LToPos] xor (LWord shl LPartial);
+    ReduceWord(ABuf, AOff, AToBit, LWord, AM, AKs);
   end;
-  Result := prev;
 end;
 
-class function TLongArray.BitLength(w: Int64): Int32;
+class procedure TLongArray.FlipVector(const AX: TCryptoLibUInt64Array; AXOff: Int32; const AY: TCryptoLibUInt64Array; AYOff, AYLen, ABits: Int32);
 var
-  u, b, t, k, v: Int32;
+  LCarry: UInt64;
 begin
-  u := Int32(UInt64(w) shr 32);
-  if (u = 0) then
-  begin
-    u := Int32(w);
-    b := 0;
-  end
+  AXOff := AXOff + Int32(UInt32(ABits) shr 6);
+  ABits := ABits and $3F;
+  if ABits = 0 then
+    Add(AX, AXOff, AY, AYOff, AYLen)
   else
   begin
-    b := 32;
+    LCarry := AddShiftedDown(AX, AXOff + 1, AY, AYOff, AYLen, 64 - ABits);
+    AX[AXOff] := AX[AXOff] xor LCarry;
   end;
+end;
 
-  t := Int32(UInt32(u) shr 16);
-  if (t = 0) then
+class procedure TLongArray.ReduceVectorWise(ABuf: TCryptoLibUInt64Array; AOff, ALen, AWords, AM: Int32; const AKs: TCryptoLibInt32Array);
+var
+  LBaseBit: Int32;
+  LJ: Int32;
+begin
+  LBaseBit := (AWords shl 6) - AM;
+  LJ := System.Length(AKs);
+  while True do
   begin
-    t := Int32(UInt32(u) shr 8);
-    if (t = 0) then
-    begin
-      k := BitLengths[u];
-    end
-    else
-    begin
-      k := 8 + BitLengths[t];
-    end;
+    System.Dec(LJ);
+    if LJ < 0 then
+      Break;
+    FlipVector(ABuf, AOff, ABuf, AOff + AWords, ALen - AWords, LBaseBit + AKs[LJ]);
+  end;
+  FlipVector(ABuf, AOff, ABuf, AOff + AWords, ALen - AWords, LBaseBit);
+end;
 
-  end
+class function TLongArray.ReduceInPlace(ABuf: TCryptoLibUInt64Array; AOff, ALen, AM: Int32; const AKs: TCryptoLibInt32Array): Int32;
+var
+  LMLen: Int32;
+  LNumBits: Int32;
+  LExcessBits: Int32;
+  LKLen, LKMax, LKNext: Int32;
+  LWordWiseLimit: Int32;
+  LVectorableWords: Int32;
+  LVectorWiseWords: Int32;
+begin
+  LMLen := TBitUtilities.Asr32(AM + 63, 6);
+  if ALen < LMLen then
+    Exit(ALen);
+
+  LNumBits := Min(ALen shl 6, (AM shl 1) - 1);
+  LExcessBits := (ALen shl 6) - LNumBits;
+  while LExcessBits >= 64 do
+  begin
+    System.Dec(ALen);
+    LExcessBits := LExcessBits - 64;
+  end;
+
+  LKLen := System.Length(AKs);
+  LKMax := AKs[LKLen - 1];
+  if LKLen > 1 then
+    LKNext := AKs[LKLen - 2]
   else
-  begin
-    v := Int32(UInt32(t) shr 8);
-
-    if (v = 0) then
+    LKNext := 0;
+  LWordWiseLimit := Max(AM, LKMax + 64);
+  LVectorableWords := TBitUtilities.Asr32(LExcessBits + Min(LNumBits - LWordWiseLimit, AM - LKNext), 6);
+  if LVectorableWords > 1 then
+  begin
+    LVectorWiseWords := ALen - LVectorableWords;
+    ReduceVectorWise(ABuf, AOff, ALen, LVectorWiseWords, AM, AKs);
+    while ALen > LVectorWiseWords do
     begin
-      k := 16 + BitLengths[t];
-    end
-    else
-    begin
-      k := 24 + BitLengths[v];
+      System.Dec(ALen);
+      ABuf[AOff + ALen] := 0;
     end;
-
+    LNumBits := LVectorWiseWords shl 6;
   end;
 
-  Result := b + k;
-end;
-
-function TLongArray.Copy: TLongArray;
-begin
-  Result := TLongArray.Create(System.Copy(Fm_ints));
-end;
-
-constructor TLongArray.Create(const ints: TCryptoLibInt64Array;
-  off, len: Int32);
-begin
-  if ((off = 0) and (len = System.Length(ints))) then
-  begin
-    Fm_ints := ints;
-  end
-  else
+  if LNumBits > LWordWiseLimit then
   begin
-    System.SetLength(Fm_ints, len);
-    System.Move(ints[off], Fm_ints[0], len * System.SizeOf(Int64));
+    ReduceWordWise(ABuf, AOff, ALen, LWordWiseLimit, AM, AKs);
+    LNumBits := LWordWiseLimit;
   end;
-end;
 
-constructor TLongArray.Create(const ints: TCryptoLibInt64Array);
-begin
-  Fm_ints := ints;
+  if LNumBits > AM then
+    ReduceBitWise(ABuf, AOff, LNumBits, AM, AKs);
+
+  Result := LMLen;
 end;
 
-constructor TLongArray.Create(intLen: Int32);
+class function TLongArray.ReduceResult(const ABuf: TCryptoLibUInt64Array; AOff, ALen, AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+var
+  RLen: Int32;
 begin
-  System.SetLength(Fm_ints, intLen);
+  RLen := ReduceInPlace(ABuf, AOff, ALen, AM, AKs);
+  Result := TLongArray.Create(ABuf, AOff, RLen);
 end;
 
-constructor TLongArray.Create(const bigInt: TBigInteger);
+function TLongArray.AddOne(): TLongArray;
 var
-  barr: TCryptoLibByteArray;
-  barrLen, barrStart, intLen, iarrJ, rem, barrI, I: Int32;
-  temp: Int64;
-  barrBarrI: UInt32;
+  LResultLen: Int32;
+  LData: TCryptoLibUInt64Array;
 begin
-  if (not(bigInt.IsInitialized) or (bigInt.SignValue < 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidF2MFieldValue);
-  end;
+  if System.Length(FData) = 0 then
+    Exit(TLongArray.Create(TCryptoLibUInt64Array.Create(1)));
+  LResultLen := Max(1, GetUsedLength());
+  LData := ResizedData(LResultLen);
+  LData[0] := LData[0] xor 1;
+  Result := TLongArray.Create(LData);
+end;
 
-  if (bigInt.SignValue = 0) then
-  begin
-    Fm_ints := TCryptoLibInt64Array.Create(Int64(0));
+function TLongArray.ModMultiplyLD(const AOther: TLongArray; AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+var
+  LADeg, LBDeg, LALen, LBLen, LCLen: Int32;
+  LA, LB: TLongArray;
+  LA0: UInt64;
+  LC0: TCryptoLibUInt64Array;
+  LBMax, LTOff, I: Int32;
+  LTi: TCryptoLibInt32Array;
+  LT0, LT1: TCryptoLibUInt64Array;
+  LAArr: TCryptoLibUInt64Array;
+  LC: TCryptoLibUInt64Array;
+  LMask: UInt32;
+  LK, LJ: Int32;
+  LAVal: UInt32;
+  LU, LV: UInt32;
+begin
+  LADeg := Degree();
+  if LADeg = 0 then
+    Exit(Self);
+  LBDeg := AOther.Degree();
+  if LBDeg = 0 then
+    Exit(AOther);
+
+  LA := Self;
+  LB := AOther;
+  if LADeg > LBDeg then
+  begin
+    LA := AOther;
+    LB := Self;
+    LADeg := LBDeg;
+    LBDeg := Degree();
+  end;
+
+  LALen := Int32((UInt32(LADeg + 63) shr 6));
+  LBLen := Int32((UInt32(LBDeg + 63) shr 6));
+  LCLen := Int32((UInt32(LADeg + LBDeg + 62) shr 6));
+
+  if LALen = 1 then
+  begin
+    LA0 := LA.FData[0];
+    if LA0 = 1 then
+      Exit(LB);
+    System.SetLength(LC0, LCLen);
+    MultiplyWord(LA0, LB.FData, LBLen, LC0, 0);
+    Result := ReduceResult(LC0, 0, LCLen, AM, AKs);
     Exit;
   end;
 
-  barr := bigInt.ToByteArray();
-  barrLen := System.Length(barr);
-  barrStart := 0;
-  if (barr[0] = 0) then
+  LBMax := Int32((UInt32(LBDeg + 7 + 63) shr 6));
+  System.SetLength(LTi, 16);
+  System.SetLength(LT0, LBMax shl 4);
+  LTOff := LBMax;
+  LTi[1] := LTOff;
+  for I := 0 to LBLen - 1 do
+    LT0[LTOff + I] := LB.FData[I];
+  for I := 2 to 15 do
   begin
-    // First byte is 0 to enforce highest (=sign) bit is zero.
-    // In this case ignore barr[0].
-    System.Dec(barrLen);
-    barrStart := 1;
+    LTOff := LTOff + LBMax;
+    LTi[I] := LTOff;
+    if (I and 1) = 0 then
+      ShiftUp(LT0, Int32(UInt32(LTOff) shr 1), LT0, LTOff, LBMax, 1)
+    else
+      Add(LT0, LBMax, LT0, LTOff - LBMax, LT0, LTOff, LBMax);
   end;
-  intLen := (barrLen + 7) div 8;
-  System.SetLength(Fm_ints, intLen);
-
-  iarrJ := intLen - 1;
-  rem := (barrLen mod 8) + barrStart;
-  temp := 0;
-  barrI := barrStart;
-  if (barrStart < rem) then
-  begin
-    while (barrI < rem) do
-    begin
-      temp := temp shl 8;
-      barrBarrI := barr[barrI];
-      temp := temp or barrBarrI;
-      System.Inc(barrI);
-    end;
 
-    Fm_ints[iarrJ] := temp;
-    System.Dec(iarrJ);
+  System.SetLength(LT1, System.Length(LT0));
+  ShiftUp(LT0, 0, LT1, 0, System.Length(LT0), 4);
 
-  end;
-
-  while (iarrJ >= 0) do
+  LAArr := LA.FData;
+  System.SetLength(LC, LCLen);
+  LMask := $F;
 
+  LK := 56;
+  while LK >= 0 do
   begin
-    temp := 0;
-    I := 0;
-    while I < 8 do
+    LJ := 1;
+    while LJ < LALen do
     begin
-      temp := temp shl 8;
-      barrBarrI := barr[barrI];
-      System.Inc(barrI);
-      temp := temp or barrBarrI;
-      System.Inc(I);
+      LAVal := UInt32(LAArr[LJ] shr LK);
+      LU := LAVal and LMask;
+      LV := (LAVal shr 4) and LMask;
+      AddBoth(LC, LJ - 1, LT0, LTi[LU], LT1, LTi[LV], LBMax);
+      LJ := LJ + 2;
     end;
-    Fm_ints[iarrJ] := temp;
-    System.Dec(iarrJ);
+    ShiftUp(LC, 0, LCLen, 8);
+    LK := LK - 8;
   end;
-end;
 
-function TLongArray.Degree: Int32;
-var
-  I: Int32;
-  w: Int64;
-begin
-  I := System.Length(Fm_ints);
-  repeat
-    if (I = 0) then
+  LK := 56;
+  while LK >= 0 do
+  begin
+    LJ := 0;
+    while LJ < LALen do
     begin
-      Result := 0;
-      Exit;
+      LAVal := UInt32(LAArr[LJ] shr LK);
+      LU := LAVal and LMask;
+      LV := (LAVal shr 4) and LMask;
+      AddBoth(LC, LJ, LT0, LTi[LU], LT1, LTi[LV], LBMax);
+      LJ := LJ + 2;
     end;
-    System.Dec(I);
-    w := Fm_ints[I];
-  until (not(w = 0));
+    if LK > 0 then
+      ShiftUp(LC, 0, LCLen, 8);
+    LK := LK - 8;
+  end;
 
-  Result := (I shl 6) + BitLength(w);
+  Result := ReduceResult(LC, 0, LCLen, AM, AKs);
 end;
 
-function TLongArray.DegreeFrom(limit: Int32): Int32;
+function TLongArray.ModMultiply(const AOther: TLongArray; AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
 var
-  I: Int32;
-  w: Int64;
-begin
-  I := Int32((UInt32(limit) + 62) shr 6);
-  repeat
-    if (I = 0) then
+  LADeg, LBDeg, LALen, LBLen, LCLen: Int32;
+  LA, LB: TLongArray;
+  LA0: UInt64;
+  LC0: TCryptoLibUInt64Array;
+  LBMax, LTOff, I: Int32;
+  LTi: TCryptoLibInt32Array;
+  LT0, LT1: TCryptoLibUInt64Array;
+  LAArr: TCryptoLibUInt64Array;
+  LC: TCryptoLibUInt64Array;
+  LMask: UInt32;
+  LAPos: Int32;
+  LAVal: UInt64;
+  LCOff: Int32;
+  LU, LV: UInt32;
+  LCOff2: Int32;
+begin
+  LADeg := Degree();
+  if LADeg = 0 then
+    Exit(Self);
+  LBDeg := AOther.Degree();
+  if LBDeg = 0 then
+    Exit(AOther);
+
+  LA := Self;
+  LB := AOther;
+  if LADeg > LBDeg then
+  begin
+    LA := AOther;
+    LB := Self;
+    LADeg := LBDeg;
+    LBDeg := Degree();
+  end;
+
+  LALen := Int32((UInt32(LADeg + 63) shr 6));
+  LBLen := Int32((UInt32(LBDeg + 63) shr 6));
+  LCLen := Int32((UInt32(LADeg + LBDeg + 62) shr 6));
+
+  if LALen = 1 then
+  begin
+    LA0 := LA.FData[0];
+    if LA0 = 1 then
+      Exit(LB);
+    System.SetLength(LC0, LCLen);
+    MultiplyWord(LA0, LB.FData, LBLen, LC0, 0);
+    Exit(ReduceResult(LC0, 0, LCLen, AM, AKs));
+  end;
+
+  LBMax := Int32((UInt32(LBDeg + 7 + 63) shr 6));
+  System.SetLength(LTi, 16);
+  System.SetLength(LT0, LBMax shl 4);
+  LTOff := LBMax;
+  LTi[1] := LTOff;
+  for I := 0 to LBLen - 1 do
+    LT0[LTOff + I] := LB.FData[I];
+  for I := 2 to 15 do
+  begin
+    LTOff := LTOff + LBMax;
+    LTi[I] := LTOff;
+    if (I and 1) = 0 then
+      ShiftUp(LT0, Int32(UInt32(LTOff) shr 1), LT0, LTOff, LBMax, 1)
+    else
+      Add(LT0, LBMax, LT0, LTOff - LBMax, LT0, LTOff, LBMax);
+  end;
+
+  System.SetLength(LT1, System.Length(LT0));
+  ShiftUp(LT0, 0, LT1, 0, System.Length(LT0), 4);
+
+  LAArr := LA.FData;
+  System.SetLength(LC, LCLen shl 3);
+  LMask := $F;
+
+  for LAPos := 0 to LALen - 1 do
+  begin
+    LAVal := LAArr[LAPos];
+    LCOff := LAPos;
+    while True do
     begin
-      Result := 0;
-      Exit;
+      LU := UInt32(LAVal) and LMask;
+      LAVal := LAVal shr 4;
+      LV := UInt32(LAVal) and LMask;
+      LAVal := LAVal shr 4;
+      AddBoth(LC, LCOff, LT0, LTi[LU], LT1, LTi[LV], LBMax);
+      if LAVal = 0 then
+        Break;
+      LCOff := LCOff + LCLen;
     end;
-    System.Dec(I);
-    w := Fm_ints[I];
-  until (not(w = 0));
+  end;
+
+  LCOff2 := System.Length(LC);
+  while True do
+  begin
+    LCOff2 := LCOff2 - LCLen;
+    if LCOff2 <= 0 then
+      Break;
+    AddShiftedUp(LC, LCOff2 - LCLen, LC, LCOff2, LCLen, 8);
+  end;
 
-  Result := (I shl 6) + BitLength(w);
+  Result := ReduceResult(LC, 0, LCLen, AM, AKs);
 end;
 
-class procedure TLongArray.Distribute(const x: TCryptoLibInt64Array;
-  src, dst1, dst2, count: Int32);
-var
-  I: Int32;
-  v: Int64;
+function TLongArray.Multiply(const AOther: TLongArray): TLongArray;
 begin
-  for I := 0 to System.Pred(count) do
-  begin
-    v := x[src + I];
-    x[dst1 + I] := x[dst1 + I] xor v;
-    x[dst2 + I] := x[dst2 + I] xor v;
-  end;
+  Result := Multiply(AOther, 0, nil);
 end;
 
-function TLongArray.Equals(const other: TLongArray): Boolean;
+function TLongArray.Multiply(const AOther: TLongArray; AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
 var
-  usedLen, I: Int32;
-begin
-  usedLen := GetUsedLength();
-  if (other.GetUsedLength() <> usedLen) then
-  begin
-    Result := false;
-    Exit;
+  LADeg, LBDeg, LALen, LBLen, LCLen: Int32;
+  LA, LB: TLongArray;
+  LA0: UInt64;
+  LC0: TCryptoLibUInt64Array;
+  LBMax, LTOff, I: Int32;
+  LTi: TCryptoLibInt32Array;
+  LT0, LT1: TCryptoLibUInt64Array;
+  LAArr: TCryptoLibUInt64Array;
+  LC: TCryptoLibUInt64Array;
+  LMask: UInt32;
+  LAPos: Int32;
+  LAVal: UInt64;
+  LCOff: Int32;
+  LU, LV: UInt32;
+  LCOff2: Int32;
+begin
+  LADeg := Degree();
+  if LADeg = 0 then
+    Exit(Self);
+  LBDeg := AOther.Degree();
+  if LBDeg = 0 then
+    Exit(AOther);
+
+  LA := Self;
+  LB := AOther;
+  if LADeg > LBDeg then
+  begin
+    LA := AOther;
+    LB := Self;
+    LADeg := LBDeg;
+    LBDeg := Degree();
+  end;
+
+  LALen := Int32((UInt32(LADeg + 63) shr 6));
+  LBLen := Int32((UInt32(LBDeg + 63) shr 6));
+  LCLen := Int32((UInt32(LADeg + LBDeg + 62) shr 6));
+
+  if LALen = 1 then
+  begin
+    LA0 := LA.FData[0];
+    if LA0 = 1 then
+      Exit(LB);
+    System.SetLength(LC0, LCLen);
+    MultiplyWord(LA0, LB.FData, LBLen, LC0, 0);
+    Exit(TLongArray.Create(LC0, 0, LCLen));
+  end;
+
+  LBMax := Int32((UInt32(LBDeg + 7 + 63) shr 6));
+  System.SetLength(LTi, 16);
+  System.SetLength(LT0, LBMax shl 4);
+  LTOff := LBMax;
+  LTi[1] := LTOff;
+  for I := 0 to LBLen - 1 do
+    LT0[LTOff + I] := LB.FData[I];
+  for I := 2 to 15 do
+  begin
+    LTOff := LTOff + LBMax;
+    LTi[I] := LTOff;
+    if (I and 1) = 0 then
+      ShiftUp(LT0, Int32(UInt32(LTOff) shr 1), LT0, LTOff, LBMax, 1)
+    else
+      Add(LT0, LBMax, LT0, LTOff - LBMax, LT0, LTOff, LBMax);
   end;
 
-  for I := 0 to System.Pred(usedLen) do
+  System.SetLength(LT1, System.Length(LT0));
+  ShiftUp(LT0, 0, LT1, 0, System.Length(LT0), 4);
 
+  LAArr := LA.FData;
+  System.SetLength(LC, LCLen shl 3);
+  LMask := $F;
+
+  for LAPos := 0 to LALen - 1 do
   begin
-    if (Fm_ints[I] <> other.Fm_ints[I]) then
+    LAVal := LAArr[LAPos];
+    LCOff := LAPos;
+    while True do
     begin
-      Result := false;
-      Exit;
+      LU := UInt32(LAVal) and LMask;
+      LAVal := LAVal shr 4;
+      LV := UInt32(LAVal) and LMask;
+      LAVal := LAVal shr 4;
+      AddBoth(LC, LCOff, LT0, LTi[LU], LT1, LTi[LV], LBMax);
+      if LAVal = 0 then
+        Break;
+      LCOff := LCOff + LCLen;
     end;
   end;
-  Result := true;
-end;
-
-class procedure TLongArray.FlipVector(const x: TCryptoLibInt64Array;
-  xOff: Int32; const y: TCryptoLibInt64Array; yOff, yLen, bits: Int32);
-var
-  carry: Int64;
-begin
-  xOff := xOff + Int32(UInt32(bits) shr 6);
-  bits := bits and $3F;
 
-  if (bits = 0) then
-  begin
-    Add(x, xOff, y, yOff, yLen);
-  end
-  else
+  LCOff2 := System.Length(LC);
+  while True do
   begin
-    carry := AddShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits);
-    x[xOff] := x[xOff] xor carry;
+    LCOff2 := LCOff2 - LCLen;
+    if LCOff2 <= 0 then
+      Break;
+    AddShiftedUp(LC, LCOff2 - LCLen, LC, LCOff2, LCLen, 8);
   end;
+
+  Result := TLongArray.Create(LC, 0, LCLen);
 end;
 
-class procedure TLongArray.FlipWord(const buf: TCryptoLibInt64Array;
-  off, bit: Int32; word: Int64);
+procedure TLongArray.Reduce(AM: Int32; const AKs: TCryptoLibInt32Array);
 var
-  n, shift: Int32;
+  LBuf: TCryptoLibUInt64Array;
+  RLen: Int32;
+  LNewData: TCryptoLibUInt64Array;
 begin
-  n := off + Int32(UInt32(bit) shr 6);
-  shift := bit and $3F;
-  if (shift = 0) then
+  LBuf := FData;
+  RLen := ReduceInPlace(LBuf, 0, System.Length(LBuf), AM, AKs);
+  if RLen < System.Length(LBuf) then
   begin
-    buf[n] := buf[n] xor word;
-  end
-  else
-  begin
-    buf[n] := buf[n] xor (word shl shift);
-    word := Int64(UInt64(word) shr (64 - shift));
-    if (word <> 0) then
-    begin
-      System.Inc(n);
-      buf[n] := buf[n] xor word;
-    end;
+    System.SetLength(LNewData, RLen);
+    if RLen > 0 then
+      System.Move(LBuf[0], LNewData[0], RLen * SizeOf(UInt64));
+    FData := LNewData;
   end;
 end;
 
-function TLongArray.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-
+function TLongArray.ModSquare(AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
 var
-  usedLen, hash, I: Int32;
-  mi: Int64;
+  LLen: Int32;
+  LR: TCryptoLibUInt64Array;
+  RLen: Int32;
 begin
-  usedLen := GetUsedLength();
-  hash := 1;
-  for I := 0 to System.Pred(usedLen) do
+  LLen := GetUsedLength();
+  if LLen = 0 then
+    Exit(Self);
+  System.SetLength(LR, LLen shl 1);
+  TInterleave.Expand64To128(FData, 0, LLen, LR, 0);
+  RLen := ReduceInPlace(LR, 0, System.Length(LR), AM, AKs);
+  Result := TLongArray.Create(LR, 0, RLen);
+end;
 
+function TLongArray.ModSquareN(AN, AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+var
+  LLen: Int32;
+  LMLen: Int32;
+  LR: TCryptoLibUInt64Array;
+  I: Int32;
+begin
+  LLen := GetUsedLength();
+  if LLen = 0 then
+    Exit(Self);
+  LMLen := TBitUtilities.Asr32(AM + 63, 6);
+  System.SetLength(LR, LMLen shl 1);
+  if LLen > 0 then
+    System.Move(FData[0], LR[0], LLen * SizeOf(UInt64));
+  for I := AN - 1 downto 0 do
   begin
-    mi := Fm_ints[I];
-    hash := hash * 31;
-    hash := hash xor Int32(mi);
-    hash := hash * 31;
-    hash := hash xor Int32(UInt64(mi) shr 32);
+    TInterleave.Expand64To128(LR, 0, LLen, LR, 0);
+    LLen := ReduceInPlace(LR, 0, System.Length(LR), AM, AKs);
   end;
-  Result := hash;
+  Result := TLongArray.Create(LR, 0, LLen);
 end;
 
-function TLongArray.GetLength: Int32;
+function TLongArray.Square(AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
+var
+  LLen: Int32;
+  LR: TCryptoLibUInt64Array;
 begin
-  Result := System.Length(Fm_ints);
+  LLen := GetUsedLength();
+  if LLen = 0 then
+    Exit(Self);
+  System.SetLength(LR, LLen shl 1);
+  TInterleave.Expand64To128(FData, 0, LLen, LR, 0);
+  Result := TLongArray.Create(LR, 0, System.Length(LR));
 end;
 
-function TLongArray.GetUsedLengthFrom(from: Int32): Int32;
+function TLongArray.ModInverse(AM: Int32; const AKs: TCryptoLibInt32Array): TLongArray;
 var
-  a: TCryptoLibInt64Array;
-begin
-  a := Fm_ints;
-  from := Math.Min(from, System.Length(a));
-
-  if (from < 1) then
-  begin
-    Result := 0;
-    Exit;
-  end;
-
-  // Check if first element will act as sentinel
-  if (a[0] <> 0) then
-  begin
-    System.Dec(from);
-    while (a[from] = 0) do
+  LUzDegree: Int32;
+  LT: Int32;
+  LUz: TLongArray;
+  LVz: TLongArray;
+  LG1z: TLongArray;
+  LG2z: TLongArray;
+  LUvDeg: TCryptoLibInt32Array;
+  LUv: array [0 .. 1] of TLongArray;
+  LGgDeg: TCryptoLibInt32Array;
+  LGg: array [0 .. 1] of TLongArray;
+  LB, LDuv1, LDgg1, LJ, LDuv2, LDgg2: Int32;
+begin
+  LUzDegree := Degree();
+  if LUzDegree = 0 then
+    raise EArgumentCryptoLibException.Create('');
+  if LUzDegree = 1 then
+    Exit(Self);
+
+  LUz := Copy();
+  LT := TBitUtilities.Asr32(AM + 63, 6);
+
+  LVz := TLongArray.Create(LT);
+  ReduceBit(LVz.FData, 0, AM, AM, AKs);
+
+  LG1z := TLongArray.Create(LT);
+  LG1z.FData[0] := 1;
+  LG2z := TLongArray.Create(LT);
+
+  LUvDeg := TCryptoLibInt32Array.Create(LUzDegree, AM + 1);
+  LUv[0] := LUz;
+  LUv[1] := LVz;
+
+  LGgDeg := TCryptoLibInt32Array.Create(1, 0);
+  LGg[0] := LG1z;
+  LGg[1] := LG2z;
+
+  LB := 1;
+  LDuv1 := LUvDeg[LB];
+  LDgg1 := LGgDeg[LB];
+  LJ := LDuv1 - LUvDeg[1 - LB];
+
+  while True do
+  begin
+    if LJ < 0 then
     begin
-      System.Dec(from);
+      LJ := -LJ;
+      LUvDeg[LB] := LDuv1;
+      LGgDeg[LB] := LDgg1;
+      LB := 1 - LB;
+      LDuv1 := LUvDeg[LB];
+      LDgg1 := LGgDeg[LB];
     end;
-    Result := from + 1;
-    Exit;
-  end;
 
-  repeat
+    LUv[LB].AddShiftedByBitsSafe(LUv[1 - LB], LUvDeg[1 - LB], LJ);
 
-    System.Dec(from);
-    if (a[from] <> 0) then
-    begin
-      Result := from + 1;
-      Exit;
-    end;
-    System.Dec(from);
+    LDuv2 := LUv[LB].DegreeFrom(LDuv1);
+    if LDuv2 = 0 then
+      Exit(LGg[1 - LB]);
 
-  until (not(from > 0));
+    LDgg2 := LGgDeg[1 - LB];
+    LGg[LB].AddShiftedByBitsSafe(LGg[1 - LB], LDgg2, LJ);
+    LDgg2 := LDgg2 + LJ;
 
-  Result := 0;
+    if LDgg2 > LDgg1 then
+      LDgg1 := LDgg2
+    else if LDgg2 = LDgg1 then
+      LDgg1 := LGg[LB].DegreeFrom(LDgg1);
+
+    LJ := LJ + (LDuv2 - LDuv1);
+    LDuv1 := LDuv2;
+  end;
 end;
 
-class procedure TLongArray.Interleave(const x: TCryptoLibInt64Array;
-  xOff: Int32; const z: TCryptoLibInt64Array; zOff, count, width: Int32);
+function TLongArray.Copy(): TLongArray;
+var
+  LCloned: TCryptoLibUInt64Array;
 begin
-  case width of
-    3:
-      Interleave3(x, xOff, z, zOff, count);
-
-    5:
-      Interleave5(x, xOff, z, zOff, count);
-
-    7:
-      Interleave7(x, xOff, z, zOff, count);
-
-  else
-    Interleave2_n(x, xOff, z, zOff, count, BitLengths[width] - 1);
+  LCloned := System.Copy(FData, 0, System.Length(FData));
+  Result := TLongArray.Create(LCloned);
+end;
 
-  end;
+function TLongArray.Equals(const AOther: TLongArray): Boolean;
+var
+  LUsedLen, I: Int32;
+begin
+  if AreAliased(Self, AOther) then
+    Exit(True);
+  LUsedLen := GetUsedLength();
+  if AOther.GetUsedLength() <> LUsedLen then
+    Exit(False);
+  for I := 0 to LUsedLen - 1 do
+    if FData[I] <> AOther.FData[I] then
+      Exit(False);
+  Result := True;
+end;
 
+function TLongArray.GetHashCode(): Int32;
+begin
+  Result := TArrayUtilities.GetArrayHashCode(FData, 0, GetUsedLength());
 end;
 
-class function TLongArray.Int64ToBin(input: Int64): string;
+function TLongArray.ToString(): String;
 var
-  bits: TCryptoLibCharArray;
   I: Int32;
+  LS: String;
+  LW: UInt64;
+  LB: Int32;
 begin
-
+  I := GetUsedLength();
+  if I = 0 then
+    Exit('0');
+  System.Dec(I);
+  LW := FData[I];
   Result := '';
-
-  System.SetLength(bits, System.SizeOf(Int64) * 8);
-
-  I := 0;
-
-  while (input <> 0) do
-  begin
-    if (input and 1) = 1 then
-      bits[I] := '1'
-    else
-    begin
-      bits[I] := '0';
-    end;
-    System.Inc(I);
-    input := input shr 1;
-  end;
-
-  System.SetString(Result, PChar(@bits[0]), I);
-
-  Result := ReverseString(Result);
-
-end;
-
-procedure TLongArray.CopyTo(const z: TCryptoLibInt64Array; zOff: Int32);
-begin
-  System.Move(Fm_ints[0], z[zOff], System.Length(Fm_ints) *
-    System.SizeOf(Int64));
-end;
-
-function TLongArray.IsOne: Boolean;
-var
-  a: TCryptoLibInt64Array;
-  I: Int32;
-begin
-  a := Fm_ints;
-  if (a[0] <> Int64(1)) then
-  begin
-    Result := false;
-    Exit;
-  end;
-
-  for I := 1 to System.Pred(System.Length(a)) do
+  for LB := 63 downto 0 do
+    if (LW shr LB) and 1 <> 0 then
+      Result := Result + '1'
+    else if System.Length(Result) > 0 then
+      Result := Result + '0';
+  if Result = '' then
+    Result := '0';
+  while I > 0 do
   begin
-    if (a[I] <> Int64(0)) then
-    begin
-      Result := false;
-      Exit;
-    end;
+    System.Dec(I);
+    LW := FData[I];
+    LS := '';
+    for LB := 63 downto 0 do
+      if (LW shr LB) and 1 <> 0 then
+        LS := LS + '1'
+      else
+        LS := LS + '0';
+    Result := Result + LS;
   end;
-
-  Result := true;
 end;
 
-function TLongArray.IsZero: Boolean;
+function TLongArray.BitLength(): Int32;
 var
-  a: TCryptoLibInt64Array;
   I: Int32;
+  LW: UInt64;
 begin
-  a := Fm_ints;
-  for I := 0 to System.Pred(System.Length(a)) do
-  begin
-    if (a[I] <> Int64(0)) then
-    begin
-      Result := false;
-      Exit;
-    end;
-  end;
-
-  Result := true;
-end;
-
-function TLongArray.ModInverse(m: Int32; const ks: TCryptoLibInt32Array)
-  : TLongArray;
-var
-  uzDegree, t, b, duv1, dgg1, j, duv2, dgg2: Int32;
-  uz, vz, g1z, g2z: TLongArray;
-  uvDeg, ggDeg: TCryptoLibInt32Array;
-  uv, gg: TCryptoLibGenericArray<TLongArray>;
-begin
-  // /*
-  // * Inversion in F2m using the extended Euclidean algorithm
-  // *
-  // * Input: A nonzero polynomial a(z) of degree at most m-1
-  // * Output: a(z)^(-1) mod f(z)
-  // */
-
-  Result := Default (TLongArray); // to make FixInsight Happy:)
-  uzDegree := Degree();
-  if (uzDegree = 0) then
-  begin
-    raise EInvalidOperationCryptoLibException.Create('');
-  end;
-  if (uzDegree = 1) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-
-  // u(z) := a(z)
-  uz := Copy();
-
-  t := TBitUtilities.Asr32((m + 63), 6);
-
-  // v(z) := f(z)
-  vz := TLongArray.Create(t);
-  ReduceBit(vz.Fm_ints, 0, m, m, ks);
-
-  // g1(z) := 1, g2(z) := 0
-  g1z := TLongArray.Create(t);
-  g1z.Fm_ints[0] := Int64(1);
-  g2z := TLongArray.Create(t);
-
-  uvDeg := TCryptoLibInt32Array.Create(uzDegree, m + 1);
-  uv := TCryptoLibGenericArray<TLongArray>.Create(uz, vz);
-
-  ggDeg := TCryptoLibInt32Array.Create(1, 0);
-  gg := TCryptoLibGenericArray<TLongArray>.Create(g1z, g2z);
-
-  b := 1;
-  duv1 := uvDeg[b];
-  dgg1 := ggDeg[b];
-  j := duv1 - uvDeg[1 - b];
-
-  while true do
-
-  begin
-    if (j < 0) then
-    begin
-      j := -j;
-      uvDeg[b] := duv1;
-      ggDeg[b] := dgg1;
-      b := 1 - b;
-      duv1 := uvDeg[b];
-      dgg1 := ggDeg[b];
-    end;
-
-    uv[b].AddShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j);
-
-    duv2 := uv[b].DegreeFrom(duv1);
-    if (duv2 = 0) then
-    begin
-      Result := gg[1 - b];
-      Exit;
-    end;
-
-    dgg2 := ggDeg[1 - b];
-    gg[b].AddShiftedByBitsSafe(gg[1 - b], dgg2, j);
-    dgg2 := dgg2 + j;
-
-    if (dgg2 > dgg1) then
-    begin
-      dgg1 := dgg2;
-    end
-    else if (dgg2 = dgg1) then
-    begin
-      dgg1 := gg[b].DegreeFrom(dgg1);
-    end;
-
-    j := j + (duv2 - duv1);
-    duv1 := duv2;
-  end;
-end;
-
-class procedure TLongArray.MultiplyWord(a: Int64; const b: TCryptoLibInt64Array;
-  bLen: Int32; const c: TCryptoLibInt64Array; cOff: Int32);
-var
-  k: Int32;
-  carry: Int64;
-begin
-  if ((a and Int64(1)) <> Int64(0)) then
-  begin
-    Add(c, cOff, b, 0, bLen);
-  end;
-  k := 1;
-  a := Int64(UInt64(a) shr 1);
-  while (a <> Int64(0)) do
-  begin
-    if ((a and Int64(1)) <> Int64(0)) then
-    begin
-      carry := AddShiftedUp(c, cOff, b, 0, bLen, k);
-      if (carry <> Int64(0)) then
-      begin
-        c[cOff + bLen] := c[cOff + bLen] xor carry;
-      end;
-    end;
-    System.Inc(k);
-    a := Int64(UInt64(a) shr 1);
-  end;
-end;
-
-class function TLongArray.ReduceResult(const buf: TCryptoLibInt64Array;
-  off, len, m: Int32; const ks: TCryptoLibInt32Array): TLongArray;
-var
-  rLen: Int32;
-begin
-  rLen := ReduceInPlace(buf, off, len, m, ks);
-  Result := TLongArray.Create(buf, off, rLen);
-end;
-
-function TLongArray.ModMultiply(const other: TLongArray; m: Int32;
-  const ks: TCryptoLibInt32Array): TLongArray;
-var
-  aDeg, bDeg, tmp, aLen, bLen, cLen, bMax, tOff, I, MASK, aPos, cOff,
-    u, v: Int32;
-  a, b: TLongArray;
-  c0, T0, T1, aMInts, c: TCryptoLibInt64Array;
-  ti: TCryptoLibInt32Array;
-  a0, aVal: Int64;
-begin
-  // /*
-  // * Find out the degree of each argument and handle the zero cases
-  // */
-  aDeg := Degree();
-  if (aDeg = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-  bDeg := other.Degree();
-  if (bDeg = 0) then
-  begin
-    Result := other;
-    Exit;
-  end;
-
-  // /*
-  // * Swap if necessary so that A is the smaller argument
-  // */
-  a := Self;
-  b := other;
-  if (aDeg > bDeg) then
-  begin
-    a := other;
-    b := Self;
-    tmp := aDeg;
-    aDeg := bDeg;
-    bDeg := tmp;
-  end;
-
-  // /*
-  // * Establish the word lengths of the arguments and result
-  // */
-  aLen := Int32(UInt32(aDeg + 63) shr 6);
-  bLen := Int32(UInt32(bDeg + 63) shr 6);
-  cLen := Int32(UInt32(aDeg + bDeg + 62) shr 6);
-
-  if (aLen = 1) then
-  begin
-    a0 := a.Fm_ints[0];
-    if (a0 = Int64(1)) then
-    begin
-      Result := b;
-      Exit;
-    end;
-
-    // /*
-    // * Fast path for small A, with performance dependent only on the number of set bits
-    // */
-    System.SetLength(c0, cLen);
-    MultiplyWord(a0, b.Fm_ints, bLen, c0, 0);
-
-    // /*
-    // * Reduce the raw answer against the reduction coefficients
-    // */
-    Result := ReduceResult(c0, 0, cLen, m, ks);
-    Exit;
-  end;
-
-  // /*
-  // * Determine if B will get bigger during shifting
-  // */
-  bMax := Int32(UInt32(bDeg + 7 + 63) shr 6);
-
-  // /*
-  // * Lookup table for the offset of each B in the tables
-  // */
-
-  System.SetLength(ti, 16);
-
-  // /*
-  // * Precompute table of all 4-bit products of B
-  // */
-
-  System.SetLength(T0, bMax shl 4);
-  tOff := bMax;
-  ti[1] := tOff;
-  System.Move(b.Fm_ints[0], T0[tOff], bLen * System.SizeOf(Int64));
-
-  for I := 2 to System.Pred(16) do
-  begin
-    tOff := tOff + bMax;
-    ti[I] := tOff;
-    if ((I and 1) = 0) then
-    begin
-      ShiftUp(T0, Int32(UInt32(tOff) shr 1), T0, tOff, bMax, 1);
-    end
-    else
-    begin
-      Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
-    end;
-  end;
-
-  // /*
-  // * Second table with all 4-bit products of B shifted 4 bits
-  // */
-
-  System.SetLength(T1, System.Length(T0));
-
-  ShiftUp(T0, 0, T1, 0, System.Length(T0), 4);
-  // ShiftUp(T0, bMax, T1, bMax, tOff, 4);
-
-  aMInts := a.Fm_ints;
-  System.SetLength(c, cLen shl 3);
-
-  MASK := $F;
-
-  // /*
-  // * Lopez-Dahab (Modified) algorithm
-  // */
-
-  for aPos := 0 to System.Pred(aLen) do
-  begin
-    aVal := aMInts[aPos];
-    cOff := aPos;
-    while true do
-
-    begin
-      u := Int32(aVal) and MASK;
-      aVal := Int64(UInt64(aVal) shr 4);
-      v := Int32(aVal) and MASK;
-      AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
-      aVal := Int64(UInt64(aVal) shr 4);
-      if (aVal = Int64(0)) then
-      begin
-        break;
-      end;
-      cOff := cOff + cLen;
-    end;
-  end;
-
-  cOff := System.Length(c);
-  cOff := cOff - cLen;
-  while (cOff <> 0) do
-  begin
-    AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
-    cOff := cOff - cLen;
-  end;
-
-  // /*
-  // * Finally the raw answer is collected, reduce it against the reduction coefficients
-  // */
-  Result := ReduceResult(c, 0, cLen, m, ks);
-end;
-
-function TLongArray.ModMultiplyAlt(const other: TLongArray; m: Int32;
-  const ks: TCryptoLibInt32Array): TLongArray;
-var
-  aDeg, bDeg, tmp, aLen, bLen, cLen, width, positions, top, banks, shifts, bMax,
-    bTotal, stride, cTotal, I, bOff, bank, MASK, k, aPos, index, ciPos: Int32;
-  a0, aVal: Int64;
-  a, b: TLongArray;
-  c0, c: TCryptoLibInt64Array;
-  ci: TCryptoLibInt32Array;
-begin
-  // /*
-  // * Find out the degree of each argument and handle the zero cases
-  // */
-  aDeg := Degree();
-  if (aDeg = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-  bDeg := other.Degree();
-  if (bDeg = 0) then
-  begin
-    Result := other;
-    Exit;
-  end;
-
-  // /*
-  // * Swap if necessary so that A is the smaller argument
-  // */
-  a := Self;
-  b := other;
-  if (aDeg > bDeg) then
-  begin
-    a := other;
-    b := Self;
-    tmp := aDeg;
-    aDeg := bDeg;
-    bDeg := tmp;
-  end;
-
-  // /*
-  // * Establish the word lengths of the arguments and result
-  // */
-  aLen := Int32(UInt32(aDeg + 63) shr 6);
-  bLen := Int32(UInt32(bDeg + 63) shr 6);
-  cLen := Int32(UInt32(aDeg + bDeg + 62) shr 6);
-
-  if (aLen = 1) then
-  begin
-    a0 := a.Fm_ints[0];
-    if (a0 = Int64(1)) then
-    begin
-      Result := b;
-      Exit;
-    end;
-
-    // /*
-    // * Fast path for small A, with performance dependent only on the number of set bits
-    // */
-    System.SetLength(c0, cLen);
-    MultiplyWord(a0, b.Fm_ints, bLen, c0, 0);
-
-    // /*
-    // * Reduce the raw answer against the reduction coefficients
-    // */
-    Result := ReduceResult(c0, 0, cLen, m, ks);
-    Exit;
-  end;
-
-  // /*
-  // * Determine the parameters of the Interleaved window algorithm: the 'width' in bits to
-  // * process together, the number of evaluation 'positions' implied by that width, and the
-  // * 'top' position at which the regular window algorithm stops.
-  // */
-
-  // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto
-  // width = 1; positions = 64; top = 64; banks = 4;
-  // width = 2; positions = 32; top = 64; banks = 4;
-  // width = 3; positions = 21; top = 63; banks = 3;
-  width := 4;
-  positions := 16;
-  top := 64;
-  banks := 8;
-  // width = 5; positions = 13; top = 65; banks = 7;
-  // width = 7; positions = 9; top = 63; banks = 9;
-  // width = 8; positions = 8; top = 64; banks = 8;
-
-  // /*
-  // * Determine if B will get bigger during shifting
-  // */
-  if top < 64 then
-  begin
-    shifts := positions;
-  end
-  else
-  begin
-    shifts := positions - 1;
-  end;
-
-  bMax := Int32(UInt32(bDeg + shifts + 63) shr 6);
-
-  bTotal := bMax * banks;
-  stride := width * banks;
-
-  // /*
-  // * Create a single temporary buffer, with an offset table to find the positions of things in it
-  // */
-  System.SetLength(ci, 1 shl width);
-  cTotal := aLen;
-
-  ci[0] := cTotal;
-  cTotal := cTotal + bTotal;
-  ci[1] := cTotal;
-
-  for I := 2 to System.Pred(System.Length(ci)) do
-  begin
-    cTotal := cTotal + cLen;
-    ci[I] := ci[I] + cTotal;
-  end;
-  cTotal := cTotal + cLen;
-
-  // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen'
-  System.Inc(cTotal);
-
-  System.SetLength(c, cTotal);
-
-  // Prepare A in Interleaved form, according to the chosen width
-  Interleave(a.Fm_ints, 0, c, 0, aLen, width);
-
-  // Make a working copy of B, since we will be shifting it
-
-  bOff := aLen;
-
-  System.Move(b.Fm_ints[0], c[bOff], bLen * System.SizeOf(Int64));
-  for bank := 1 to System.Pred(banks) do
-
-  begin
-    bOff := bOff + bMax;
-    ShiftUp(c, aLen, c, bOff, bMax, bank);
-  end;
-
-  // /*
-  // * The main loop analyzes the Interleaved windows in A, and for each non-zero window
-  // * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is
-  // * breadth-first, checking the lowest window in each word, then looping again for the
-  // * next higher window position.
-  // */
-  MASK := (1 shl width) - 1;
-
-  k := 0;
-  while true do
-  begin
-    aPos := 0;
-    repeat
-
-      aVal := Int64(UInt64(c[aPos]) shr k);
-      bank := 0;
-      bOff := aLen;
-      while true do
-
-      begin
-        index := Int32(aVal) and MASK;
-        if (index <> 0) then
-        begin
-          // /*
-          // * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in
-          // * Interleaved form, the bits represent the current B shifted by 0, 'positions',
-          // * 'positions' * 2, ..., 'positions' * ('width' - 1)
-          // */
-          Add(c, aPos + ci[index], c, bOff, bMax);
-        end;
-        System.Inc(bank);
-        if (bank = banks) then
-        begin
-          break;
-        end;
-        bOff := bOff + bMax;
-        aVal := Int64(UInt64(aVal) shr width);
-      end;
-
-      System.Inc(aPos);
-    until (not(aPos < aLen));
-
-    k := k + stride;
-    if (k >= top) then
-    begin
-      if (k >= 64) then
-      begin
-        break;
-      end;
-
-      // /*
-      // * Adjustment for window setups with top == 63, the final bit (if any) is processed
-      // * as the top-bit of a window
-      // */
-      k := 64 - width;
-      MASK := MASK and (MASK shl (top - k));
-    end;
-
-    // /*
-    // * After each position has been checked for all words of A, B is shifted up 1 place
-    // */
-    ShiftUp(c, aLen, bTotal, banks);
-  end;
-
-  ciPos := System.Length(ci);
-  System.Dec(ciPos);
-  while (ciPos > 1) do
-  begin
-    if ((ciPos and Int64(1)) = Int64(0)) then
-    begin
-      // /*
-      // * For even numbers, shift contents and add to the half-position
-      // */
-      AddShiftedUp(c, ci[UInt32(ciPos) shr 1], c, ci[ciPos], cLen, positions);
-    end
-    else
-    begin
-      // /*
-      // * For odd numbers, 'distribute' contents to the result and the next-lowest position
-      // */
-      Distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen);
-    end;
-    System.Dec(ciPos);
-  end;
-
-  // /*
-  // * Finally the raw answer is collected, reduce it against the reduction coefficients
-  // */
-  Result := ReduceResult(c, ci[1], cLen, m, ks);
-end;
-
-function TLongArray.ModMultiplyLD(const other: TLongArray; m: Int32;
-  const ks: TCryptoLibInt32Array): TLongArray;
-var
-  aDeg, bDeg, tmp, aLen, bLen, cLen, bMax, tOff, I, MASK, k, aVal, u,
-    v, j: Int32;
-  a, b: TLongArray;
-  a0: Int64;
-  c0, T0, T1, aMInts, c: TCryptoLibInt64Array;
-  ti: TCryptoLibInt32Array;
-begin
-  // /*
-  // * Find out the degree of each argument and handle the zero cases
-  // */
-  aDeg := Degree();
-  if (aDeg = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-  bDeg := other.Degree();
-  if (bDeg = 0) then
-  begin
-    Result := other;
-    Exit;
-  end;
-
-  // /*
-  // * Swap if necessary so that A is the smaller argument
-  // */
-  a := Self;
-  b := other;
-  if (aDeg > bDeg) then
-  begin
-    a := other;
-    b := Self;
-    tmp := aDeg;
-    aDeg := bDeg;
-    bDeg := tmp;
-  end;
-
-  // /*
-  // * Establish the word lengths of the arguments and result
-  // */
-  aLen := Int32(UInt32(aDeg + 63) shr 6);
-  bLen := Int32(UInt32(bDeg + 63) shr 6);
-  cLen := Int32(UInt32(aDeg + bDeg + 62) shr 6);
-
-  if (aLen = 1) then
-  begin
-    a0 := a.Fm_ints[0];
-    if (a0 = Int64(1)) then
-    begin
-      Result := b;
-      Exit;
-    end;
-
-    // /*
-    // * Fast path for small A, with performance dependent only on the number of set bits
-    // */
-    System.SetLength(c0, cLen);
-
-    MultiplyWord(a0, b.Fm_ints, bLen, c0, 0);
-
-    // /*
-    // * Reduce the raw answer against the reduction coefficients
-    // */
-    Result := ReduceResult(c0, 0, cLen, m, ks);
-    Exit;
-  end;
-
-  // /*
-  // * Determine if B will get bigger during shifting
-  // */
-  bMax := Int32(UInt32(bDeg + 7 + 63) shr 6);
-
-  // /*
-  // * Lookup table for the offset of each B in the tables
-  // */
-  System.SetLength(ti, 16);
-
-  // /*
-  // * Precompute table of all 4-bit products of B
-  // */
-  System.SetLength(T0, bMax shl 4);
-  tOff := bMax;
-  ti[1] := tOff;
-  System.Move(b.Fm_ints[0], T0[tOff], bLen * System.SizeOf(Int64));
-
-  for I := 2 to System.Pred(16) do
-
-  begin
-    tOff := tOff + bMax;
-    ti[I] := tOff;
-    if ((I and 1) = 0) then
-    begin
-      ShiftUp(T0, Int32(UInt32(tOff) shr 1), T0, tOff, bMax, 1);
-    end
-    else
-    begin
-      Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
-    end;
-  end;
-
-  // /*
-  // * Second table with all 4-bit products of B shifted 4 bits
-  // */
-  System.SetLength(T1, System.Length(T0));
-  ShiftUp(T0, 0, T1, 0, System.Length(T0), 4);
-  // shiftUp(T0, bMax, T1, bMax, tOff, 4);
-
-  aMInts := a.Fm_ints;
-  System.SetLength(c, cLen);
-
-  MASK := $F;
-
-  // /*
-  // * Lopez-Dahab algorithm
-  // */
-
-  k := 56;
-  while k >= 0 do
-  begin
-    j := 1;
-    while j < aLen do
-    begin
-      aVal := Int32(UInt64(aMInts[j]) shr k);
-      u := aVal and MASK;
-      v := Int32(UInt32(aVal) shr 4) and MASK;
-      AddBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax);
-      System.Inc(j, 2);
-    end;
-    ShiftUp(c, 0, cLen, 8);
-    System.Dec(k, 8);
-  end;
-
-  k := 56;
-  while k >= 0 do
-  begin
-    j := 0;
-    while j < aLen do
-    begin
-      aVal := Int32(UInt64(aMInts[j]) shr k);
-      u := aVal and MASK;
-      v := Int32(UInt32(aVal) shr 4) and MASK;
-      AddBoth(c, j, T0, ti[u], T1, ti[v], bMax);
-      System.Inc(j, 2);
-    end;
-    if (k > 0) then
-    begin
-      ShiftUp(c, 0, cLen, 8);
-    end;
-    System.Dec(k, 8);
-  end;
-
-  // /*
-  // * Finally the raw answer is collected, reduce it against the reduction coefficients
-  // */
-  Result := ReduceResult(c, 0, cLen, m, ks);
-
-end;
-
-function TLongArray.ModReduce(m: Int32; const ks: TCryptoLibInt32Array)
-  : TLongArray;
-var
-  buf: TCryptoLibInt64Array;
-  rLen: Int32;
-begin
-  buf := System.Copy(Fm_ints);
-  rLen := ReduceInPlace(buf, 0, System.Length(buf), m, ks);
-  Result := TLongArray.Create(buf, 0, rLen);
-end;
-
-function TLongArray.ModSquare(m: Int32; const ks: TCryptoLibInt32Array)
-  : TLongArray;
-var
-  len, _2len, pos: Int32;
-  r: TCryptoLibInt64Array;
-  mi: Int64;
-begin
-  len := GetUsedLength();
-  if (len = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-
-  _2len := len shl 1;
-  System.SetLength(r, _2len);
-
-  pos := 0;
-  while (pos < _2len) do
-  begin
-    mi := Fm_ints[UInt32(pos) shr 1];
-
-    r[pos] := Interleave2_32to64(Int32(mi));
-    System.Inc(pos);
-    r[pos] := Interleave2_32to64(Int32(UInt64(mi) shr 32));
-    System.Inc(pos);
-  end;
-
-  Result := TLongArray.Create(r, 0, ReduceInPlace(r, 0,
-    System.Length(r), m, ks));
-end;
-
-function TLongArray.ModSquareN(n, m: Int32; const ks: TCryptoLibInt32Array)
-  : TLongArray;
-var
-  len, mLen: Int32;
-  r: TCryptoLibInt64Array;
-begin
-  len := GetUsedLength();
-  if (len = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-
-  mLen := TBitUtilities.Asr32((m + 63), 6);
-
-  System.SetLength(r, mLen shl 1);
-  System.Move(Fm_ints[0], r[0], len * System.SizeOf(Int64));
-
-  System.Dec(n);
-  while (n >= 0) do
-  begin
-    SquareInPlace(r, len);
-    len := ReduceInPlace(r, 0, System.Length(r), m, ks);
-    System.Dec(n);
-  end;
-
-  Result := TLongArray.Create(r, 0, len);
-end;
-
-function TLongArray.Multiply(const other: TLongArray): TLongArray;
-var
-  aDeg, bDeg, tmp, aLen, bLen, cLen, bMax, tOff, I, MASK, aPos, cOff,
-    u, v: Int32;
-  a0, aVal: Int64;
-  a, b: TLongArray;
-  c0, T0, T1, aMInts, c: TCryptoLibInt64Array;
-  ti: TCryptoLibInt32Array;
-begin
-  // /*
-  // * Find out the degree of each argument and handle the zero cases
-  // */
-
-  aDeg := Degree();
-  if (aDeg = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-  bDeg := other.Degree();
-  if (bDeg = 0) then
-  begin
-    Result := other;
-    Exit;
-  end;
-
-  // /*
-  // * Swap if necessary so that A is the smaller argument
-  // */
-  a := Self;
-  b := other;
-  if (aDeg > bDeg) then
-  begin
-    a := other;
-    b := Self;
-    tmp := aDeg;
-    aDeg := bDeg;
-    bDeg := tmp;
-  end;
-
-  // /*
-  // * Establish the word lengths of the arguments and result
-  // */
-  aLen := Int32(UInt32(aDeg + 63) shr 6);
-  bLen := Int32(UInt32(bDeg + 63) shr 6);
-  cLen := Int32(UInt32(aDeg + bDeg + 62) shr 6);
-
-  if (aLen = 1) then
-  begin
-    a0 := a.Fm_ints[0];
-    if (a0 = Int64(1)) then
-    begin
-      Result := b;
-      Exit;
-    end;
-
-    // /*
-    // * Fast path for small A, with performance dependent only on the number of set bits
-    // */
-    System.SetLength(c0, cLen);
-    MultiplyWord(a0, b.Fm_ints, bLen, c0, 0);
-
-    // /*
-    // * Reduce the raw answer against the reduction coefficients
-    // */
-    // return ReduceResult(c0, 0, cLen, m, ks);
-    Result := TLongArray.Create(c0, 0, cLen);
-    Exit;
-  end;
-
-  // /*
-  // * Determine if B will get bigger during shifting
-  // */
-  bMax := Int32(UInt32(bDeg + 7 + 63) shr 6);
-
-  // /*
-  // * Lookup table for the offset of each B in the tables
-  // */
-  System.SetLength(ti, 16);
-
-  // /*
-  // * Precompute table of all 4-bit products of B
-  // */
-  System.SetLength(T0, bMax shl 4);
-
-  tOff := bMax;
-  ti[1] := tOff;
-  System.Move(b.Fm_ints[0], T0[tOff], bLen * System.SizeOf(Int64));
-
-  for I := 2 to System.Pred(16) do
-  begin
-    tOff := tOff + bMax;
-    ti[I] := tOff;
-    if ((I and 1) = 0) then
-    begin
-      ShiftUp(T0, Int32(UInt32(tOff) shr 1), T0, tOff, bMax, 1);
-    end
-    else
-    begin
-      Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
-    end;
-  end;
-
-  // /*
-  // * Second table with all 4-bit products of B shifted 4 bits
-  // */
-  System.SetLength(T1, System.Length(T0));
-
-  ShiftUp(T0, 0, T1, 0, System.Length(T0), 4);
-  // ShiftUp(T0, bMax, T1, bMax, tOff, 4);
-
-  aMInts := a.Fm_ints;
-  System.SetLength(c, cLen shl 3);
-
-  MASK := $F;
-
-  // /*
-  // * Lopez-Dahab (Modified) algorithm
-  // */
-
-  for aPos := 0 to System.Pred(aLen) do
-
-  begin
-    aVal := aMInts[aPos];
-    cOff := aPos;
-    while true do
-
-    begin
-      u := Int32(aVal) and MASK;
-      aVal := Int64(UInt64(aVal) shr 4);
-      v := Int32(aVal) and MASK;
-      AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
-      aVal := Int64(UInt64(aVal) shr 4);
-      if (aVal = Int64(0)) then
-      begin
-        break;
-      end;
-      cOff := cOff + cLen;
-    end;
-  end;
-
-  cOff := System.Length(c);
-  cOff := cOff - cLen;
-  while (cOff <> 0) do
-  begin
-    AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
-    cOff := cOff - cLen;
-  end;
-
-  // /*
-  // * Finally the raw answer is collected, reduce it against the reduction coefficients
-  // */
-  // return ReduceResult(c, 0, cLen, m, ks);
-  Result := TLongArray.Create(c, 0, cLen);
-end;
-
-procedure TLongArray.Reduce(m: Int32; const ks: TCryptoLibInt32Array);
-var
-  buf: TCryptoLibInt64Array;
-  rLen: Int32;
-begin
-  buf := Fm_ints;
-  rLen := ReduceInPlace(buf, 0, System.Length(buf), m, ks);
-  if (rLen < System.Length(buf)) then
-  begin
-    System.SetLength(Fm_ints, rLen);
-    System.Move(buf[0], Fm_ints[0], rLen * System.SizeOf(Int64));
-  end;
-end;
-
-class procedure TLongArray.ReduceWord(const buf: TCryptoLibInt64Array;
-  off, bit: Int32; word: Int64; m: Int32; const ks: TCryptoLibInt32Array);
-var
-  offset, j: Int32;
-begin
-  offset := bit - m;
-  j := System.Length(ks);
-  System.Dec(j);
-  while (j >= 0) do
-  begin
-    FlipWord(buf, off, offset + ks[j], word);
-    System.Dec(j);
-  end;
-  FlipWord(buf, off, offset, word);
-end;
-
-class procedure TLongArray.ReduceWordWise(const buf: TCryptoLibInt64Array;
-  off, len, toBit, m: Int32; const ks: TCryptoLibInt32Array);
-var
-  toPos, partial: Int32;
-  word: Int64;
-begin
-  toPos := Int32(UInt32(toBit) shr 6);
-  System.Dec(len);
-  while (len > toPos) do
-  begin
-    word := buf[off + len];
-    if (word <> 0) then
-    begin
-      buf[off + len] := 0;
-      ReduceWord(buf, off, (len shl 6), word, m, ks);
-    end;
-    System.Dec(len);
-  end;
-
-  partial := toBit and $3F;
-  word := Int64(UInt64(buf[off + toPos]) shr partial);
-  if (word <> 0) then
-  begin
-    buf[off + toPos] := buf[off + toPos] xor (word shl partial);
-    ReduceWord(buf, off, toBit, word, m, ks);
-  end;
-
-end;
-
-class function TLongArray.ShiftUp(const x: TCryptoLibInt64Array; xOff: Int32;
-  const z: TCryptoLibInt64Array; zOff, count, shift: Int32): Int64;
-var
-  shiftInv, I: Int32;
-  prev, next: Int64;
-begin
-  shiftInv := 64 - shift;
-  prev := 0;
-  for I := 0 to System.Pred(count) do
-
-  begin
-    next := x[xOff + I];
-    z[zOff + I] := (next shl shift) or prev;
-    prev := Int64(UInt64(next) shr shiftInv);
-  end;
-  Result := prev;
-end;
-
-class function TLongArray.ShiftUp(const x: TCryptoLibInt64Array;
-  xOff, count, shift: Int32): Int64;
-var
-  shiftInv, I: Int32;
-  prev, next: Int64;
-begin
-  shiftInv := 64 - shift;
-  prev := 0;
-  for I := 0 to System.Pred(count) do
-
-  begin
-    next := x[xOff + I];
-    x[xOff + I] := (next shl shift) or prev;
-    prev := Int64(UInt64(next) shr shiftInv);
-  end;
-  Result := prev;
-end;
-
-function TLongArray.Square(): TLongArray;
-var
-  len, _2len, pos: Int32;
-  r: TCryptoLibInt64Array;
-  mi: Int64;
-begin
-  len := GetUsedLength();
-  if (len = 0) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-
-  _2len := len shl 1;
-  System.SetLength(r, _2len);
-
-  pos := 0;
-  while (pos < _2len) do
-  begin
-    mi := Fm_ints[UInt32(pos) shr 1];
-    r[pos] := Interleave2_32to64(Int32(mi));
-    System.Inc(pos);
-    r[pos] := Interleave2_32to64(Int32(UInt64(mi) shr 32));
-    System.Inc(pos);
-  end;
-
-  Result := TLongArray.Create(r, 0, System.Length(r));
-end;
-
-function TLongArray.TestBitZero: Boolean;
-begin
-  Result := (System.Length(Fm_ints) > 0) and ((Fm_ints[0] and Int64(1)) <> 0);
-end;
-
-function TLongArray.ToBigInteger: TBigInteger;
-var
-  usedLen, barrI, j, barrLen, iarrJ: Int32;
-  highestInt, mi: Int64;
-  temp, barr: TCryptoLibByteArray;
-  trailingZeroBytesDone: Boolean;
-  thisByte: Byte;
-begin
-  usedLen := GetUsedLength();
-  if (usedLen = 0) then
-  begin
-    Result := TBigInteger.Zero;
-    Exit;
-  end;
-
-  highestInt := Fm_ints[usedLen - 1];
-  System.SetLength(temp, 8);
-  barrI := 0;
-  trailingZeroBytesDone := false;
-
-  j := 7;
-  while j >= 0 do
-  begin
-    thisByte := Byte(UInt64(highestInt) shr (8 * j));
-    if (trailingZeroBytesDone or (thisByte <> 0)) then
-    begin
-      trailingZeroBytesDone := true;
-      temp[barrI] := thisByte;
-      System.Inc(barrI);
-    end;
-    System.Dec(j);
-  end;
-
-  barrLen := (8 * (usedLen - 1)) + barrI;
-  System.SetLength(barr, barrLen);
-
-  for j := 0 to System.Pred(barrI) do
-
-  begin
-    barr[j] := temp[j];
-  end;
-  // Highest value int is done now
-
-  iarrJ := usedLen - 2;
-  while (iarrJ >= 0) do
-  begin
-    mi := Fm_ints[iarrJ];
-    j := 7;
-    while (j >= 0) do
-    begin
-      barr[barrI] := Byte(UInt64(mi) shr (8 * j));
-      System.Inc(barrI);
-      System.Dec(j);
-    end;
-    System.Dec(iarrJ);
-  end;
-  Result := TBigInteger.Create(1, barr);
-end;
-
-function TLongArray.ToString: String;
-var
-  I, len: Int32;
-  sl: TStringList;
-  S, temp: String;
-begin
-  I := GetUsedLength();
-  if (I = 0) then
-  begin
-    Result := '0';
-    Exit;
-  end;
-
-  System.Dec(I);
-  sl := TStringList.Create();
-  sl.LineBreak := '';
-  try
-    sl.Add(TLongArray.Int64ToBin(Fm_ints[I]));
-
+  I := System.Length(FData);
+  repeat
+    if I = 0 then
+      Exit(0);
     System.Dec(I);
-
-    while (I >= 0) do
-    begin
-
-      S := TLongArray.Int64ToBin(Fm_ints[I]);
-
-      // Add leading zeroes, except for highest significant word
-      len := System.Length(S);
-      if (len < 64) then
-      begin
-        temp := System.Copy(ZEROES, len, System.Length(ZEROES) - (len - 1));
-        sl.Add(temp);
-      end;
-
-      sl.Add(S);
-      System.Dec(I);
-    end;
-    Result := sl.Text;
-  finally
-    sl.Free;
-  end;
+    LW := FData[I];
+  until LW <> 0;
+  Result := (I shl 6) + BitLength(LW);
 end;
 
 end.

+ 1 - 1
CryptoLib/src/Math/EC/Multiplier/ClpMultipliers.pas

@@ -423,7 +423,7 @@ begin
     // Optimization can only be used for values in the lower half of the table
     if ((n shl 2) < (1 shl width)) then
     begin
-      highest := 32 - TBitUtilities.NumberOfLeadingZeros(n);
+      highest := 32 - TBitUtilities.NumberOfLeadingZeros32(n);
 
       // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting?
       scale := width - highest;

+ 2 - 2
CryptoLib/src/Math/EC/Rfc8032/ClpScalarUtilities.pas

@@ -219,7 +219,7 @@ begin
   LSign := UInt32(TBitUtilities.Asr32(Int32(AX[LI]), 31));
   while (LI > 0) and (AX[LI] = LSign) do
     System.Dec(LI);
-  Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros(UInt32(Int32(AX[LI]) xor Int32(LSign)));
+  Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros32(UInt32(Int32(AX[LI]) xor Int32(LSign)));
 end;
 
 class function TScalarUtilities.GetBitLengthPositive(ALast: Int32; const AX: TCryptoLibUInt32Array): Int32;
@@ -229,7 +229,7 @@ begin
   LI := ALast;
   while (LI > 0) and (AX[LI] = 0) do
     System.Dec(LI);
-  Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros(UInt32(AX[LI]));
+  Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros32(UInt32(AX[LI]));
 end;
 
 class function TScalarUtilities.LessThan(ALast: Int32; const AX: TCryptoLibUInt32Array;

+ 1 - 1
CryptoLib/src/Math/EC/Rfc8032/ClpWnaf.pas

@@ -77,7 +77,7 @@ begin
     while LJ < 16 do
     begin
       LWord16 := Int32(UInt32(LWord) shr (UInt32(LJ) and 31));
-      LSkip := TBitUtilities.NumberOfTrailingZeros(UInt32((LSign xor LWord16) or (1 shl 16)));
+      LSkip := TBitUtilities.NumberOfTrailingZeros32(UInt32((LSign xor LWord16) or (1 shl 16)));
       if LSkip > 0 then
       begin
         LJ := LJ + LSkip;

+ 5 - 5
CryptoLib/src/Math/Raw/ClpMod.pas

@@ -164,7 +164,7 @@ begin
   System.Assert(AM[LLen32 - 1] <> 0);
   {$ENDIF}
 
-  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros32(AM[LLen32 - 1]);
   LLen30 := (LBits + 29) div 30;
 
   SetLength(LT, 4);
@@ -223,7 +223,7 @@ begin
   System.Assert(AM[LLen32 - 1] <> 0);
   {$ENDIF}
 
-  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros32(AM[LLen32 - 1]);
   LLen30 := (LBits + 29) div 30;
 
   LClz := LBits - TNat.GetBitLength(LLen32, AX);
@@ -314,7 +314,7 @@ begin
   System.Assert(AM[LLen32 - 1] <> 0);
   {$ENDIF}
 
-  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros32(AM[LLen32 - 1]);
   LLen30 := (LBits + 29) div 30;
 
   SetLength(LT, 4);
@@ -356,7 +356,7 @@ begin
   System.Assert(AM[LLen32 - 1] <> 0);
   {$ENDIF}
 
-  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros(AM[LLen32 - 1]);
+  LBits := (LLen32 shl 5) - TBitUtilities.NumberOfLeadingZeros32(AM[LLen32 - 1]);
   LLen30 := (LBits + 29) div 30;
 
   LClz := LBits - TNat.GetBitLength(LLen32, AX);
@@ -584,7 +584,7 @@ begin
   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));
+    LZeros := TBitUtilities.NumberOfTrailingZeros32(UInt32(LG) or (UInt32($FFFFFFFF) shl LI));
 
     LG := TBitUtilities.Asr32(LG, LZeros);
     LU := LU shl LZeros;

+ 2 - 2
CryptoLib/src/Math/Raw/ClpNat.pas

@@ -905,7 +905,7 @@ begin
     LXI := AX[LI];
     if LXI <> 0 then
     begin
-      Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros(LXI);
+      Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros32(LXI);
       Exit;
     end;
   end;
@@ -922,7 +922,7 @@ begin
     LXI := AX[AXOff + LI];
     if LXI <> 0 then
     begin
-      Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros(LXI);
+      Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros32(LXI);
       Exit;
     end;
   end;