Browse Source

Cache-safety for EC lookup tables

- creation of cache-safe lookup tables delegated to ECCurve
- FixedPointCombMultiplier uses cache-safe lookup table
- FixedPointCombMultiplier avoids BigInteger.TestBit
Ugochukwu Mmaduekwe 7 years ago
parent
commit
294d6519ed

+ 2 - 1
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -315,7 +315,8 @@ uses
   ClpECSchnorrSigner in '..\..\CryptoLib\src\Crypto\Signers\ClpECSchnorrSigner.pas',
   ClpECSchnorrSigner in '..\..\CryptoLib\src\Crypto\Signers\ClpECSchnorrSigner.pas',
   ClpIECSchnorrSigner in '..\..\CryptoLib\src\Interfaces\ClpIECSchnorrSigner.pas',
   ClpIECSchnorrSigner in '..\..\CryptoLib\src\Interfaces\ClpIECSchnorrSigner.pas',
   ECSchnorrTests in '..\src\Others\ECSchnorrTests.pas',
   ECSchnorrTests in '..\src\Others\ECSchnorrTests.pas',
-  DigestRandomNumberTests in '..\src\Crypto\DigestRandomNumberTests.pas';
+  DigestRandomNumberTests in '..\src\Crypto\DigestRandomNumberTests.pas',
+  FixedPointTests in '..\src\Math\EC\FixedPointTests.pas';
 
 
 begin
 begin
 
 

+ 6 - 2
CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi

@@ -36,7 +36,7 @@
         <PackageName Value="FCL"/>
         <PackageName Value="FCL"/>
       </Item4>
       </Item4>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="18">
+    <Units Count="19">
       <Unit0>
       <Unit0>
         <Filename Value="CryptoLib.lpr"/>
         <Filename Value="CryptoLib.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -110,6 +110,10 @@
         <Filename Value="..\src\Crypto\DigestRandomNumberTests.pas"/>
         <Filename Value="..\src\Crypto\DigestRandomNumberTests.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit17>
       </Unit17>
+      <Unit18>
+        <Filename Value="..\src\Math\EC\FixedPointTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit18>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>
@@ -120,7 +124,7 @@
     </Target>
     </Target>
     <SearchPaths>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir)"/>
       <IncludeFiles Value="$(ProjOutDir)"/>
-      <OtherUnitFiles Value="..\src\Asn1;..\src\Math;..\src\Math\EC\Custom\Sec;..\src\Others;..\src\Security;..\src\Utils;..\src\Crypto"/>
+      <OtherUnitFiles Value="..\src\Asn1;..\src\Math;..\src\Math\EC\Custom\Sec;..\src\Others;..\src\Security;..\src\Utils;..\src\Crypto;..\src\Math\EC"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     </SearchPaths>
     <Linking>
     <Linking>

+ 1 - 0
CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr

@@ -21,6 +21,7 @@ uses
   SignerUtilitiesTests,
   SignerUtilitiesTests,
   SecureRandomTests,
   SecureRandomTests,
   DigestRandomNumberTests,
   DigestRandomNumberTests,
+  FixedPointTests,
   ClpFixedSecureRandom,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom;
   ClpIFixedSecureRandom;
 
 

+ 1 - 0
CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr

@@ -19,6 +19,7 @@ uses
   SignerUtilitiesTests,
   SignerUtilitiesTests,
   SecureRandomTests,
   SecureRandomTests,
   DigestRandomNumberTests,
   DigestRandomNumberTests,
+  FixedPointTests,
   ClpFixedSecureRandom,
   ClpFixedSecureRandom,
   ClpIFixedSecureRandom;
   ClpIFixedSecureRandom;
 
 

+ 181 - 0
CryptoLib.Tests/src/Math/EC/FixedPointTests.pas

@@ -0,0 +1,181 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                    Copyright (c) 2018 Ugochukwu Mmaduekwe                       * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *        Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring        * }
+{ *                        the development of this library                          * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit FixedPointTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$WARNINGS OFF}
+{$ENDIF FPC}
+
+uses
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  Generics.Collections,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpIECInterface,
+  ClpBigInteger,
+  ClpECNamedCurveTable,
+  ClpFixedPointCombMultiplier,
+  ClpIFixedPointCombMultiplier,
+  ClpECAlgorithms,
+  ClpX9ECParameters,
+  ClpIX9ECParameters,
+  ClpCryptoLibTypes;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  TTestFixedPoint = class(TCryptoLibTestCase)
+  private
+
+    class var
+
+      FRandom: ISecureRandom;
+
+  const
+    TestsPerCurve = Int32(5);
+
+    procedure AssertPointsEqual(const msg: String; const a, b: IECPoint);
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+    procedure TestFixedPointMultiplier;
+
+  end;
+
+implementation
+
+{ TTestFixedPoint }
+
+procedure TTestFixedPoint.AssertPointsEqual(const msg: String;
+  const a, b: IECPoint);
+begin
+  // NOTE: We intentionally test points for equality in both directions
+  CheckEquals(True, a.Equals(b), msg);
+  CheckEquals(True, b.Equals(a), msg);
+end;
+
+procedure TTestFixedPoint.TestFixedPointMultiplier;
+var
+  name, s: string;
+  i: Int32;
+  tempList: TList<String>;
+  tempDict: TDictionary<String, String>;
+  names: TCryptoLibStringArray;
+  x9, X9A: IX9ECParameters;
+  M: IFixedPointCombMultiplier;
+  k: TBigInteger;
+  pRef, pA: IECPoint;
+
+begin
+  M := TFixedPointCombMultiplier.Create();
+
+  tempList := TList<String>.Create();
+  try
+    tempList.AddRange(TECNamedCurveTable.names); // get all collections
+    // tempList.AddRange(TCustomNamedCurves.Names);
+    tempDict := TDictionary<String, String>.Create();
+    try
+      for s in tempList do
+      begin
+        if not tempDict.ContainsKey(s) then // make sure they are unique
+        begin
+          tempDict.Add(s, s);
+        end;
+      end;
+      names := tempDict.Values.ToArray; // save unique instances to array
+    finally
+      tempDict.Free;
+    end;
+  finally
+    tempList.Free;
+  end;
+
+  for name in names do
+  begin
+    X9A := TECNamedCurveTable.GetByName(name);
+    // x9B := CustomNamedCurves.GetByName(name);
+    // if (x9B <> Nil) then
+    // begin
+    // x9 := x9B
+    // end
+    // else
+    // begin
+    x9 := X9A;
+    // end;
+
+    i := 0;
+    while i < TestsPerCurve do
+    begin
+      k := TBigInteger.Create(x9.N.BitLength, FRandom);
+      pRef := TECAlgorithms.ReferenceMultiply(x9.G, k);
+
+      if (X9A <> Nil) then
+      begin
+        pA := M.Multiply(X9A.G, k);
+        AssertPointsEqual('Standard curve fixed-point failure', pRef, pA);
+      end;
+
+      // if (x9B <> Nil) then
+      // begin
+      // pB := M.Multiply(x9B.G, k);
+      // AssertPointsEqual('Custom curve fixed-point failure', pRef, pB);
+      // end;
+      System.Inc(i);
+    end;
+
+  end;
+
+end;
+
+procedure TTestFixedPoint.SetUp;
+begin
+  FRandom := TSecureRandom.Create();
+end;
+
+procedure TTestFixedPoint.TearDown;
+begin
+  inherited;
+
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestFixedPoint);
+{$ELSE}
+  RegisterTest(TTestFixedPoint.Suite);
+{$ENDIF FPC}
+
+end.

+ 0 - 1
CryptoLib.Tests/src/Math/ECAlgorithmsTests.pas

@@ -60,7 +60,6 @@ type
 
 
       FRandom: ISecureRandom;
       FRandom: ISecureRandom;
 
 
-  var
   const
   const
     Scale = Int32(4);
     Scale = Int32(4);
 
 

+ 25 - 0
CryptoLib/src/Interfaces/ClpIECInterface.pas

@@ -276,6 +276,7 @@ type
 
 
   // type
   // type
   IConfig = interface;
   IConfig = interface;
+  IECLookupTable = interface;
 
 
   IECCurve = interface(IInterface)
   IECCurve = interface(IInterface)
     ['{F340C8A1-034D-4845-BDE7-A5F55FFDE71B}']
     ['{F340C8A1-034D-4845-BDE7-A5F55FFDE71B}']
@@ -323,6 +324,10 @@ type
       : IECPoint; overload;
       : IECPoint; overload;
       deprecated 'Per-point compression property will be removed';
       deprecated 'Per-point compression property will be removed';
 
 
+    function CreateCacheSafeLookupTable
+      (points: TCryptoLibGenericArray<IECPoint>; off, len: Int32)
+      : IECLookupTable;
+
     function CreatePoint(const x, y: TBigInteger): IECPoint; overload;
     function CreatePoint(const x, y: TBigInteger): IECPoint; overload;
 
 
     function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
     function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
@@ -442,12 +447,32 @@ type
 
 
   end;
   end;
 
 
+  IECLookupTable = interface(IInterface)
+
+    ['{A1839961-4FBF-42EF-BF8B-6084064A05C1}']
+    function GetSize: Int32;
+    function Lookup(index: Int32): IECPoint;
+    property Size: Int32 read GetSize;
+  end;
+
+type
+  IDefaultLookupTable = interface(IECLookupTable)
+    ['{094881EB-24A6-41A3-BAD6-D6DAB13DD17D}']
+
+  end;
+
 type
 type
   IAbstractFpCurve = interface(IECCurve)
   IAbstractFpCurve = interface(IECCurve)
     ['{D37FE528-66B3-4449-A95C-8658A9A89B85}']
     ['{D37FE528-66B3-4449-A95C-8658A9A89B85}']
 
 
   end;
   end;
 
 
+type
+  IDefaultF2mLookupTable = interface(IECLookupTable)
+    ['{0C019049-9839-4322-BAF5-8E5D39BC426D}']
+
+  end;
+
 type
 type
   IFpCurve = interface(IAbstractFpCurve)
   IFpCurve = interface(IAbstractFpCurve)
     ['{73E49F8B-C63F-4F91-8F40-A4C3B15F47FF}']
     ['{73E49F8B-C63F-4F91-8F40-A4C3B15F47FF}']

+ 1 - 0
CryptoLib/src/Interfaces/ClpIFixedPointCombMultiplier.pas

@@ -29,6 +29,7 @@ type
     ['{A3345E31-4D5C-4442-9C3D-ACC7F6DA4A14}']
     ['{A3345E31-4D5C-4442-9C3D-ACC7F6DA4A14}']
 
 
     function GetWidthForCombSize(combSize: Int32): Int32;
     function GetWidthForCombSize(combSize: Int32): Int32;
+      deprecated 'Is no longer used; remove any overrides in subclasses.';
   end;
   end;
 
 
 implementation
 implementation

+ 7 - 1
CryptoLib/src/Interfaces/ClpIFixedPointPreCompInfo.pas

@@ -33,13 +33,19 @@ type
     function GetWidth: Int32;
     function GetWidth: Int32;
     procedure SetWidth(const Value: Int32);
     procedure SetWidth(const Value: Int32);
     function GetPreComp: TCryptoLibGenericArray<IECPoint>;
     function GetPreComp: TCryptoLibGenericArray<IECPoint>;
+      deprecated 'Will be removed';
     procedure SetPreComp(const Value: TCryptoLibGenericArray<IECPoint>);
     procedure SetPreComp(const Value: TCryptoLibGenericArray<IECPoint>);
+      deprecated 'Will be removed';
+    function GetLookupTable: IECLookupTable;
+    procedure SetLookupTable(const Value: IECLookupTable);
     function GetOffset: IECPoint;
     function GetOffset: IECPoint;
     procedure SetOffset(const Value: IECPoint);
     procedure SetOffset(const Value: IECPoint);
 
 
     property Offset: IECPoint read GetOffset write SetOffset;
     property Offset: IECPoint read GetOffset write SetOffset;
     property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp
     property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp
-      write SetPreComp;
+      write SetPreComp; {$IFDEF FPC }deprecated 'Use "LookupTable" property instead.'; {$ENDIF FPC }
+    property LookupTable: IECLookupTable read GetLookupTable
+      write SetLookupTable;
     property Width: Int32 read GetWidth write SetWidth;
     property Width: Int32 read GetWidth write SetWidth;
 
 
   end;
   end;

+ 229 - 0
CryptoLib/src/Math/EC/ClpECCurve.pas

@@ -184,6 +184,14 @@ type
     : IECPoint; overload; virtual;
     : IECPoint; overload; virtual;
     deprecated 'Per-point compression property will be removed';
     deprecated 'Per-point compression property will be removed';
 
 
+  /// <summary>
+  /// Create a cache-safe lookup table for the specified sequence of points.
+  /// All the points MUST <br />belong to this <c>ECCurve</c> instance, and
+  /// MUST already be normalized.
+  /// </summary>
+  function CreateCacheSafeLookupTable(points: TCryptoLibGenericArray<IECPoint>;
+    off, len: Int32): IECLookupTable; virtual;
+
   function CreatePoint(const x, y: TBigInteger): IECPoint; overload; virtual;
   function CreatePoint(const x, y: TBigInteger): IECPoint; overload; virtual;
 
 
   function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
   function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
@@ -301,6 +309,24 @@ type
 
 
   end;
   end;
 
 
+type
+  TDefaultLookupTable = class(TInterfacedObject, IDefaultLookupTable,
+    IECLookupTable)
+  strict private
+  var
+    Fm_outer: IECCurve;
+    Fm_table: TCryptoLibByteArray;
+    Fm_size: Int32;
+
+  public
+    constructor Create(const outer: IECCurve; table: TCryptoLibByteArray;
+      size: Int32);
+    function GetSize: Int32; virtual;
+    function Lookup(index: Int32): IECPoint; virtual;
+    property size: Int32 read GetSize;
+
+  end;
+
 type
 type
   TAbstractFpCurve = class(TECCurve, IAbstractFpCurve)
   TAbstractFpCurve = class(TECCurve, IAbstractFpCurve)
 
 
@@ -316,6 +342,24 @@ type
 
 
   end;
   end;
 
 
+type
+  TDefaultF2mLookupTable = class(TInterfacedObject, IDefaultF2mLookupTable,
+    IECLookupTable)
+  strict private
+  var
+    Fm_outer: IF2mCurve;
+    Fm_table: TCryptoLibInt64Array;
+    Fm_size: Int32;
+
+  public
+    constructor Create(const outer: IF2mCurve; table: TCryptoLibInt64Array;
+      size: Int32);
+    function GetSize: Int32; virtual;
+    function Lookup(index: Int32): IECPoint; virtual;
+    property size: Int32 read GetSize;
+
+  end;
+
 type
 type
   TFpCurve = class(TAbstractFpCurve, IFpCurve)
   TFpCurve = class(TAbstractFpCurve, IFpCurve)
 
 
@@ -593,6 +637,10 @@ type
     /// </returns>
     /// </returns>
     function IsTrinomial(): Boolean; inline;
     function IsTrinomial(): Boolean; inline;
 
 
+    function CreateCacheSafeLookupTable
+      (points: TCryptoLibGenericArray<IECPoint>; off, len: Int32)
+      : IECLookupTable; override;
+
     property FieldSize: Int32 read GetFieldSize;
     property FieldSize: Int32 read GetFieldSize;
     property Infinity: IECPoint read GetInfinity;
     property Infinity: IECPoint read GetInfinity;
     property m: Int32 read GetM;
     property m: Int32 read GetM;
@@ -657,6 +705,56 @@ begin
   Fm_field := field;
   Fm_field := field;
 end;
 end;
 
 
+function TECCurve.CreateCacheSafeLookupTable
+  (points: TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
+var
+  FE_BYTES, position, i, pxStart, pyStart, pxLen, pyLen: Int32;
+  table, px, py: TCryptoLibByteArray;
+  p: IECPoint;
+begin
+  FE_BYTES := (FieldSize + 7) div 8;
+  System.SetLength(table, len * FE_BYTES * 2);
+  position := 0;
+
+  for i := 0 to System.Pred(len) do
+  begin
+    p := points[off + i];
+    px := p.RawXCoord.ToBigInteger().ToByteArray();
+    py := p.RawYCoord.ToBigInteger().ToByteArray();
+
+    if System.Length(px) > FE_BYTES then
+    begin
+      pxStart := 1
+    end
+    else
+    begin
+      pxStart := 0
+    end;
+
+    pxLen := System.Length(px) - pxStart;
+
+    if System.Length(py) > FE_BYTES then
+    begin
+      pyStart := 1
+    end
+    else
+    begin
+      pyStart := 0
+    end;
+
+    pyLen := System.Length(py) - pyStart;
+
+    System.Move(px[pxStart], table[position + FE_BYTES - pxLen],
+      pxLen * System.SizeOf(Byte));
+    position := position + FE_BYTES;
+
+    System.Move(py[pyStart], table[position + FE_BYTES - pyLen],
+      pyLen * System.SizeOf(Byte));
+    position := position + FE_BYTES;
+  end;
+  Result := TDefaultLookupTable.Create(Self as IECCurve, table, len);
+end;
+
 function TECCurve.CreateDefaultMultiplier: IECMultiplier;
 function TECCurve.CreateDefaultMultiplier: IECMultiplier;
 var
 var
   glvEndomorphism: IGlvEndomorphism;
   glvEndomorphism: IGlvEndomorphism;
@@ -1541,6 +1639,30 @@ begin
 
 
 end;
 end;
 
 
+function TF2mCurve.CreateCacheSafeLookupTable
+  (points: TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
+var
+  FE_LONGS, position, i: Int32;
+  table: TCryptoLibInt64Array;
+  p: IECPoint;
+begin
+  FE_LONGS := (m + 63) div 64;
+  System.SetLength(table, len * FE_LONGS * 2);
+
+  position := 0;
+
+  for i := 0 to System.Pred(len) do
+  begin
+    p := points[off + i];
+    (p.RawXCoord as IF2mFieldElement).x.CopyTo(table, position);
+    position := position + FE_LONGS;
+    (p.RawYCoord as IF2mFieldElement).x.CopyTo(table, position);
+    position := position + FE_LONGS;
+  end;
+
+  Result := TDefaultF2mLookupTable.Create(Self as IF2mCurve, table, len);
+end;
+
 constructor TF2mCurve.Create(m, k1, k2, k3: Int32; const A, B: TBigInteger);
 constructor TF2mCurve.Create(m, k1, k2, k3: Int32; const A, B: TBigInteger);
 begin
 begin
   Create(m, k1, k2, k3, A, B, Default (TBigInteger), Default (TBigInteger));
   Create(m, k1, k2, k3, A, B, Default (TBigInteger), Default (TBigInteger));
@@ -1629,4 +1751,111 @@ begin
   end;
   end;
 end;
 end;
 
 
+{ TDefaultLookupTable }
+
+constructor TDefaultLookupTable.Create(const outer: IECCurve;
+  table: TCryptoLibByteArray; size: Int32);
+begin
+  Inherited Create();
+  Fm_outer := outer;
+  Fm_table := table;
+  Fm_size := size;
+end;
+
+function TDefaultLookupTable.GetSize: Int32;
+begin
+  Result := Fm_size;
+end;
+
+function TDefaultLookupTable.Lookup(index: Int32): IECPoint;
+var
+  FE_BYTES, position, i, j: Int32;
+  x, y: TCryptoLibByteArray;
+  MASK: Byte;
+  XFieldElement, YFieldElement: IECFieldElement;
+begin
+  FE_BYTES := (Fm_outer.FieldSize + 7) div 8;
+  System.SetLength(x, FE_BYTES);
+  System.SetLength(y, FE_BYTES);
+
+  position := 0;
+
+  for i := 0 to System.Pred(Fm_size) do
+  begin
+
+    MASK := Byte(TBits.Asr32((i xor index) - 1, 31));
+
+    for j := 0 to System.Pred(FE_BYTES) do
+    begin
+
+      x[j] := x[j] xor Byte(Fm_table[position + j] and MASK);
+      y[j] := y[j] xor Byte(Fm_table[position + FE_BYTES + j] and MASK);
+    end;
+    position := position + (FE_BYTES * 2);
+  end;
+
+  XFieldElement := Fm_outer.FromBigInteger(TBigInteger.Create(1, x));
+  YFieldElement := Fm_outer.FromBigInteger(TBigInteger.Create(1, y));
+  Result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement, false);
+end;
+
+{ TDefaultF2mLookupTable }
+
+constructor TDefaultF2mLookupTable.Create(const outer: IF2mCurve;
+  table: TCryptoLibInt64Array; size: Int32);
+begin
+  Inherited Create();
+  Fm_outer := outer;
+  Fm_table := table;
+  Fm_size := size;
+end;
+
+function TDefaultF2mLookupTable.GetSize: Int32;
+begin
+  Result := Fm_size;
+end;
+
+function TDefaultF2mLookupTable.Lookup(index: Int32): IECPoint;
+var
+  FE_LONGS, position, m, i, j: Int32;
+  ks: TCryptoLibInt32Array;
+  x, y: TCryptoLibInt64Array;
+  MASK: Int64;
+  XFieldElement, YFieldElement: IECFieldElement;
+begin
+  m := Fm_outer.m;
+  if Fm_outer.IsTrinomial() then
+  begin
+    ks := TCryptoLibInt32Array.Create(Fm_outer.k1);
+  end
+  else
+  begin
+    ks := TCryptoLibInt32Array.Create(Fm_outer.k1, Fm_outer.k2, Fm_outer.k3);
+  end;
+
+  FE_LONGS := (Fm_outer.m + 63) div 64;
+  System.SetLength(x, FE_LONGS);
+  System.SetLength(y, FE_LONGS);
+
+  position := 0;
+
+  for i := 0 to System.Pred(Fm_size) do
+  begin
+
+    MASK := TBits.Asr32((i xor index) - 1, 31);
+
+    for j := 0 to System.Pred(FE_LONGS) do
+    begin
+
+      x[j] := x[j] xor (Fm_table[position + j] and MASK);
+      y[j] := y[j] xor (Fm_table[position + FE_LONGS + j] and MASK);
+    end;
+    position := position + (FE_LONGS * 2);
+  end;
+
+  XFieldElement := TF2mFieldElement.Create(m, ks, TLongArray.Create(x));
+  YFieldElement := TF2mFieldElement.Create(m, ks, TLongArray.Create(y));
+  Result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement, false);
+end;
+
 end.
 end.

+ 3 - 3
CryptoLib/src/Math/EC/ClpECFieldElement.pas

@@ -222,9 +222,6 @@ type
     function GetK2: Int32; inline;
     function GetK2: Int32; inline;
     function GetK3: Int32; inline;
     function GetK3: Int32; inline;
 
 
-    constructor Create(m: Int32; ks: TCryptoLibInt32Array;
-      const x: TLongArray); overload;
-
   public
   public
 
 
     const
     const
@@ -274,6 +271,9 @@ type
     // */
     // */
     constructor Create(m, K: Int32; const x: TBigInteger); overload;
     constructor Create(m, K: Int32; const x: TBigInteger); overload;
 
 
+    constructor Create(m: Int32; ks: TCryptoLibInt32Array;
+      const x: TLongArray); overload;
+
     destructor Destroy; override;
     destructor Destroy; override;
 
 
     function GetBitLength: Int32; override;
     function GetBitLength: Int32; override;

+ 8 - 0
CryptoLib/src/Math/EC/ClpLongArray.pas

@@ -570,6 +570,8 @@ type
     constructor Create(ints: TCryptoLibInt64Array; off, len: Int32); overload;
     constructor Create(ints: TCryptoLibInt64Array; off, len: Int32); overload;
     constructor Create(const bigInt: TBigInteger); overload;
     constructor Create(const bigInt: TBigInteger); overload;
 
 
+    procedure CopyTo(z: TCryptoLibInt64Array; zOff: Int32);
+
     function IsOne(): Boolean; inline;
     function IsOne(): Boolean; inline;
     function IsZero(): Boolean; inline;
     function IsZero(): Boolean; inline;
     function GetUsedLength(): Int32; inline;
     function GetUsedLength(): Int32; inline;
@@ -1460,6 +1462,12 @@ begin
 
 
 end;
 end;
 
 
+procedure TLongArray.CopyTo(z: TCryptoLibInt64Array; zOff: Int32);
+begin
+  System.Move(Fm_ints[0], z[zOff], System.Length(Fm_ints) *
+    System.SizeOf(Int64));
+end;
+
 function TLongArray.IsOne: Boolean;
 function TLongArray.IsOne: Boolean;
 var
 var
   a: TCryptoLibInt64Array;
   a: TCryptoLibInt64Array;

+ 18 - 16
CryptoLib/src/Math/EC/Multiplier/ClpFixedPointCombMultiplier.pas

@@ -23,6 +23,7 @@ interface
 
 
 uses
 uses
   ClpBigInteger,
   ClpBigInteger,
+  ClpNat,
   ClpCryptoLibTypes,
   ClpCryptoLibTypes,
   ClpIECInterface,
   ClpIECInterface,
   ClpFixedPointUtilities,
   ClpFixedPointUtilities,
@@ -42,6 +43,7 @@ type
     function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
     function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
       : IECPoint; override;
       : IECPoint; override;
     function GetWidthForCombSize(combSize: Int32): Int32; virtual;
     function GetWidthForCombSize(combSize: Int32): Int32; virtual;
+      deprecated 'Is no longer used; remove any overrides in subclasses.';
 
 
   public
   public
     constructor Create();
     constructor Create();
@@ -79,10 +81,11 @@ function TFixedPointCombMultiplier.MultiplyPositive(const p: IECPoint;
   const k: TBigInteger): IECPoint;
   const k: TBigInteger): IECPoint;
 var
 var
   c: IECCurve;
   c: IECCurve;
-  R: IECPoint;
-  size, minWidth, width, d, top, i, j, index: Int32;
+  R, add: IECPoint;
+  size, width, d, top, i, j, secretIndex, fullComb: Int32;
   info: IFixedPointPreCompInfo;
   info: IFixedPointPreCompInfo;
-  lookupTable: TCryptoLibGenericArray<IECPoint>;
+  lookupTable: IECLookupTable;
+  LK: TCryptoLibUInt32Array;
 begin
 begin
   c := p.Curve;
   c := p.Curve;
   size := TFixedPointUtilities.GetCombSize(c);
   size := TFixedPointUtilities.GetCombSize(c);
@@ -97,42 +100,41 @@ begin
     raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidComputation);
     raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidComputation);
   end;
   end;
 
 
-  minWidth := GetWidthForCombSize(size);
-
-  info := TFixedPointUtilities.Precompute(p, minWidth);
-  lookupTable := info.PreComp;
+  info := TFixedPointUtilities.Precompute(p);
+  lookupTable := info.lookupTable;
   width := info.width;
   width := info.width;
 
 
   d := (size + width - 1) div width;
   d := (size + width - 1) div width;
 
 
   R := c.Infinity;
   R := c.Infinity;
+  fullComb := d * width;
+  LK := TNat.FromBigInteger(fullComb, k);
 
 
-  top := d * width - 1;
+  top := fullComb - 1;
 
 
   for i := 0 to System.Pred(d) do
   for i := 0 to System.Pred(d) do
   begin
   begin
 
 
-    index := 0;
+    secretIndex := 0;
 
 
     j := (top - i);
     j := (top - i);
 
 
     while j >= 0 do
     while j >= 0 do
     begin
     begin
 
 
-      index := index shl 1;
-      if (k.TestBit(j)) then
-      begin
-        index := index or 1;
-      end;
+      secretIndex := secretIndex shl 1;
+
+      secretIndex := secretIndex or Int32(TNat.GetBit(LK, j));
 
 
       System.Dec(j, d);
       System.Dec(j, d);
     end;
     end;
 
 
-    R := R.TwicePlus(lookupTable[index]);
+    add := lookupTable.Lookup(secretIndex);
+    R := R.TwicePlus(add);
 
 
   end;
   end;
 
 
-  Result := R.Add(info.Offset);
+  Result := R.add(info.Offset);
   info.PreComp := Nil;
   info.PreComp := Nil;
 
 
 end;
 end;

+ 26 - 1
CryptoLib/src/Math/EC/Multiplier/ClpFixedPointPreCompInfo.pas

@@ -39,7 +39,13 @@ type
     function GetWidth: Int32;
     function GetWidth: Int32;
     procedure SetWidth(const Value: Int32);
     procedure SetWidth(const Value: Int32);
     function GetPreComp: TCryptoLibGenericArray<IECPoint>;
     function GetPreComp: TCryptoLibGenericArray<IECPoint>;
+      deprecated 'Will be removed';
     procedure SetPreComp(const Value: TCryptoLibGenericArray<IECPoint>);
     procedure SetPreComp(const Value: TCryptoLibGenericArray<IECPoint>);
+      deprecated 'Will be removed';
+
+    function GetLookupTable: IECLookupTable;
+    procedure SetLookupTable(const Value: IECLookupTable);
+
     function GetOffset: IECPoint;
     function GetOffset: IECPoint;
     procedure SetOffset(const Value: IECPoint);
     procedure SetOffset(const Value: IECPoint);
 
 
@@ -53,6 +59,12 @@ type
     /// </summary>
     /// </summary>
     Fm_preComp: TCryptoLibGenericArray<IECPoint>;
     Fm_preComp: TCryptoLibGenericArray<IECPoint>;
 
 
+    /// <summary>
+    /// Array holding the precomputed <c>ECPoint</c>s used for a fixed point
+    /// multiplication.
+    /// </summary>
+    Fm_lookupTable: IECLookupTable;
+
     /// <summary>
     /// <summary>
     /// The width used for the precomputation. If a larger width
     /// The width used for the precomputation. If a larger width
     /// precomputation is already available this may be larger than was
     /// precomputation is already available this may be larger than was
@@ -64,7 +76,9 @@ type
     constructor Create();
     constructor Create();
     property Offset: IECPoint read GetOffset write SetOffset;
     property Offset: IECPoint read GetOffset write SetOffset;
     property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp
     property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp
-      write SetPreComp;
+      write SetPreComp; {$IFDEF FPC }deprecated 'Use "LookupTable" property instead.'; {$ENDIF FPC }
+    property LookupTable: IECLookupTable read GetLookupTable
+      write SetLookupTable;
     property Width: Int32 read GetWidth write SetWidth;
     property Width: Int32 read GetWidth write SetWidth;
 
 
   end;
   end;
@@ -76,6 +90,12 @@ implementation
 constructor TFixedPointPreCompInfo.Create;
 constructor TFixedPointPreCompInfo.Create;
 begin
 begin
   inherited Create();
   inherited Create();
+  Fm_width := -1;
+end;
+
+function TFixedPointPreCompInfo.GetLookupTable: IECLookupTable;
+begin
+  Result := Fm_lookupTable;
 end;
 end;
 
 
 function TFixedPointPreCompInfo.GetOffset: IECPoint;
 function TFixedPointPreCompInfo.GetOffset: IECPoint;
@@ -93,6 +113,11 @@ begin
   Result := Fm_width;
   Result := Fm_width;
 end;
 end;
 
 
+procedure TFixedPointPreCompInfo.SetLookupTable(const Value: IECLookupTable);
+begin
+  Fm_lookupTable := Value;
+end;
+
 procedure TFixedPointPreCompInfo.SetOffset(const Value: IECPoint);
 procedure TFixedPointPreCompInfo.SetOffset(const Value: IECPoint);
 begin
 begin
   Fm_offset := Value;
   Fm_offset := Value;

+ 25 - 4
CryptoLib/src/Math/EC/Multiplier/ClpFixedPointUtilities.pas

@@ -40,8 +40,12 @@ type
     class function GetCombSize(const c: IECCurve): Int32; static; inline;
     class function GetCombSize(const c: IECCurve): Int32; static; inline;
     class function GetFixedPointPreCompInfo(const preCompInfo: IPreCompInfo)
     class function GetFixedPointPreCompInfo(const preCompInfo: IPreCompInfo)
       : IFixedPointPreCompInfo; static; inline;
       : IFixedPointPreCompInfo; static; inline;
+    class function Precompute(const p: IECPoint): IFixedPointPreCompInfo;
+      overload; static;
     class function Precompute(const p: IECPoint; minWidth: Int32)
     class function Precompute(const p: IECPoint; minWidth: Int32)
-      : IFixedPointPreCompInfo; static;
+      : IFixedPointPreCompInfo; overload; static;
+      deprecated
+      'Use "Precompute(ECPoint)" instead, as minWidth parameter is now ignored';
   end;
   end;
 
 
 implementation
 implementation
@@ -74,17 +78,26 @@ begin
   Result := TFixedPointPreCompInfo.Create();
   Result := TFixedPointPreCompInfo.Create();
 end;
 end;
 
 
-class function TFixedPointUtilities.Precompute(const p: IECPoint;
-  minWidth: Int32): IFixedPointPreCompInfo;
+class function TFixedPointUtilities.Precompute(const p: IECPoint)
+  : IFixedPointPreCompInfo;
 var
 var
   c: IECCurve;
   c: IECCurve;
-  n, bit, bits, d, i, step: Int32;
+  n, bit, bits, d, i, step, minWidth: Int32;
   info: IFixedPointPreCompInfo;
   info: IFixedPointPreCompInfo;
   pow2: IECPoint;
   pow2: IECPoint;
   lookupTable, pow2Table: TCryptoLibGenericArray<IECPoint>;
   lookupTable, pow2Table: TCryptoLibGenericArray<IECPoint>;
 begin
 begin
   c := p.Curve;
   c := p.Curve;
 
 
+  if GetCombSize(c) > 257 then
+  begin
+    minWidth := 6
+  end
+  else
+  begin
+    minWidth := 5
+  end;
+
   n := 1 shl minWidth;
   n := 1 shl minWidth;
   info := GetFixedPointPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
   info := GetFixedPointPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
 
 
@@ -133,6 +146,8 @@ begin
 
 
     c.NormalizeAll(lookupTable);
     c.NormalizeAll(lookupTable);
 
 
+    info.lookupTable := c.CreateCacheSafeLookupTable(lookupTable, 0,
+      System.Length(lookupTable));
     info.Offset := pow2Table[minWidth];
     info.Offset := pow2Table[minWidth];
     info.PreComp := lookupTable;
     info.PreComp := lookupTable;
     info.Width := minWidth;
     info.Width := minWidth;
@@ -142,4 +157,10 @@ begin
   Result := info;
   Result := info;
 end;
 end;
 
 
+class function TFixedPointUtilities.Precompute(const p: IECPoint;
+  minWidth: Int32): IFixedPointPreCompInfo;
+begin
+  Result := Precompute(p);
+end;
+
 end.
 end.

+ 10 - 1
CryptoLib/src/Math/Raw/ClpNat.pas

@@ -94,6 +94,9 @@ type
     class function Copy(len: Int32; x: TCryptoLibUInt32Array)
     class function Copy(len: Int32; x: TCryptoLibUInt32Array)
       : TCryptoLibUInt32Array; overload; static; inline;
       : TCryptoLibUInt32Array; overload; static; inline;
 
 
+    class procedure Copy(len: Int32; x: TCryptoLibUInt32Array; xOff: Int32;
+      z: TCryptoLibUInt32Array; zOff: Int32); overload; static;
+
     class function Create(len: Int32): TCryptoLibUInt32Array; static; inline;
     class function Create(len: Int32): TCryptoLibUInt32Array; static; inline;
 
 
     class function Create64(len: Int32): TCryptoLibUInt64Array; static; inline;
     class function Create64(len: Int32): TCryptoLibUInt64Array; static; inline;
@@ -114,7 +117,7 @@ type
       static; inline;
       static; inline;
 
 
     class function FromBigInteger(bits: Int32; x: TBigInteger)
     class function FromBigInteger(bits: Int32; x: TBigInteger)
-      : TCryptoLibUInt32Array; static; inline;
+      : TCryptoLibUInt32Array; static;
 
 
     class function GetBit(x: TCryptoLibUInt32Array; bit: Int32): UInt32;
     class function GetBit(x: TCryptoLibUInt32Array; bit: Int32): UInt32;
       static; inline;
       static; inline;
@@ -863,6 +866,12 @@ begin
   System.Move(x[0], z[0], len * System.SizeOf(UInt32));
   System.Move(x[0], z[0], len * System.SizeOf(UInt32));
 end;
 end;
 
 
+class procedure TNat.Copy(len: Int32; x: TCryptoLibUInt32Array; xOff: Int32;
+  z: TCryptoLibUInt32Array; zOff: Int32);
+begin
+  System.Move(x[xOff], z[zOff], len * System.SizeOf(UInt32));
+end;
+
 class function TNat.Create(len: Int32): TCryptoLibUInt32Array;
 class function TNat.Create(len: Int32): TCryptoLibUInt32Array;
 begin
 begin
   System.SetLength(Result, len);
   System.SetLength(Result, len);