Преглед изворни кода

initial commit of EC related changes

Ugochukwu Mmaduekwe пре 6 дана
родитељ
комит
acd360675d
90 измењених фајлова са 8480 додато и 13196 уклоњено
  1. 7 3
      CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr
  2. 2 2
      CryptoLib/src/Asn1/CryptoPro/ClpECGost3410NamedCurves.pas
  3. 2 2
      CryptoLib/src/Asn1/Sec/ClpSecNamedCurves.pas
  4. 2 2
      CryptoLib/src/Asn1/TeleTrust/ClpTeleTrusTNamedCurves.pas
  5. 3 2
      CryptoLib/src/Asn1/X9/ClpX9ECAsn1Objects.pas
  6. 3 2
      CryptoLib/src/Asn1/X9/ClpX9IntegerConverter.pas
  7. 3 3
      CryptoLib/src/Crypto/Agreements/ClpECDHBasicAgreement.pas
  8. 3 3
      CryptoLib/src/Crypto/Agreements/ClpECDHCBasicAgreement.pas
  9. 2 2
      CryptoLib/src/Crypto/EC/ClpCustomNamedCurves.pas
  10. 1 1
      CryptoLib/src/Crypto/Generators/ClpECGenerators.pas
  11. 1 1
      CryptoLib/src/Crypto/Parameters/ClpECParameters.pas
  12. 2 1
      CryptoLib/src/Crypto/Signers/ClpECDsaSigner.pas
  13. 1 1
      CryptoLib/src/Crypto/Signers/ClpECNRSigner.pas
  14. 1 1
      CryptoLib/src/Factories/ClpPublicKeyFactory.pas
  15. 2 1
      CryptoLib/src/Interfaces/Asn1/X9/ClpIX9ECAsn1Objects.pas
  16. 1 1
      CryptoLib/src/Interfaces/Crypto/Parameters/ClpIECParameters.pas
  17. 2 1
      CryptoLib/src/Interfaces/Crypto/Signers/ClpIECDsaSigner.pas
  18. 4 15
      CryptoLib/src/Interfaces/Math/EC/Abc/ClpIZTauElement.pas
  19. 0 709
      CryptoLib/src/Interfaces/Math/EC/ClpIECC.pas
  20. 242 0
      CryptoLib/src/Interfaces/Math/EC/ClpIECCore.pas
  21. 102 0
      CryptoLib/src/Interfaces/Math/EC/ClpIECFieldElement.pas
  22. 3 8
      CryptoLib/src/Interfaces/Math/EC/ClpIECPointMap.pas
  23. 1 1
      CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP256K1Custom.pas
  24. 1 1
      CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP256R1Custom.pas
  25. 1 1
      CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP384R1Custom.pas
  26. 1 1
      CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP521R1Custom.pas
  27. 1 1
      CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecT283Custom.pas
  28. 5 28
      CryptoLib/src/Interfaces/Math/EC/Endo/ClpIEndoPreCompInfo.pas
  29. 0 35
      CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeAEndomorphism.pas
  30. 0 45
      CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeAParameters.pas
  31. 2 10
      CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeBEndomorphism.pas
  32. 5 16
      CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeBParameters.pas
  33. 8 17
      CryptoLib/src/Interfaces/Math/EC/Endo/ClpIScalarSplitParameters.pas
  34. 9 20
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIFixedPointPreCompInfo.pas
  35. 0 78
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIMultipliers.pas
  36. 4 10
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIPreCompCallback.pas
  37. 1 14
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIPreCompInfo.pas
  38. 8 17
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIValidityPreCompInfo.pas
  39. 18 34
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIWNafPreCompInfo.pas
  40. 6 16
      CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIWTauNafPreCompInfo.pas
  41. 4 5
      CryptoLib/src/Interfaces/Math/Field/ClpIExtensionField.pas
  42. 6 3
      CryptoLib/src/Interfaces/Math/Field/ClpIFiniteField.pas
  43. 1 10
      CryptoLib/src/Interfaces/Math/Field/ClpIGF2Polynomial.pas
  44. 1 7
      CryptoLib/src/Interfaces/Math/Field/ClpIGenericPolynomialExtensionField.pas
  45. 6 3
      CryptoLib/src/Interfaces/Math/Field/ClpIPolynomial.pas
  46. 4 5
      CryptoLib/src/Interfaces/Math/Field/ClpIPolynomialExtensionField.pas
  47. 1 6
      CryptoLib/src/Interfaces/Math/Field/ClpIPrimeField.pas
  48. 32 0
      CryptoLib/src/Math/ClpBigIntegers.pas
  49. 144 235
      CryptoLib/src/Math/EC/Abc/ClpSimpleBigDecimal.pas
  50. 618 911
      CryptoLib/src/Math/EC/Abc/ClpTnaf.pas
  51. 17 45
      CryptoLib/src/Math/EC/Abc/ClpZTauElement.pas
  52. 14 12
      CryptoLib/src/Math/EC/ClpAbstractECLookupTable.pas
  53. 586 899
      CryptoLib/src/Math/EC/ClpECAlgorithms.pas
  54. 0 6809
      CryptoLib/src/Math/EC/ClpECC.pas
  55. 0 1537
      CryptoLib/src/Math/EC/ClpECCompUtilities.pas
  56. 3 12
      CryptoLib/src/Math/EC/ClpECCore.pas
  57. 1423 0
      CryptoLib/src/Math/EC/ClpECCurve.pas
  58. 20 19
      CryptoLib/src/Math/EC/ClpECCurveConstants.pas
  59. 971 0
      CryptoLib/src/Math/EC/ClpECFieldElement.pas
  60. 2263 0
      CryptoLib/src/Math/EC/ClpECPoint.pas
  61. 5 7
      CryptoLib/src/Math/EC/ClpLongArray.pas
  62. 11 24
      CryptoLib/src/Math/EC/ClpScaleXNegateYPointMap.pas
  63. 11 29
      CryptoLib/src/Math/EC/ClpScaleXPointMap.pas
  64. 11 17
      CryptoLib/src/Math/EC/ClpScaleYNegateXPointMap.pas
  65. 23 9
      CryptoLib/src/Math/EC/ClpScaleYPointMap.pas
  66. 83 0
      CryptoLib/src/Math/EC/ClpSimpleLookupTable.pas
  67. 20 19
      CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas
  68. 20 19
      CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas
  69. 20 19
      CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas
  70. 20 19
      CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas
  71. 20 19
      CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283Custom.pas
  72. 14 50
      CryptoLib/src/Math/EC/Endo/ClpEndoPreCompInfo.pas
  73. 120 0
      CryptoLib/src/Math/EC/Endo/ClpEndoUtilities.pas
  74. 0 92
      CryptoLib/src/Math/EC/Endo/ClpGlvTypeAEndomorphism.pas
  75. 0 80
      CryptoLib/src/Math/EC/Endo/ClpGlvTypeAParameters.pas
  76. 28 45
      CryptoLib/src/Math/EC/Endo/ClpGlvTypeBEndomorphism.pas
  77. 22 36
      CryptoLib/src/Math/EC/Endo/ClpGlvTypeBParameters.pas
  78. 47 66
      CryptoLib/src/Math/EC/Endo/ClpScalarSplitParameters.pas
  79. 27 66
      CryptoLib/src/Math/EC/Multiplier/ClpFixedPointPreCompInfo.pas
  80. 159 0
      CryptoLib/src/Math/EC/Multiplier/ClpFixedPointUtilities.pas
  81. 259 487
      CryptoLib/src/Math/EC/Multiplier/ClpMultipliers.pas
  82. 24 47
      CryptoLib/src/Math/EC/Multiplier/ClpValidityPreCompInfo.pas
  83. 61 139
      CryptoLib/src/Math/EC/Multiplier/ClpWNafPreCompInfo.pas
  84. 754 0
      CryptoLib/src/Math/EC/Multiplier/ClpWNafUtilities.pas
  85. 12 52
      CryptoLib/src/Math/EC/Multiplier/ClpWTauNafPreCompInfo.pas
  86. 39 68
      CryptoLib/src/Math/Field/ClpFiniteFields.pas
  87. 23 53
      CryptoLib/src/Math/Field/ClpGF2Polynomial.pas
  88. 50 66
      CryptoLib/src/Math/Field/ClpGenericPolynomialExtensionField.pas
  89. 22 43
      CryptoLib/src/Math/Field/ClpPrimeField.pas
  90. 1 1
      CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk

+ 7 - 3
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -97,7 +97,7 @@ uses
   ClpDsaSigner in '..\..\CryptoLib\src\Crypto\Signers\ClpDsaSigner.pas',
   ClpEacObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Eac\ClpEacObjectIdentifiers.pas',
   ClpECAlgorithms in '..\..\CryptoLib\src\Math\EC\ClpECAlgorithms.pas',
-  ClpECC in '..\..\CryptoLib\src\Math\EC\ClpECC.pas',
+  ClpECCurve in '..\..\CryptoLib\src\Math\EC\ClpECCurve.pas',
   ClpECCompUtilities in '..\..\CryptoLib\src\Math\EC\ClpECCompUtilities.pas',
   ClpECCurveConstants in '..\..\CryptoLib\src\Math\EC\ClpECCurveConstants.pas',
   ClpECDHBasicAgreement in '..\..\CryptoLib\src\Crypto\Agreements\ClpECDHBasicAgreement.pas',
@@ -123,6 +123,7 @@ uses
   ClpEphemeralKeyPairGenerator in '..\..\CryptoLib\src\Crypto\Generators\ClpEphemeralKeyPairGenerator.pas',
   ClpFiniteFields in '..\..\CryptoLib\src\Math\Field\ClpFiniteFields.pas',
   ClpFixedPointPreCompInfo in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpFixedPointPreCompInfo.pas',
+  ClpFixedPointUtilities in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpFixedPointUtilities.pas',
   ClpGeneratorUtilities in '..\..\CryptoLib\src\Crypto\Generators\ClpGeneratorUtilities.pas',
   ClpGenericPolynomialExtensionField in '..\..\CryptoLib\src\Math\Field\ClpGenericPolynomialExtensionField.pas',
   ClpGenericSigner in '..\..\CryptoLib\src\Crypto\Signers\ClpGenericSigner.pas',
@@ -179,7 +180,8 @@ uses
   ClpIDsaGenerators in '..\..\CryptoLib\src\Interfaces\Crypto\Generators\ClpIDsaGenerators.pas',
   ClpIDsaParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpIDsaParameters.pas',
   ClpIDsaSigner in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\ClpIDsaSigner.pas',
-  ClpIECC in '..\..\CryptoLib\src\Interfaces\Math\EC\ClpIECC.pas',
+  ClpIECCore in '..\..\CryptoLib\src\Interfaces\Math\EC\ClpIECCore.pas',
+  ClpIECFieldElement in '..\..\CryptoLib\src\Interfaces\Math\EC\ClpIECFieldElement.pas',
   ClpIECDHBasicAgreement in '..\..\CryptoLib\src\Interfaces\Crypto\Agreements\ClpIECDHBasicAgreement.pas',
   ClpIECDHCBasicAgreement in '..\..\CryptoLib\src\Interfaces\Crypto\Agreements\ClpIECDHCBasicAgreement.pas',
   ClpIECParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpIECParameters.pas',
@@ -591,7 +593,9 @@ uses
   DeltaCertificateTests in '..\src\Asn1\X509\DeltaCertificateTests.pas',
   X509CertGenTests in '..\src\X509\X509CertGenTests.pas',
   CertTests in '..\src\Others\CertTests.pas',
-  CryptoLibTestBase in '..\src\CryptoLibTestBase.pas';
+  CryptoLibTestBase in '..\src\CryptoLibTestBase.pas',
+  ClpECPoint in '..\..\CryptoLib\src\Math\EC\ClpECPoint.pas',
+  ClpECFieldElement in '..\..\CryptoLib\src\Math\EC\ClpECFieldElement.pas';
 
 begin
 

+ 2 - 2
CryptoLib/src/Asn1/CryptoPro/ClpECGost3410NamedCurves.pas

@@ -27,8 +27,8 @@ uses
   ClpBigInteger,
   ClpCryptoProObjectIdentifiers,
   ClpRosstandartObjectIdentifiers,
-  ClpECC,
-  ClpIECC,
+  ClpECCurve,
+  ClpIECCore,
   ClpECParameters,
   ClpIECParameters,
   ClpIAsn1Objects;

+ 2 - 2
CryptoLib/src/Asn1/Sec/ClpSecNamedCurves.pas

@@ -33,8 +33,8 @@ uses
   ClpCryptoLibTypes,
   ClpECCompUtilities,
   ClpBigInteger,
-  ClpECC,
-  ClpIECC,
+  ClpECCurve,
+  ClpIECCore,
   ClpIAsn1Objects,
   ClpGlvTypeBEndomorphism,
   ClpIScalarSplitParameters,

+ 2 - 2
CryptoLib/src/Asn1/TeleTrust/ClpTeleTrusTNamedCurves.pas

@@ -31,8 +31,8 @@ uses
   ClpCryptoLibTypes,
   ClpBigInteger,
   ClpECCompUtilities,
-  ClpECC,
-  ClpIECC,
+  ClpECCurve,
+  ClpIECCore,
   ClpIAsn1Objects,
   ClpX9ECAsn1Objects,
   ClpIX9ECAsn1Objects,

+ 3 - 2
CryptoLib/src/Asn1/X9/ClpX9ECAsn1Objects.pas

@@ -30,7 +30,8 @@ uses
   ClpIAsn1Core,
   ClpIX9ECAsn1Objects,
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpECAlgorithms,
   ClpX9ObjectIdentifiers,
   ClpX9IntegerConverter,
@@ -38,7 +39,7 @@ uses
   ClpAsn1Utilities,
   ClpIFiniteField,
   ClpIPolynomialExtensionField,
-  ClpECC;
+  ClpECCurve;
 
 resourcestring
   SBadSequenceSize = 'Bad sequence size: %d';

+ 3 - 2
CryptoLib/src/Asn1/X9/ClpX9IntegerConverter.pas

@@ -23,7 +23,8 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type
@@ -59,7 +60,7 @@ end;
 
 class function TX9IntegerConverter.GetByteLength(const AC: IECCurve): Int32;
 begin
-  Result := AC.FieldElementEncodingLength;
+  Result := AC.GetFieldElementEncodingLength();
 end;
 
 class function TX9IntegerConverter.IntegerToBytes(const &AS: TBigInteger; AQLength: Int32): TCryptoLibByteArray;

+ 3 - 3
CryptoLib/src/Crypto/Agreements/ClpECDHBasicAgreement.pas

@@ -27,7 +27,7 @@ uses
   ClpECAlgorithms,
   ClpICipherParameters,
   ClpIECParameters,
-  ClpIECC,
+  ClpIECCore,
   ClpIBasicAgreement,
   ClpIECDHBasicAgreement,
   ClpIParametersWithRandom,
@@ -116,7 +116,7 @@ begin
     Q := TECAlgorithms.ReferenceMultiply(Q, h);
   end;
 
-  P := Q.Multiply(d).Normalize();
+  P := params.Curve.Multiplier.Multiply(Q, d).Normalize();
 
   if (P.IsInfinity) then
   begin
@@ -125,7 +125,7 @@ begin
 
   end;
 
-  result := P.AffineXCoord.ToBigInteger();
+  result := P.XCoord.ToBigInteger();
 end;
 
 function TECDHBasicAgreement.GetFieldSize: Int32;

+ 3 - 3
CryptoLib/src/Crypto/Agreements/ClpECDHCBasicAgreement.pas

@@ -26,7 +26,7 @@ uses
   ClpBigInteger,
   ClpECAlgorithms,
   ClpICipherParameters,
-  ClpIECC,
+  ClpIECCore,
   ClpIBasicAgreement,
   ClpIECParameters,
   ClpIECDHCBasicAgreement,
@@ -112,7 +112,7 @@ begin
       (@SInfinityInvalidPublicKey);
   end;
 
-  P := pubPoint.Multiply(hd).Normalize();
+  P := params.Curve.Multiplier.Multiply(pubPoint, hd).Normalize();
 
   if (P.IsInfinity) then
   begin
@@ -121,7 +121,7 @@ begin
 
   end;
 
-  result := P.AffineXCoord.ToBigInteger();
+  result := P.XCoord.ToBigInteger();
 end;
 
 function TECDHCBasicAgreement.GetFieldSize: Int32;

+ 2 - 2
CryptoLib/src/Crypto/EC/ClpCustomNamedCurves.pas

@@ -32,7 +32,7 @@ uses
   ClpSecObjectIdentifiers,
   ClpCryptoLibTypes,
   ClpBigInteger,
-  ClpECC,
+  ClpECCurve,
   ClpECCompUtilities,
   ClpSecP256K1Custom,
   ClpISecP256K1Custom,
@@ -44,7 +44,7 @@ uses
   ClpISecP521R1Custom,
   ClpSecT283Custom,
   ClpISecT283Custom,
-  ClpIECC,
+  ClpIECCore,
   ClpIAsn1Objects,
   ClpScalarSplitParameters,
   ClpIScalarSplitParameters,

+ 1 - 1
CryptoLib/src/Crypto/Generators/ClpECGenerators.pas

@@ -32,7 +32,7 @@ uses
   ClpIAsn1Objects,
   ClpIKeyGenerationParameters,
   ClpIECParameters,
-  ClpIECC,
+  ClpIECCore,
   ClpMultipliers,
   ClpIMultipliers,
   ClpSecObjectIdentifiers,

+ 1 - 1
CryptoLib/src/Crypto/Parameters/ClpECParameters.pas

@@ -26,7 +26,7 @@ uses
   SysUtils,
   ClpBigInteger,
   ClpECAlgorithms,
-  ClpIECC,
+  ClpIECCore,
   ClpIECParameters,
   ClpIAsn1Objects,
   ClpIX9ECAsn1Objects,

+ 2 - 1
CryptoLib/src/Crypto/Signers/ClpECDsaSigner.pas

@@ -26,7 +26,8 @@ uses
   ClpBigInteger,
   ClpSecureRandom,
   ClpECAlgorithms,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpIECParameters,
   ClpMultipliers,
   ClpCryptoLibTypes,

+ 1 - 1
CryptoLib/src/Crypto/Signers/ClpECNRSigner.pas

@@ -24,7 +24,7 @@ interface
 uses
   SysUtils,
   ClpIDsa,
-  ClpIECC,
+  ClpIECCore,
   ClpIECNRSigner,
   ClpBigInteger,
   ClpBigIntegers,

+ 1 - 1
CryptoLib/src/Factories/ClpPublicKeyFactory.pas

@@ -35,7 +35,7 @@ uses
   ClpIX9ECAsn1Objects,
   ClpX9ECAsn1Objects,
   ClpAsn1Objects,
-  ClpIECC,
+  ClpIECCore,
   ClpIDsaParameters,
   ClpIECParameters,
   ClpIX509Asn1Objects,

+ 2 - 1
CryptoLib/src/Interfaces/Asn1/X9/ClpIX9ECAsn1Objects.pas

@@ -25,7 +25,8 @@ uses
   ClpIAsn1Core,
   ClpIAsn1Objects,
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type

+ 1 - 1
CryptoLib/src/Interfaces/Crypto/Parameters/ClpIECParameters.pas

@@ -23,7 +23,7 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
   ClpIAsymmetricKeyParameter,
   ClpIKeyGenerationParameters,
   ClpIAsn1Objects,

+ 2 - 1
CryptoLib/src/Interfaces/Crypto/Signers/ClpIECDsaSigner.pas

@@ -26,7 +26,8 @@ uses
   ClpISecureRandom,
   ClpBigInteger,
   ClpCryptoLibTypes,
-  ClpIECC;
+  ClpIECCore,
+  ClpIECFieldElement;
 
 type
   IECDsaSigner = interface(IDsa)

+ 4 - 15
CryptoLib/src/Interfaces/Math/EC/Abc/ClpIZTauElement.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIZTauElement;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -25,21 +18,17 @@ uses
   ClpBigInteger;
 
 type
+  /// <summary>
+  /// Interface for an element of Z[tau], where lambda = u + v*tau.
+  /// </summary>
   IZTauElement = interface(IInterface)
-    ['{607ABBF3-AE3E-45AC-B772-92423508528A}']
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}']
 
     function GetU: TBigInteger;
     function GetV: TBigInteger;
 
-    // /**
-    // * The &quot;real&quot; part of <code>&#955;</code>.
-    // */
     property U: TBigInteger read GetU;
-    // /**
-    // * The &quot;<code>&#964;</code>-adic&quot; part of <code>&#955;</code>.
-    // */
     property V: TBigInteger read GetV;
-
   end;
 
 implementation

+ 0 - 709
CryptoLib/src/Interfaces/Math/EC/ClpIECC.pas

@@ -1,709 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpIECC;
-
-{$I ..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  Generics.Collections,
-  ClpIPreCompCallBack,
-  ClpCryptoLibTypes,
-  ClpIFiniteField,
-  ClpIPreCompInfo,
-  ClpLongArray,
-  ClpBigInteger;
-
-type
-  IECFieldElement = interface(IInterface)
-    ['{22B107FE-0F5A-4426-BBA0-C8E641E450B8}']
-
-    function GetFieldName: String;
-    function GetFieldSize: Int32;
-    function GetBitLength: Int32;
-    function GetIsOne: Boolean;
-    function GetIsZero: Boolean;
-
-    function ToBigInteger(): TBigInteger;
-    function Add(const b: IECFieldElement): IECFieldElement;
-    function AddOne(): IECFieldElement;
-    function Subtract(const b: IECFieldElement): IECFieldElement;
-    function Multiply(const b: IECFieldElement): IECFieldElement;
-    function Divide(const b: IECFieldElement): IECFieldElement;
-    function Negate(): IECFieldElement;
-    function Square(): IECFieldElement;
-    function Invert(): IECFieldElement;
-    function Sqrt(): IECFieldElement;
-
-    function MultiplyMinusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement;
-
-    function MultiplyPlusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement;
-
-    function SquareMinusProduct(const x, y: IECFieldElement): IECFieldElement;
-
-    function SquarePlusProduct(const x, y: IECFieldElement): IECFieldElement;
-
-    function SquarePow(pow: Int32): IECFieldElement;
-
-    function TestBitZero(): Boolean;
-
-    function Equals(const other: IECFieldElement): Boolean;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-    function ToString(): String;
-
-    function GetEncoded(): TCryptoLibByteArray;
-    function GetEncodedLength(): Int32;
-
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-    property BitLength: Int32 read GetBitLength;
-    property IsOne: Boolean read GetIsOne;
-    property IsZero: Boolean read GetIsZero;
-
-  end;
-
-type
-  IAbstractFpFieldElement = interface(IECFieldElement)
-
-    ['{C3FFD257-58FB-4730-B26A-E225C48F374E}']
-  end;
-
-type
-  IFpFieldElement = interface(IAbstractFpFieldElement)
-
-    ['{F5106EAC-DA8F-4815-8403-3D9C5438BF6F}']
-
-    function GetQ: TBigInteger;
-
-    function CheckSqrt(const z: IECFieldElement): IECFieldElement;
-    function LucasSequence(const P, Q, K: TBigInteger)
-      : TCryptoLibGenericArray<TBigInteger>;
-
-    function ModAdd(const x1, x2: TBigInteger): TBigInteger;
-    function ModDouble(const x: TBigInteger): TBigInteger;
-    function ModHalf(const x: TBigInteger): TBigInteger;
-    function ModHalfAbs(const x: TBigInteger): TBigInteger;
-    function ModInverse(const x: TBigInteger): TBigInteger;
-    function ModMult(const x1, x2: TBigInteger): TBigInteger;
-    function ModReduce(const x: TBigInteger): TBigInteger;
-    function ModSubtract(const x1, x2: TBigInteger): TBigInteger;
-
-    property Q: TBigInteger read GetQ;
-
-  end;
-
-type
-  IAbstractF2mFieldElement = interface(IECFieldElement)
-
-    ['{EA6B19A3-77AF-4EDE-A96B-D736DBD71B81}']
-
-    function Trace(): Int32;
-    function HalfTrace(): IECFieldElement;
-    function HasFastTrace(): Boolean;
-  end;
-
-type
-  IF2mFieldElement = interface(IAbstractF2mFieldElement)
-
-    ['{1B29CD22-21C3-424B-9496-BF5F1E4662E8}']
-
-    // /**
-    // * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
-    // */
-    function GetM: Int32;
-    /// <summary>
-    /// Tpb or Ppb.
-    /// </summary>
-    function GetRepresentation: Int32;
-    function GetKs: TCryptoLibInt32Array;
-    function GetX: TLongArray;
-
-    function GetK1: Int32;
-    function GetK2: Int32;
-    function GetK3: Int32;
-
-    // /**
-    // * @return the representation of the field
-    // * <code>F<sub>2<sup>m</sup></sub></code>, either of
-    // * {@link F2mFieldElement.Tpb} (trinomial
-    // * basis representation) or
-    // * {@link F2mFieldElement.Ppb} (pentanomial
-    // * basis representation).
-    // */
-    property Representation: Int32 read GetRepresentation;
-
-    // /**
-    // * @return the degree <code>m</code> of the reduction polynomial
-    // * <code>f(z)</code>.
-    // */
-    property m: Int32 read GetM;
-    // /**
-    // * @return Tpb: The integer <code>k</code> where <code>x<sup>m</sup> +
-    // * x<sup>k</sup> + 1</code> represents the reduction polynomial
-    // * <code>f(z)</code>.<br/>
-    // * Ppb: The integer <code>k1</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    property k1: Int32 read GetK1;
-    // /**
-    // * @return Tpb: Always returns <code>0</code><br/>
-    // * Ppb: The integer <code>k2</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    property k2: Int32 read GetK2;
-    // /**
-    // * @return Tpb: Always set to <code>0</code><br/>
-    // * Ppb: The integer <code>k3</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    property k3: Int32 read GetK3;
-
-    property ks: TCryptoLibInt32Array read GetKs;
-
-    /// <summary>
-    /// The <c>LongArray</c> holding the bits.
-    /// </summary>
-    property x: TLongArray read GetX;
-
-  end;
-
-type
-  IECCurve = interface;
-
-  IECPoint = interface(IInterface)
-    ['{625704AF-950B-4B39-976B-573A8DC42790}']
-
-    function GetIsInfinity: Boolean;
-    function GetIsCompressed: Boolean;
-    function GetpreCompTable: TDictionary<String, IPreCompInfo>;
-    procedure SetpreCompTable(const Value: TDictionary<String, IPreCompInfo>);
-    function GetCurve: IECCurve;
-    function GetCurveCoordinateSystem: Int32;
-    function GetAffineXCoord: IECFieldElement;
-    function GetAffineYCoord: IECFieldElement;
-    function GetXCoord: IECFieldElement;
-    function GetYCoord: IECFieldElement;
-    function GetCompressionYTilde: Boolean;
-
-    function SatisfiesOrder(): Boolean;
-    function SatisfiesCurveEquation(): Boolean;
-    function Detach(): IECPoint;
-
-    function RawXCoord: IECFieldElement;
-
-    function RawYCoord: IECFieldElement;
-
-    function RawZCoords: TCryptoLibGenericArray<IECFieldElement>;
-
-    function CreateScaledPoint(const sx, sy: IECFieldElement): IECPoint;
-
-    procedure CheckNormalized();
-
-    property CurveCoordinateSystem: Int32 read GetCurveCoordinateSystem;
-
-    property CompressionYTilde: Boolean read GetCompressionYTilde;
-
-    function GetDetachedPoint(): IECPoint;
-    function GetZCoord(index: Int32): IECFieldElement;
-    function GetZCoords(): TCryptoLibGenericArray<IECFieldElement>;
-
-    function IsNormalized(): Boolean;
-
-    /// <summary>
-    /// Normalization ensures that any projective coordinate is 1, and
-    /// therefore that the x, y <br />coordinates reflect those of the
-    /// equivalent point in an affine coordinate system.
-    /// </summary>
-    /// <returns>
-    /// a new ECPoint instance representing the same point, but with
-    /// normalized coordinates
-    /// </returns>
-    function Normalize(): IECPoint; overload;
-
-    function Normalize(const zInv: IECFieldElement): IECPoint; overload;
-
-    function ImplIsValid(decompressed, checkOrder: Boolean): Boolean;
-
-    function IsValid(): Boolean;
-
-    function IsValidPartial(): Boolean;
-
-    function ScaleX(const scale: IECFieldElement): IECPoint;
-    function ScaleY(const scale: IECFieldElement): IECPoint;
-
-    function ScaleXNegateY(const scale: IECFieldElement): IECPoint;
-    function ScaleYNegateX(const scale: IECFieldElement): IECPoint;
-
-    function GetEncoded(): TCryptoLibByteArray; overload;
-    function GetEncoded(compressed: Boolean): TCryptoLibByteArray; overload;
-
-    function Add(const b: IECPoint): IECPoint;
-    function Subtract(const b: IECPoint): IECPoint;
-    function Negate(): IECPoint;
-    function TimesPow2(e: Int32): IECPoint;
-
-    function Twice(): IECPoint;
-    function Multiply(b: TBigInteger): IECPoint;
-
-    function TwicePlus(const b: IECPoint): IECPoint;
-
-    function ThreeTimes(): IECPoint;
-
-    function Clone: IECPoint;
-
-    function Equals(const other: IECPoint): Boolean;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
-    function ToString(): String;
-
-    property preCompTable: TDictionary<String, IPreCompInfo>
-      read GetpreCompTable write SetpreCompTable;
-
-    /// <summary>
-    /// Returns the affine x-coordinate after checking that this point is
-    /// normalized.
-    /// </summary>
-    /// <value>
-    /// The affine x-coordinate of this point
-    /// </value>
-    /// <exception cref="ClpCryptoLibTypes|EInvalidOperationCryptoLibException">
-    /// if the point is not normalized
-    /// </exception>
-    property AffineXCoord: IECFieldElement read GetAffineXCoord;
-    /// <summary>
-    /// Returns the affine y-coordinate after checking that this point is
-    /// normalized.
-    /// </summary>
-    /// <value>
-    /// The affine y-coordinate of this point
-    /// </value>
-    /// <exception cref="ClpCryptoLibTypes|EInvalidOperationCryptoLibException">
-    /// if the point is not normalized
-    /// </exception>
-    property AffineYCoord: IECFieldElement read GetAffineYCoord;
-
-    /// <summary>
-    /// Returns the x-coordinate. <br />Caution: depending on the curve's
-    /// coordinate system, this may not be the same value as in an <br />
-    /// affine coordinate system; use Normalize() to get a point where the
-    /// coordinates have their <br />affine values, or use AffineXCoord if
-    /// you expect the point to already have been normalized.
-    /// </summary>
-    /// <value>
-    /// the x-coordinate of this point
-    /// </value>
-    property XCoord: IECFieldElement read GetXCoord;
-    /// <summary>
-    /// Returns the y-coordinate. <br />Caution: depending on the curve's
-    /// coordinate system, this may not be the same value as in an <br />
-    /// affine coordinate system; use Normalize() to get a point where the
-    /// coordinates have their <br />affine values, or use AffineYCoord if
-    /// you expect the point to already have been normalized.
-    /// </summary>
-    /// <value>
-    /// the y-coordinate of this point
-    /// </value>
-    property YCoord: IECFieldElement read GetYCoord;
-
-    property curve: IECCurve read GetCurve;
-
-    property IsInfinity: Boolean read GetIsInfinity;
-
-    property IsCompressed: Boolean read GetIsCompressed;
-  end;
-
-  IECPointBase = interface(IECPoint)
-    ['{66AF58F3-2A82-41AA-B01F-AA4A67CA5E80}']
-
-  end;
-
-  IAbstractFpPoint = interface(IECPointBase)
-    ['{57991B0C-7994-4130-93DC-02FEB42E131B}']
-
-  end;
-
-  IFpPoint = interface(IAbstractFpPoint)
-    ['{4113EEFE-A0F1-439B-97FD-921CA1E0A814}']
-
-    function Two(const x: IECFieldElement): IECFieldElement;
-    function Three(const x: IECFieldElement): IECFieldElement;
-    function Four(const x: IECFieldElement): IECFieldElement;
-    function Eight(const x: IECFieldElement): IECFieldElement;
-    function DoubleProductFromSquares(const a, b, aSquared,
-      bSquared: IECFieldElement): IECFieldElement;
-
-    function CalculateJacobianModifiedW(const z: IECFieldElement;
-      const ZSquared: IECFieldElement): IECFieldElement;
-
-    function GetJacobianModifiedW(): IECFieldElement;
-
-    function TwiceJacobianModified(calculateW: Boolean): IFpPoint;
-
-  end;
-
-  IAbstractF2mPoint = interface(IECPointBase)
-    ['{D5231494-74E4-4400-A2FE-8E512411515C}']
-
-    function Tau(): IAbstractF2mPoint;
-
-    function TauPow(pow: Int32): IAbstractF2mPoint;
-
-  end;
-
-  IF2mPoint = interface(IAbstractF2mPoint)
-    ['{ADFE17E0-6A08-430A-970F-353DE2B9426C}']
-
-  end;
-
-  // type
-  /// **
-  // * Interface for classes encapsulating a point multiplication algorithm
-  // * for <code>ECPoint</code>s.
-  // */
-  IECMultiplier = interface(IInterface)
-    ['{08D01BBB-38C1-4416-867A-D42FAB51E3CB}']
-
-    // /**
-    // * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.
-    // * <code>p</code> is added <code>k</code> times to itself.
-    // * @param p The <code>ECPoint</code> to be multiplied.
-    // * @param k The factor by which <code>p</code> is multiplied.
-    // * @return <code>p</code> multiplied by <code>k</code>.
-    // */
-
-    function Multiply(const P: IECPoint; const K: TBigInteger): IECPoint;
-
-  end;
-
-  // type
-  IECPointMap = interface(IInterface)
-    ['{73C2B23F-C05D-4916-8E30-14275F1051B6}']
-
-    function Map(const P: IECPoint): IECPoint;
-
-  end;
-
-  // type
-  IECEndomorphism = interface(IInterface)
-
-    ['{DFEE6FD7-C820-401D-8AD3-4DA9A7509DFD}']
-
-    function GetPointMap: IECPointMap;
-
-    function GetHasEfficientPointMap: Boolean;
-
-    property PointMap: IECPointMap read GetPointMap;
-
-    property HasEfficientPointMap: Boolean read GetHasEfficientPointMap;
-  end;
-
-  // type
-  IConfig = interface;
-  IECLookupTable = interface;
-
-  IECCurve = interface(IInterface)
-    ['{F340C8A1-034D-4845-BDE7-A5F55FFDE71B}']
-
-    procedure SetCoord(const Value: Int32);
-    procedure SetEndomorphism(const Value: IECEndomorphism);
-    procedure SetMultiplier(const Value: IECMultiplier);
-    function GetFieldSize: Int32;
-    function GetInfinity: IECPoint;
-    function GetField: IFiniteField;
-    function GetA: IECFieldElement;
-    function GetB: IECFieldElement;
-    function GetOrder: TBigInteger;
-    function GetCofactor: TBigInteger;
-    function GetCoordinateSystem: Int32;
-
-    function CloneCurve(): IECCurve;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      withCompression: Boolean): IECPoint; overload;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean): IECPoint; overload;
-
-    function CreateDefaultMultiplier(): IECMultiplier;
-
-    procedure CheckPoint(const point: IECPoint);
-
-    procedure CheckPoints(const points
-      : TCryptoLibGenericArray<IECPoint>); overload;
-
-    procedure CheckPoints(const points: TCryptoLibGenericArray<IECPoint>;
-      off, len: Int32); overload;
-
-    function DecompressPoint(yTilde: Int32; const x1: TBigInteger): IECPoint;
-
-    function GetFieldElementEncodingLength: Int32;
-
-    property FieldSize: Int32 read GetFieldSize;
-    property FieldElementEncodingLength: Int32 read GetFieldElementEncodingLength;
-    function FromBigInteger(const x: TBigInteger): IECFieldElement;
-    function IsValidFieldElement(const x: TBigInteger): Boolean;
-
-    function Configure(): IConfig;
-    function ValidatePoint(const x, y: TBigInteger): IECPoint; overload;
-
-    function ValidatePoint(const x, y: TBigInteger; withCompression: Boolean)
-      : IECPoint; overload;
-      deprecated 'Per-point compression property will be removed';
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-
-    function CreatePoint(const x, y: TBigInteger): IECPoint; overload;
-
-    function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
-      : IECPoint; overload;
-      deprecated 'Per-point compression property will be removed';
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean;
-
-    function GetPreCompInfo(const point: IECPoint; const name: String)
-      : IPreCompInfo;
-
-    /// <summary>
-    /// Compute a <c>PreCompInfo</c> for a point on this curve, under a given
-    /// name. Used by <c>ECMultiplier</c> to save the precomputation for this <c>
-    /// ECPoint</c> for use by subsequent multiplication.
-    /// </summary>
-    /// <param name="point">
-    /// The <c>ECPoint</c> to store precomputations for.
-    /// </param>
-    /// <param name="name">
-    /// A <c>String</c> used to index precomputations of different types.
-    /// </param>
-    /// <param name="callback">
-    /// Called to calculate the <c>PreCompInfo</c>
-    /// </param>
-    function Precompute(const point: IECPoint; const name: String;
-      const callback: IPreCompCallback): IPreCompInfo;
-
-    function ImportPoint(const P: IECPoint): IECPoint;
-
-    /// <summary>
-    /// Normalization ensures that any projective coordinate is 1, and
-    /// therefore that the x, y coordinates reflect those of the equivalent
-    /// point in an affine coordinate system. Where more than one point is to
-    /// be normalized, this method will generally be more efficient than
-    /// normalizing each point separately.
-    /// </summary>
-    /// <param name="points">
-    /// An array of points that will be updated in place with their normalized
-    /// versions, where necessary
-    /// </param>
-    procedure NormalizeAll(const points
-      : TCryptoLibGenericArray<IECPoint>); overload;
-
-    /// <summary>
-    /// Normalization ensures that any projective coordinate is 1, and
-    /// therefore that the x, y coordinates reflect those of the equivalent
-    /// point in an affine coordinate system. Where more than one point is to
-    /// be normalized, this method will generally be more efficient than
-    /// normalizing each point separately. An (optional) z-scaling factor can
-    /// be applied; effectively each z coordinate is scaled by this value prior
-    /// to normalization (but only one actual multiplication is needed).
-    /// </summary>
-    /// <param name="points">
-    /// An array of points that will be updated in place with their normalized
-    /// versions, where necessary
-    /// </param>
-    /// <param name="off">
-    /// The start of the range of points to normalize
-    /// </param>
-    /// <param name="len">
-    /// The length of the range of points to normalize
-    /// </param>
-    /// <param name="iso">
-    /// The (optional) z-scaling factor - can be null
-    /// </param>
-    procedure NormalizeAll(const points: TCryptoLibGenericArray<IECPoint>;
-      off, len: Int32; const iso: IECFieldElement); overload;
-
-    function GetEndomorphism(): IECEndomorphism;
-
-    /// <summary>
-    /// Sets the default <c>ECMultiplier</c>, unless already set.
-    /// </summary>
-    function GetMultiplier(): IECMultiplier;
-
-    /// <summary>
-    /// Decode a point on this curve from its ASN.1 encoding. The different
-    /// encodings are taken account of, including point compression for <br /><c>
-    /// F</c><b>p</b> (X9.62 s 4.2.1 pg 17).
-    /// </summary>
-    /// <returns>
-    /// The decoded point.
-    /// </returns>
-    function DecodePoint(const encoded: TCryptoLibByteArray): IECPoint;
-
-    property coord: Int32 write SetCoord;
-    property Endomorphism: IECEndomorphism write SetEndomorphism;
-    property Multiplier: IECMultiplier write SetMultiplier;
-
-    property Infinity: IECPoint read GetInfinity;
-
-    property field: IFiniteField read GetField;
-
-    property a: IECFieldElement read GetA;
-
-    property b: IECFieldElement read GetB;
-
-    property Order: TBigInteger read GetOrder;
-
-    property Cofactor: TBigInteger read GetCofactor;
-
-    property CoordinateSystem: Int32 read GetCoordinateSystem;
-
-    function Equals(const other: IECCurve): Boolean;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-  end;
-
-  IConfig = interface(IInterface)
-
-    ['{F4BD2FCC-FC9B-4FBB-8A3B-CC9031739D9F}']
-
-    function SetCoordinateSystem(coord: Int32): IConfig;
-    function SetEndomorphism(const Endomorphism: IECEndomorphism): IConfig;
-    function SetMultiplier(const Multiplier: IECMultiplier): IConfig;
-    function CreateCurve(): IECCurve;
-
-  end;
-
-  IECLookupTable = interface(IInterface)
-
-    ['{A1839961-4FBF-42EF-BF8B-6084064A05C1}']
-    function GetSize: Int32;
-    function Lookup(index: Int32): IECPoint;
-    function LookupVar(index: Int32): IECPoint;
-    property Size: Int32 read GetSize;
-  end;
-
-type
-  IAbstractECLookupTable = interface(IECLookupTable)
-    ['{9695E807-6A2A-4879-8438-84CE029AD143}']
-
-  end;
-
-type
-  ISimpleLookupTable = interface(IAbstractECLookupTable)
-    ['{5C2C8292-CECE-4A01-89D2-AF75B55F6FA3}']
-
-  end;
-
-type
-  IDefaultLookupTable = interface(IAbstractECLookupTable)
-    ['{094881EB-24A6-41A3-BAD6-D6DAB13DD17D}']
-
-  end;
-
-type
-  IAbstractFpCurve = interface(IECCurve)
-    ['{D37FE528-66B3-4449-A95C-8658A9A89B85}']
-
-  end;
-
-type
-  IDefaultF2mLookupTable = interface(IAbstractECLookupTable)
-    ['{0C019049-9839-4322-BAF5-8E5D39BC426D}']
-
-  end;
-
-type
-  IFpCurve = interface(IAbstractFpCurve)
-    ['{73E49F8B-C63F-4F91-8F40-A4C3B15F47FF}']
-
-    function GetQ: TBigInteger;
-
-    property Q: TBigInteger read GetQ;
-
-  end;
-
-type
-  IAbstractF2mCurve = interface(IECCurve)
-    ['{97782F77-89D4-410A-9343-518FAB97F349}']
-
-    /// <summary>
-    /// Returns true if this is a Koblitz curve (ABC curve).
-    /// </summary>
-    /// <returns>
-    /// true if this is a Koblitz curve (ABC curve), false otherwise
-    /// </returns>
-    function GetIsKoblitz: Boolean;
-
-    // /**
-    // * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-    // * D.1.6) The other solution is <code>z + 1</code>.
-    // *
-    // * @param beta
-    // *            The value to solve the qradratic equation for.
-    // * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-    // *         <code>null</code> if no solution exists.
-    // */
-    function SolveQuadraticEquation(const beta: IECFieldElement)
-      : IECFieldElement;
-
-    // /**
-    // * @return the auxiliary values <code>s<sub>0</sub></code> and
-    // * <code>s<sub>1</sub></code> used for partial modular reduction for
-    // * Koblitz curves.
-    // */
-    function GetSi(): TCryptoLibGenericArray<TBigInteger>;
-
-    property IsKoblitz: Boolean read GetIsKoblitz;
-
-  end;
-
-type
-  IF2mCurve = interface(IAbstractF2mCurve)
-    ['{B1C98330-51ED-4C0C-91B1-319223483147}']
-
-    function GetM: Int32;
-    function GetK1: Int32;
-    function GetK2: Int32;
-    function GetK3: Int32;
-
-    /// <summary>
-    /// Return true if curve uses a Trinomial basis.
-    /// </summary>
-    /// <returns>
-    /// return true if curve Trinomial, false otherwise.
-    /// </returns>
-    function IsTrinomial(): Boolean;
-
-    property m: Int32 read GetM;
-    property k1: Int32 read GetK1;
-    property k2: Int32 read GetK2;
-    property k3: Int32 read GetK3;
-
-  end;
-
-implementation
-
-end.

+ 242 - 0
CryptoLib/src/Interfaces/Math/EC/ClpIECCore.pas

@@ -0,0 +1,242 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpIECCore;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBigInteger,
+  ClpIFiniteField,
+  ClpIECFieldElement,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpISecureRandom,
+  ClpCryptoLibTypes;
+
+type
+  IECCurve = interface;
+  IECCurveConfig = interface;
+  IECMultiplier = interface;
+  IECPoint = interface;
+  IECPointBase = interface;
+  IAbstractFpPoint = interface;
+  IFpPoint = interface;
+  IAbstractF2mPoint = interface;
+  IF2mPoint = interface;
+
+  IECPointMap = interface(IInterface)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567822}']
+    function Map(const AP: IECPoint): IECPoint;
+  end;
+
+  IECEndomorphism = interface(IInterface)
+    ['{E5F6A7B8-C9D0-1234-E5F6-A7B8C9D01235}']
+    function GetPointMap: IECPointMap;
+    function GetHasEfficientPointMap: Boolean;
+    property PointMap: IECPointMap read GetPointMap;
+    property HasEfficientPointMap: Boolean read GetHasEfficientPointMap;
+  end;
+
+  IGlvEndomorphism = interface(IECEndomorphism)
+    ['{F6A7B8C9-D0E1-2345-F6A7-B8C9D0E12346}']
+    function DecomposeScalar(const AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
+  end;
+
+  IECLookupTable = interface(IInterface)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567821}']
+    function GetSize: Int32;
+    function Lookup(AIndex: Int32): IECPoint;
+    function LookupVar(AIndex: Int32): IECPoint;
+    property Size: Int32 read GetSize;
+  end;
+
+  ISimpleLookupTable = interface(IECLookupTable)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567835}']
+  end;
+
+  IECCurve = interface(IInterface)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567819}']
+    function GetHashCode: {$IFDEF DELPHI}Int32{$ELSE}PtrInt{$ENDIF};
+    function ToString: String;
+    function GetFieldSize: Int32;
+    function GetFieldElementEncodingLength: Int32;
+    function GetField: IFiniteField;
+    function GetInfinity: IECPoint;
+    function GetOrder: TBigInteger;
+    function GetCofactor: TBigInteger;
+    function GetCoordinateSystem: Int32;
+    function GetA: IECFieldElement;
+    function GetB: IECFieldElement;
+    function GetMultiplier: IECMultiplier;
+    function Equals(const AOther: IECCurve): Boolean;
+    property FieldSize: Int32 read GetFieldSize;
+    property FieldElementEncodingLength: Int32 read GetFieldElementEncodingLength;
+    property Field: IFiniteField read GetField;
+    property Infinity: IECPoint read GetInfinity;
+    property Order: TBigInteger read GetOrder;
+    property Cofactor: TBigInteger read GetCofactor;
+    property CoordinateSystem: Int32 read GetCoordinateSystem;
+    property A: IECFieldElement read GetA;
+    property B: IECFieldElement read GetB;
+    property Multiplier: IECMultiplier read GetMultiplier;
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement;
+    function CreatePoint(const AX, AY: TBigInteger): IECPoint;
+    function CreateRawPoint(const AX, AY: IECFieldElement): IECPoint; overload;
+    function CreateRawPoint(const AX, AY: IECFieldElement; const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; overload;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
+    function IsValidFieldElement(const AX: TBigInteger): Boolean;
+    function GetAffinePointEncodingLength(ACompressed: Boolean): Int32;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>; AOff, ALen: Int32): IECLookupTable;
+    function GetPreCompInfo(const APoint: IECPoint; const AName: String): IPreCompInfo;
+    function GetEndomorphism: IECEndomorphism;
+    procedure NormalizeAll(const APoints: TCryptoLibGenericArray<IECPoint>); overload;
+    procedure NormalizeAll(const APoints: TCryptoLibGenericArray<IECPoint>; AOff, ALen: Int32; const AIso: IECFieldElement); overload;
+    function ImportPoint(const AP: IECPoint): IECPoint;
+    function Precompute(const APoint: IECPoint; const AName: String; const ACallback: IPreCompCallback): IPreCompInfo; overload;
+    function Precompute(const AName: String; const ACallback: IPreCompCallback): IPreCompInfo; overload;
+    function DecodePoint(const AEncoded: TCryptoLibByteArray): IECPoint;
+    function Configure: IECCurveConfig;
+  end;
+
+  IECPoint = interface(IInterface)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567820}']
+
+    function GetCurve: IECCurve;
+    function GetIsInfinity: Boolean;
+    function GetXCoord: IECFieldElement;
+    function GetYCoord: IECFieldElement;
+    function GetRawXCoord: IECFieldElement;
+    function GetRawYCoord: IECFieldElement;
+    function GetZCoord(AIndex: Int32): IECFieldElement;
+    function IsNormalized: Boolean;
+    function GetAffineXCoord: IECFieldElement;
+    function GetAffineYCoord: IECFieldElement;
+    function GetCompressionYTilde: Boolean;
+
+    property Curve: IECCurve read GetCurve;
+    property IsInfinity: Boolean read GetIsInfinity;
+    property XCoord: IECFieldElement read GetXCoord;
+    property YCoord: IECFieldElement read GetYCoord;
+    property RawXCoord: IECFieldElement read GetRawXCoord;
+    property RawYCoord: IECFieldElement read GetRawYCoord;
+    property AffineXCoord: IECFieldElement read GetAffineXCoord;
+    property AffineYCoord: IECFieldElement read GetAffineYCoord;
+
+    function Normalize: IECPoint; overload;
+    function Normalize(const AZInv: IECFieldElement): IECPoint; overload;
+    function Detach: IECPoint;
+    function GetDetachedPoint: IECPoint;
+
+    function ScaleX(const AScale: IECFieldElement): IECPoint;
+    function ScaleXNegateY(const AScale: IECFieldElement): IECPoint;
+    function ScaleY(const AScale: IECFieldElement): IECPoint;
+    function ScaleYNegateX(const AScale: IECFieldElement): IECPoint;
+
+    function GetPreCompInfo(const AName: String): IPreCompInfo;
+    function Precompute(const AName: String; const ACallback: IPreCompCallback): IPreCompInfo;
+    function GetEncoded: TCryptoLibByteArray; overload;
+    function GetEncoded(ACompressed: Boolean): TCryptoLibByteArray; overload;
+    function GetEncodedLength(ACompressed: Boolean): Int32;
+    procedure EncodeTo(ACompressed: Boolean; var ABuf: TCryptoLibByteArray; AOff: Int32);
+    function IsValid: Boolean;
+    function IsValidPartial: Boolean;
+    function ImplIsValid(ADecompressed, ACheckOrder: Boolean): Boolean;
+    function SatisfiesCurveEquation: Boolean;
+    function SatisfiesOrder: Boolean;
+
+    function Add(const AB: IECPoint): IECPoint;
+    function Subtract(const AB: IECPoint): IECPoint;
+    function Negate: IECPoint;
+    function Twice: IECPoint;
+    function Multiply(const AK: TBigInteger): IECPoint;
+    function TimesPow2(AE: Int32): IECPoint;
+    function TwicePlus(const AB: IECPoint): IECPoint;
+    function ThreeTimes: IECPoint;
+    function Equals(const AOther: IECPoint): Boolean;
+  end;
+
+  IECPointBase = interface(IECPoint)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567830}']
+  end;
+
+  IAbstractFpPoint = interface(IECPointBase)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567831}']
+  end;
+
+  IFpPoint = interface(IAbstractFpPoint)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567832}']
+  end;
+
+  IAbstractF2mPoint = interface(IECPointBase)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567833}']
+    function Tau: IAbstractF2mPoint;
+    function TauPow(APow: Int32): IAbstractF2mPoint;
+  end;
+
+  IF2mPoint = interface(IAbstractF2mPoint)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567834}']
+  end;
+
+  IECCurveConfig = interface(IInterface)
+    ['{C5D6E7F8-A9B0-1234-C5D6-E7F8A9B01236}']
+
+    function SetCoordinateSystem(ACoord: Int32): IECCurveConfig;
+    function SetEndomorphism(const AEndomorphism: IECEndomorphism): IECCurveConfig;
+    function SetMultiplier(const AMultiplier: IECMultiplier): IECCurveConfig;
+    function CreateCurve: IECCurve;
+  end;
+
+  IAbstractFpCurve = interface(IECCurve)
+    ['{B2C3D4E5-F6A7-8901-BCDE-F12345678901}']
+    function IsValidFieldElement(const AX: TBigInteger): Boolean; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint; override;
+  end;
+
+  IFpCurve = interface(IAbstractFpCurve)
+    ['{B2C3D4E5-F6A7-8901-BCDE-F12345678902}']
+  end;
+
+  IAbstractF2mCurve = interface(IECCurve)
+    ['{B2C3D4E5-F6A7-8901-BCDE-F12345678901}']
+    function GetIsKoblitz: Boolean;
+    function SolveQuadraticEquation(const ABeta: IECFieldElement): IECFieldElement;
+    property IsKoblitz: Boolean read GetIsKoblitz;
+  end;
+
+  IF2mCurve = interface(IAbstractF2mCurve)
+    ['{C3D4E5F6-A7B8-9012-CDEF-123456789013}']
+  end;
+
+  IECMultiplier = interface(IInterface)
+    ['{D4E5F6A7-B8C9-0123-D4E5-F6A7B8C90124}']
+
+    function Multiply(const APoint: IECPoint; const AK: TBigInteger): IECPoint;
+  end;
+
+  IWNafL2RMultiplier = interface(IECMultiplier)
+    ['{E5F6A7B8-C9D0-2345-E5F6-A7B8C9D02346}']
+  end;
+
+implementation
+
+end.

+ 102 - 0
CryptoLib/src/Interfaces/Math/EC/ClpIECFieldElement.pas

@@ -0,0 +1,102 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+unit ClpIECFieldElement;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBigInteger,
+  ClpLongArray,
+  ClpCryptoLibTypes;
+
+type
+  IECFieldElement = interface(IInterface)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567818}']
+
+    function GetHashCode: {$IFDEF DELPHI}Int32{$ELSE}PtrInt{$ENDIF};
+    function ToString: String;
+    function GetFieldName: String;
+    function GetFieldSize: Int32;
+
+    property FieldName: String read GetFieldName;
+    property FieldSize: Int32 read GetFieldSize;
+
+    function ToBigInteger: TBigInteger;
+    function GetEncoded: TCryptoLibByteArray;
+    function GetEncodedLength: Int32;
+    procedure EncodeTo(var ABuf: TCryptoLibByteArray; AOff: Int32);
+    function GetIsOne: Boolean;
+    function GetIsZero: Boolean;
+    function GetBitLength: Int32;
+    function TestBitZero: Boolean;
+    function Equals(const AOther: IECFieldElement): Boolean;
+    function Add(const AB: IECFieldElement): IECFieldElement;
+    function AddOne: IECFieldElement;
+    function Subtract(const AB: IECFieldElement): IECFieldElement;
+    function Multiply(const AB: IECFieldElement): IECFieldElement;
+    function Divide(const AB: IECFieldElement): IECFieldElement;
+    function Negate: IECFieldElement;
+    function Square: IECFieldElement;
+    function Invert: IECFieldElement;
+    function Sqrt: IECFieldElement;
+    function MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+    function MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+    function SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+    function SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+    function SquarePow(APow: Int32): IECFieldElement;
+  end;
+
+  IFpFieldElement = interface(IECFieldElement)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF123456781A}']
+
+    function GetQ: TBigInteger;
+
+    property Q: TBigInteger read GetQ;
+  end;
+
+  IAbstractF2mFieldElement = interface(IECFieldElement)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF123456781C}']
+
+    function HalfTrace: IECFieldElement;
+    function GetHasFastTrace: Boolean;
+    function Trace: Int32;
+
+    property HasFastTrace: Boolean read GetHasFastTrace;
+  end;
+
+  IF2mFieldElement = interface(IAbstractF2mFieldElement)
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF123456781B}']
+
+    function GetRepresentation: Int32;
+    function GetM: Int32;
+    function GetK1: Int32;
+    function GetK2: Int32;
+    function GetK3: Int32;
+    function GetX: TLongArray;
+
+    property Representation: Int32 read GetRepresentation;
+    property M: Int32 read GetM;
+    property K1: Int32 read GetK1;
+    property K2: Int32 read GetK2;
+    property K3: Int32 read GetK3;
+    property X: TLongArray read GetX;
+  end;
+
+implementation
+
+end.

+ 3 - 8
CryptoLib/src/Interfaces/Math/EC/ClpIScaleXPointMap.pas → CryptoLib/src/Interfaces/Math/EC/ClpIECPointMap.pas

@@ -15,21 +15,16 @@
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 
-unit ClpIScaleXPointMap;
+unit ClpIECPointMap;
 
 {$I ..\..\..\Include\CryptoLib.inc}
 
 interface
 
 uses
-  ClpIECC;
+  ClpIECCore;
 
-type
-  IScaleXPointMap = interface(IECPointMap)
-
-    ['{3449A622-7472-4B51-A9EF-01B5E586813C}']
-
-  end;
+  { IECPointMap is declared in ClpIECCore to avoid circular unit reference. }
 
 implementation
 

+ 1 - 1
CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP256K1Custom.pas

@@ -23,7 +23,7 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
   ClpCryptoLibTypes;
 
 type

+ 1 - 1
CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP256R1Custom.pas

@@ -23,7 +23,7 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
   ClpCryptoLibTypes;
 
 type

+ 1 - 1
CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP384R1Custom.pas

@@ -23,7 +23,7 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
   ClpCryptoLibTypes;
 
 type

+ 1 - 1
CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecP521R1Custom.pas

@@ -23,7 +23,7 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIECC,
+  ClpIECCore,
   ClpCryptoLibTypes;
 
 type

+ 1 - 1
CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecT283Custom.pas

@@ -22,7 +22,7 @@ unit ClpISecT283Custom;
 interface
 
 uses
-  ClpIECC,
+  ClpIECCore,
   ClpCryptoLibTypes;
 
 type

+ 5 - 28
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIEndoPreCompInfo.pas

@@ -1,20 +1,3 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIEndoPreCompInfo;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,24 +5,18 @@ unit ClpIEndoPreCompInfo;
 interface
 
 uses
-  ClpIECC,
+  ClpIECCore,
   ClpIPreCompInfo;
 
 type
   IEndoPreCompInfo = interface(IPreCompInfo)
-    ['{84C79A80-8162-4079-8146-AA1D46A739ED}']
-
+    ['{B1C2D3E4-F5A6-7890-BCDE-F12345678903}']
     function GetEndomorphism: IECEndomorphism;
-    procedure SetEndomorphism(const value: IECEndomorphism);
-
-    property Endomorphism: IECEndomorphism read GetEndomorphism
-      write SetEndomorphism;
-
+    procedure SetEndomorphism(const AValue: IECEndomorphism);
     function GetMappedPoint: IECPoint;
-    procedure SetMappedPoint(const value: IECPoint);
-
+    procedure SetMappedPoint(const AValue: IECPoint);
+    property Endomorphism: IECEndomorphism read GetEndomorphism write SetEndomorphism;
     property MappedPoint: IECPoint read GetMappedPoint write SetMappedPoint;
-
   end;
 
 implementation

+ 0 - 35
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeAEndomorphism.pas

@@ -1,35 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpIGlvTypeAEndomorphism;
-
-{$I ..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpIGlvEndomorphism;
-
-type
-  IGlvTypeAEndomorphism = interface(IGlvEndomorphism)
-    ['{961A1588-7D37-46C5-BC67-F71063641B42}']
-
-  end;
-
-implementation
-
-end.

+ 0 - 45
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeAParameters.pas

@@ -1,45 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpIGlvTypeAParameters;
-
-{$I ..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpBigInteger,
-  ClpIScalarSplitParameters;
-
-type
-
-  IGlvTypeAParameters = interface(IInterface)
-    ['{B5DDABB5-B51C-41F4-B2FD-6C8733300502}']
-
-    function GetI: TBigInteger;
-    function GetLambda: TBigInteger;
-    function GetSplitParams: IScalarSplitParameters;
-
-    property I: TBigInteger read GetI;
-    property lambda: TBigInteger read GetLambda;
-    property splitParams: IScalarSplitParameters read GetSplitParams;
-
-  end;
-
-implementation
-
-end.

+ 2 - 10
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeBEndomorphism.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIGlvTypeBEndomorphism;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,12 +15,11 @@ unit ClpIGlvTypeBEndomorphism;
 interface
 
 uses
-  ClpIGlvEndomorphism;
+  ClpIECCore;
 
 type
   IGlvTypeBEndomorphism = interface(IGlvEndomorphism)
-    ['{4F285F6A-F627-4873-9F4C-FBC7A7B83A9C}']
-
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567892}']
   end;
 
 implementation

+ 5 - 16
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvTypeBParameters.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIGlvTypeBParameters;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -26,18 +19,14 @@ uses
   ClpIScalarSplitParameters;
 
 type
-
   IGlvTypeBParameters = interface(IInterface)
-    ['{089AC2AB-15A1-47F5-BED0-C09EA77BECB9}']
-
-    function GetLambda: TBigInteger;
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567891}']
     function GetBeta: TBigInteger;
+    function GetLambda: TBigInteger;
     function GetSplitParams: IScalarSplitParameters;
-
-    property lambda: TBigInteger read GetLambda;
-    property beta: TBigInteger read GetBeta;
-    property splitParams: IScalarSplitParameters read GetSplitParams;
-
+    property Beta: TBigInteger read GetBeta;
+    property Lambda: TBigInteger read GetLambda;
+    property SplitParams: IScalarSplitParameters read GetSplitParams;
   end;
 
 implementation

+ 8 - 17
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIScalarSplitParameters.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIScalarSplitParameters;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,28 +15,26 @@ unit ClpIScalarSplitParameters;
 interface
 
 uses
-  ClpBigInteger;
+  ClpBigInteger,
+  ClpCryptoLibTypes;
 
 type
   IScalarSplitParameters = interface(IInterface)
-    ['{C36FF223-C4F3-4483-B280-A50EF95497AF}']
-
-    function GetG1: TBigInteger;
-    function GetG2: TBigInteger;
+    ['{C1D2E3F4-A5B6-7890-CDEF-1234567890AB}']
     function GetV1A: TBigInteger;
     function GetV1B: TBigInteger;
     function GetV2A: TBigInteger;
     function GetV2B: TBigInteger;
+    function GetG1: TBigInteger;
+    function GetG2: TBigInteger;
     function GetBits: Int32;
-
-    property g1: TBigInteger read GetG1;
-    property g2: TBigInteger read GetG2;
     property V1A: TBigInteger read GetV1A;
     property V1B: TBigInteger read GetV1B;
     property V2A: TBigInteger read GetV2A;
     property V2B: TBigInteger read GetV2B;
-    property bits: Int32 read GetBits;
-
+    property G1: TBigInteger read GetG1;
+    property G2: TBigInteger read GetG2;
+    property Bits: Int32 read GetBits;
   end;
 
 implementation

+ 9 - 20
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIFixedPointPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIFixedPointPreCompInfo;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,26 +15,22 @@ unit ClpIFixedPointPreCompInfo;
 interface
 
 uses
-  ClpIECC,
-  ClpIPreCompInfo;
+  ClpIECCore,
+  ClpIPreCompInfo,
+  ClpCryptoLibTypes;
 
 type
   IFixedPointPreCompInfo = interface(IPreCompInfo)
-    ['{FD2E7BE8-D353-4229-981A-744A50EE9F7F}']
-
-    function GetWidth: Int32;
-    procedure SetWidth(const Value: Int32);
+    ['{D2E3F4A5-B6C7-8901-DEF0-234567890ABC}']
     function GetLookupTable: IECLookupTable;
-    procedure SetLookupTable(const Value: IECLookupTable);
+    procedure SetLookupTable(const AValue: IECLookupTable);
     function GetOffset: IECPoint;
-    procedure SetOffset(const Value: IECPoint);
-
+    procedure SetOffset(const AValue: IECPoint);
+    function GetWidth: Int32;
+    procedure SetWidth(AValue: Int32);
+    property LookupTable: IECLookupTable read GetLookupTable write SetLookupTable;
     property Offset: IECPoint read GetOffset write SetOffset;
-
-    property LookupTable: IECLookupTable read GetLookupTable
-      write SetLookupTable;
     property Width: Int32 read GetWidth write SetWidth;
-
   end;
 
 implementation

+ 0 - 78
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIMultipliers.pas

@@ -1,78 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpIMultipliers;
-
-{$I ..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpBigInteger,
-  ClpIZTauElement,
-  ClpIECC;
-
-type
-  IAbstractECMultiplier = interface(IECMultiplier)
-    ['{DD63984C-7D4D-46DE-9004-20FD909C2EFB}']
-
-    function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
-      : IECPoint;
-
-  end;
-
-type
-  IFixedPointCombMultiplier = interface(IAbstractECMultiplier)
-    ['{A3345E31-4D5C-4442-9C3D-ACC7F6DA4A14}']
-
-  end;
-
-type
-  IGlvMultiplier = interface(IAbstractECMultiplier)
-    ['{F54D54F5-F544-421B-89FC-1D8058FB8F33}']
-
-  end;
-
-type
-  IWNafL2RMultiplier = interface(IAbstractECMultiplier)
-
-    ['{E2A5E4EF-C092-4F83-ACCF-0FC8731FB274}']
-
-  end;
-
-type
-  IWTauNafMultiplier = interface(IAbstractECMultiplier)
-    ['{B71E75E5-FB6D-4A54-BE8A-820FC9A1E509}']
-
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code> using
-    // * the <code>&#964;</code>-adic NAF (TNAF) method.
-    // * @param p The AbstractF2mPoint to multiply.
-    // * @param lambda The element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code> of which to compute the
-    // * <code>[&#964;]</code>-adic NAF.
-    // * @return <code>p</code> multiplied by <code>&#955;</code>.
-    // */
-    function MultiplyWTnaf(const p: IAbstractF2mPoint;
-      const lambda: IZTauElement; a, mu: ShortInt): IAbstractF2mPoint;
-
-  end;
-
-implementation
-
-end.

+ 4 - 10
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIPreCompCallBack.pas → CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIPreCompCallback.pas

@@ -6,16 +6,9 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpIPreCompCallBack;
+unit ClpIPreCompCallback;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
 
@@ -26,8 +19,9 @@ uses
 
 type
   IPreCompCallback = interface(IInterface)
-    ['{3C0F2A0E-B396-4F0A-82B4-690F204D27ED}']
-    function Precompute(const existing: IPreCompInfo): IPreCompInfo;
+    ['{C3D4E5F6-A7B8-9012-C3D4-E5F6A7B89013}']
+
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
   end;
 
 implementation

+ 1 - 14
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIPreCompInfo;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,14 +15,8 @@ unit ClpIPreCompInfo;
 interface
 
 type
-
-  /// <summary>
-  /// Interface for classes storing precomputation data for multiplication
-  /// algorithms. Used as a Memento (see GOF patterns) for
-  /// &lt;code&gt;WNafMultiplier&lt;/code&gt;.
-  /// </summary>
   IPreCompInfo = interface(IInterface)
-    ['{8274B14C-C784-4964-9412-AAB3F7A36AB2}']
+    ['{B2C3D4E5-F6A7-8901-B2C3-D4E5F6A78902}']
   end;
 
 implementation

+ 8 - 17
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIValidityPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIValidityPreCompInfo;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -26,16 +19,14 @@ uses
 
 type
   IValidityPreCompInfo = interface(IPreCompInfo)
-
-    ['{2339F5CA-A4B3-4E95-B358-4D4F4CA97EB3}']
-
-    function HasFailed(): Boolean;
-    procedure ReportFailed();
-    function HasCurveEquationPassed(): Boolean;
-    procedure ReportCurveEquationPassed();
-    function HasOrderPassed(): Boolean;
-    procedure ReportOrderPassed();
-
+    ['{D4E5F6A7-B890-1234-D4E5-F6A7B8901235}']
+
+    function HasFailed: Boolean;
+    procedure ReportFailed;
+    function HasCurveEquationPassed: Boolean;
+    procedure ReportCurveEquationPassed;
+    function HasOrderPassed: Boolean;
+    procedure ReportOrderPassed;
   end;
 
 implementation

+ 18 - 34
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIWNafPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIWNafPreCompInfo;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,45 +15,36 @@ unit ClpIWNafPreCompInfo;
 interface
 
 uses
-  ClpCryptoLibTypes,
-  ClpIECC,
-  ClpIPreCompInfo;
+  ClpIECCore,
+  ClpIPreCompInfo,
+  ClpCryptoLibTypes;
 
 type
   IWNafPreCompInfo = interface(IPreCompInfo)
-    ['{DB29636B-A1EB-40C3-96C2-0B7830A55DB9}']
+    ['{E6F7A8B9-C0D1-2345-E6F7-A8B9C0D12346}']
 
+    function DecrementPromotionCountdown: Int32;
+    function GetConfWidth: Int32;
+    procedure SetConfWidth(AValue: Int32);
     function GetPreComp: TCryptoLibGenericArray<IECPoint>;
-    procedure SetPreComp(const Value: TCryptoLibGenericArray<IECPoint>);
+    procedure SetPreComp(const AValue: TCryptoLibGenericArray<IECPoint>);
     function GetPreCompNeg: TCryptoLibGenericArray<IECPoint>;
-    procedure SetPreCompNeg(const Value: TCryptoLibGenericArray<IECPoint>);
+    procedure SetPreCompNeg(const AValue: TCryptoLibGenericArray<IECPoint>);
     function GetTwice: IECPoint;
-    procedure SetTwice(const Value: IECPoint);
-
-    function GetConfWidth: Int32;
-    procedure SetConfWidth(Value: Int32);
-
+    procedure SetTwice(const AValue: IECPoint);
     function GetWidth: Int32;
-    procedure SetWidth(Value: Int32);
-
+    procedure SetWidth(AValue: Int32);
+    function GetIsPromoted: Boolean;
     function GetPromotionCountdown: Int32;
-    procedure SetPromotionCountdown(Value: Int32);
-
-    function DecrementPromotionCountdown: Int32;
-
-    function IsPromoted: Boolean;
-
-    property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp
-      write SetPreComp;
-    property PreCompNeg: TCryptoLibGenericArray<IECPoint> read GetPreCompNeg
-      write SetPreCompNeg;
-    property Twice: IECPoint read GetTwice write SetTwice;
+    procedure SetPromotionCountdown(AValue: Int32);
 
     property ConfWidth: Int32 read GetConfWidth write SetConfWidth;
+    property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp write SetPreComp;
+    property PreCompNeg: TCryptoLibGenericArray<IECPoint> read GetPreCompNeg write SetPreCompNeg;
+    property Twice: IECPoint read GetTwice write SetTwice;
     property Width: Int32 read GetWidth write SetWidth;
-    property PromotionCountdown: Int32 read GetPromotionCountdown
-      write SetPromotionCountdown;
-
+    property IsPromoted: Boolean read GetIsPromoted;
+    property PromotionCountdown: Int32 read GetPromotionCountdown write SetPromotionCountdown;
   end;
 
 implementation

+ 6 - 16
CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIWTauNafPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpIWTauNafPreCompInfo;
 
 {$I ..\..\..\..\Include\CryptoLib.inc}
@@ -22,21 +15,18 @@ unit ClpIWTauNafPreCompInfo;
 interface
 
 uses
-  ClpIECC,
-  ClpCryptoLibTypes,
-  ClpIPreCompInfo;
+  ClpIECCore,
+  ClpIPreCompInfo,
+  ClpCryptoLibTypes;
 
 type
   IWTauNafPreCompInfo = interface(IPreCompInfo)
-    ['{E2E76FDB-8DD6-4DB5-9EC7-58C87DE8AD3D}']
+    ['{F7A8B9C0-D1E2-3456-F7A8-B9C0D1E23457}']
 
     function GetPreComp: TCryptoLibGenericArray<IAbstractF2mPoint>;
-    procedure SetPreComp(const value
-      : TCryptoLibGenericArray<IAbstractF2mPoint>);
-
-    property PreComp: TCryptoLibGenericArray<IAbstractF2mPoint> read GetPreComp
-      write SetPreComp;
+    procedure SetPreComp(const AValue: TCryptoLibGenericArray<IAbstractF2mPoint>);
 
+    property PreComp: TCryptoLibGenericArray<IAbstractF2mPoint> read GetPreComp write SetPreComp;
   end;
 
 implementation

+ 4 - 5
CryptoLib/src/Interfaces/Math/Field/ClpIExtensionField.pas

@@ -25,15 +25,14 @@ uses
   ClpIFiniteField;
 
 type
-
   IExtensionField = interface(IFiniteField)
-    ['{262CB0BB-E070-4B0A-971B-33F4357BC4B5}']
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567803}']
 
-    function GetDegree: Int32;
     function GetSubfield: IFiniteField;
-    property Degree: Int32 read GetDegree;
-    property Subfield: IFiniteField read GetSubfield;
+    function GetDegree: Int32;
 
+    property Subfield: IFiniteField read GetSubfield;
+    property Degree: Int32 read GetDegree;
   end;
 
 implementation

+ 6 - 3
CryptoLib/src/Interfaces/Math/Field/ClpIFiniteField.pas

@@ -22,18 +22,21 @@ unit ClpIFiniteField;
 interface
 
 uses
-  ClpBigInteger;
+  ClpBigInteger,
+  ClpCryptoLibTypes;
 
 type
-
   IFiniteField = interface(IInterface)
-    ['{54DEBFF8-A0DF-4406-8F0C-FB1D0BD2619B}']
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567801}']
 
     function GetCharacteristic: TBigInteger;
     function GetDimension: Int32;
+
     property Characteristic: TBigInteger read GetCharacteristic;
     property Dimension: Int32 read GetDimension;
 
+    function Equals(const AOther: IFiniteField): Boolean;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
   end;
 
 implementation

+ 1 - 10
CryptoLib/src/Interfaces/Math/Field/ClpIGF2Polynomial.pas

@@ -22,20 +22,11 @@ unit ClpIGF2Polynomial;
 interface
 
 uses
-  ClpCryptoLibTypes,
   ClpIPolynomial;
 
 type
   IGF2Polynomial = interface(IPolynomial)
-    ['{B60318B7-B459-4C09-9D0A-67C84DF794B3}']
-
-    function GetExponents: TCryptoLibInt32Array;
-
-    function Equals(const other: IGF2Polynomial): Boolean;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-    property exponents: TCryptoLibInt32Array read GetExponents;
-
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567812}']
   end;
 
 implementation

+ 1 - 7
CryptoLib/src/Interfaces/Math/Field/ClpIGenericPolynomialExtensionField.pas

@@ -26,13 +26,7 @@ uses
 
 type
   IGenericPolynomialExtensionField = interface(IPolynomialExtensionField)
-    ['{BB3A963B-38E1-4DF0-A0C6-86DF5CE830FA}']
-
-    function Equals(other: TObject): Boolean; overload;
-    function Equals(const other: IGenericPolynomialExtensionField)
-      : Boolean; overload;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567813}']
   end;
 
 implementation

+ 6 - 3
CryptoLib/src/Interfaces/Math/Field/ClpIPolynomial.pas

@@ -25,14 +25,17 @@ uses
   ClpCryptoLibTypes;
 
 type
-
   IPolynomial = interface(IInterface)
-    ['{955B9231-3DE9-42D9-9D3C-20B080C1D951}']
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567802}']
 
-    function GetExponentsPresent(): TCryptoLibInt32Array;
     function GetDegree: Int32;
+    function GetExponentsPresent: TCryptoLibInt32Array;
+
     property Degree: Int32 read GetDegree;
+    property ExponentsPresent: TCryptoLibInt32Array read GetExponentsPresent;
 
+    function Equals(const AOther: IPolynomial): Boolean;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
   end;
 
 implementation

+ 4 - 5
CryptoLib/src/Interfaces/Math/Field/ClpIPolynomialExtensionField.pas

@@ -22,17 +22,16 @@ unit ClpIPolynomialExtensionField;
 interface
 
 uses
-  ClpIPolynomial,
-  ClpIExtensionField;
+  ClpIExtensionField,
+  ClpIPolynomial;
 
 type
-
   IPolynomialExtensionField = interface(IExtensionField)
-    ['{40B4388E-7014-4E15-9E93-9F5173F7F7E0}']
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567804}']
 
     function GetMinimalPolynomial: IPolynomial;
-    property MinimalPolynomial: IPolynomial read GetMinimalPolynomial;
 
+    property MinimalPolynomial: IPolynomial read GetMinimalPolynomial;
   end;
 
 implementation

+ 1 - 6
CryptoLib/src/Interfaces/Math/Field/ClpIPrimeField.pas

@@ -26,12 +26,7 @@ uses
 
 type
   IPrimeField = interface(IFiniteField)
-    ['{242D0BB8-1F38-4AC2-B7F7-D67AF94F7EEE}']
-
-    function Equals(other: TObject): Boolean; overload;
-    function Equals(const other: IPrimeField): Boolean; overload;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+    ['{A1B2C3D4-E5F6-7890-ABCD-EF1234567811}']
   end;
 
 implementation

+ 32 - 0
CryptoLib/src/Math/ClpBigIntegers.pas

@@ -24,6 +24,7 @@ interface
 uses
   SysUtils,
   Classes,
+  Generics.Defaults,
   ClpBigInteger,
   ClpMod,
   ClpNat,
@@ -38,6 +39,16 @@ resourcestring
   SBigIntegerNotInvertible = 'BigInteger not invertible';
 
 type
+  /// <summary>
+  /// Equality comparer for TBigInteger that uses value-based comparison
+  /// (Equals) instead of reference equality. Used with TDictionary.
+  /// </summary>
+  TBigIntegerEqualityComparer = class(TInterfacedObject, IEqualityComparer<TBigInteger>)
+  strict private
+    function Equals(const ALeft, ARight: TBigInteger): Boolean; reintroduce;
+    function GetHashCode(const AValue: TBigInteger): Integer; reintroduce;
+  end;
+
   /// <summary>
   /// BigInteger utilities.
   /// </summary>
@@ -46,6 +57,9 @@ type
     const
       MaxIterations = 1000;
 
+    class var
+      FBigIntegerEqualityComparer: IEqualityComparer<TBigInteger>;
+
     class constructor Create;
 
   public
@@ -53,6 +67,11 @@ type
       Zero: TBigInteger;
       One: TBigInteger;
 
+    /// <summary>
+    /// Gets the BigInteger equality comparer for use with TDictionary.
+    /// </summary>
+    class property BigIntegerEqualityComparer: IEqualityComparer<TBigInteger> read FBigIntegerEqualityComparer;
+
     /// <summary>
     /// Return the passed in value as an unsigned byte array.
     /// </summary>
@@ -168,12 +187,25 @@ type
 
 implementation
 
+{ TBigIntegerEqualityComparer }
+
+function TBigIntegerEqualityComparer.Equals(const ALeft, ARight: TBigInteger): Boolean;
+begin
+  Result := ALeft.Equals(ARight);
+end;
+
+function TBigIntegerEqualityComparer.GetHashCode(const AValue: TBigInteger): Integer;
+begin
+  Result := AValue.GetHashCode();
+end;
+
 { TBigIntegers }
 
 class constructor TBigIntegers.Create;
 begin
   Zero := TBigInteger.Zero;
   One := TBigInteger.One;
+  FBigIntegerEqualityComparer := TBigIntegerEqualityComparer.Create();
 end;
 
 class function TBigIntegers.AsUnsignedByteArray(const AN: TBigInteger): TCryptoLibByteArray;

+ 144 - 235
CryptoLib/src/Math/EC/Abc/ClpSimpleBigDecimal.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpSimpleBigDecimal;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,321 +15,237 @@ unit ClpSimpleBigDecimal;
 interface
 
 uses
-  ClpCryptoLibTypes,
-  ClpBigInteger;
+  SysUtils,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidScale = 'Scale may not be Negative';
-  SUnEqualScale =
-    'Only SimpleBigDecimal of Same Scale Allowed in Arithmetic Operations';
-  SNegativeScale = 'Scale may not be Negative';
+  SScaleMayNotBeNegative = 'scale may not be negative';
+  SSameScaleRequired = 'Only SimpleBigDecimal of same scale allowed in arithmetic operations';
 
 type
-  /// **
-  // * Class representing a simple version of a big decimal. A
-  // * <code>SimpleBigDecimal</code> is basically a
-  // * {@link java.math.BigInteger BigInteger} with a few digits on the right of
-  // * the decimal point. The number of (binary) digits on the right of the decimal
-  // * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.
-  // * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
-  // * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s
-  // * taking part in the same arithmetic operation must have equal scale. The
-  // * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a
-  // * <code>SimpleBigDecimal</code> with double scale.
-  // */
+  /// <summary>
+  /// Class representing a simple version of a big decimal. A
+  /// SimpleBigDecimal is basically a BigInteger with a few digits on the
+  /// right of the decimal point. The number of (binary) digits on the right
+  /// of the decimal point is called the scale of the SimpleBigDecimal.
+  /// </summary>
   TSimpleBigDecimal = record
-
-  strict private
-  var
-    FbigInt: TBigInteger;
-    Fscale: Int32;
-
   strict private
-
-    function GetInt32Value: Int32; inline;
-    function GetInt64Value: Int64; inline;
-    function GetScale: Int32; inline;
-
-    // constructor Create(const limBigDec: TSimpleBigDecimal); overload;
-
-    procedure CheckScale(const b: TSimpleBigDecimal); inline;
-
+    FBigInt: TBigInteger;
+    FScale: Int32;
+    procedure CheckScale(const AB: TSimpleBigDecimal);
   public
-    // /**
-    // * Constructor for <code>SimpleBigDecimal</code>. The value of the
-    // * constructed <code>SimpleBigDecimal</code> Equals <code>bigInt /
-    // * 2<sup>scale</sup></code>.
-    // * @param bigInt The <code>bigInt</code> value parameter.
-    // * @param scale The scale of the constructed <code>SimpleBigDecimal</code>.
-    // */
-    constructor Create(const bigInt: TBigInteger; scale: Int32); overload;
-
-    function AdjustScale(newScale: Int32): TSimpleBigDecimal;
-
-    function Add(const b: TSimpleBigDecimal): TSimpleBigDecimal; overload;
-
-    function Add(const b: TBigInteger): TSimpleBigDecimal; overload;
-
-    function Negate(): TSimpleBigDecimal;
-
-    function Subtract(const b: TSimpleBigDecimal): TSimpleBigDecimal; overload;
-
-    function Subtract(const b: TBigInteger): TSimpleBigDecimal; overload;
-
-    function Multiply(const b: TSimpleBigDecimal): TSimpleBigDecimal; overload;
-
-    function Multiply(const b: TBigInteger): TSimpleBigDecimal; overload;
-
-    function Divide(const b: TSimpleBigDecimal): TSimpleBigDecimal; overload;
-
-    function Divide(const b: TBigInteger): TSimpleBigDecimal; overload;
-
-    function ShiftLeft(n: Int32): TSimpleBigDecimal;
-
-    function CompareTo(const val: TSimpleBigDecimal): Int32; overload;
-
-    function CompareTo(const val: TBigInteger): Int32; overload;
-
-    function Floor(): TBigInteger;
-
-    function Round(): TBigInteger;
-
-    function ToString(): String; inline;
-
-    function Equals(const other: TSimpleBigDecimal): Boolean; inline;
-
-    function GetHashCode(): Int32; inline;
-
-    property Int32Value: Int32 read GetInt32Value;
-
-    property Int64Value: Int64 read GetInt64Value;
-
-    property scale: Int32 read GetScale;
-
-    // /**
-    // * Returns a <code>SimpleBigDecimal</code> representing the same numerical
-    // * value as <code>value</code>.
-    // * @param value The value of the <code>SimpleBigDecimal</code> to be
-    // * created.
-    // * @param scale The scale of the <code>SimpleBigDecimal</code> to be
-    // * created.
-    // * @return The such created <code>SimpleBigDecimal</code>.
-    // */
-    class function GetInstance(const val: TBigInteger; scale: Int32)
-      : TSimpleBigDecimal; static; inline;
-
+    constructor Create(const ABigInt: TBigInteger; AScale: Int32);
+
+    class function GetInstance(const AVal: TBigInteger; AScale: Int32): TSimpleBigDecimal; static;
+
+    function AdjustScale(ANewScale: Int32): TSimpleBigDecimal;
+
+    function Add(const AB: TSimpleBigDecimal): TSimpleBigDecimal; overload;
+    function Add(const AB: TBigInteger): TSimpleBigDecimal; overload;
+    function Negate: TSimpleBigDecimal;
+    function Subtract(const AB: TSimpleBigDecimal): TSimpleBigDecimal; overload;
+    function Subtract(const AB: TBigInteger): TSimpleBigDecimal; overload;
+    function Multiply(const AB: TSimpleBigDecimal): TSimpleBigDecimal; overload;
+    function Multiply(const AB: TBigInteger): TSimpleBigDecimal; overload;
+    function Divide(const AB: TSimpleBigDecimal): TSimpleBigDecimal; overload;
+    function Divide(const AB: TBigInteger): TSimpleBigDecimal; overload;
+    function ShiftLeft(AN: Int32): TSimpleBigDecimal;
+
+    function CompareTo(const AVal: TSimpleBigDecimal): Int32; overload;
+    function CompareTo(const AVal: TBigInteger): Int32; overload;
+
+    function Floor: TBigInteger;
+    function Round: TBigInteger;
+
+    function GetBigInt: TBigInteger;
+    function GetIntValue: Int32;
+    function GetLongValue: Int64;
+    function GetScale: Int32;
+
+    function ToString: String;
+    function Equals(const AOther: TSimpleBigDecimal): Boolean;
+    function GetHashCode: Int32;
+
+    property BigInt: TBigInteger read GetBigInt;
+    property IntValue: Int32 read GetIntValue;
+    property LongValue: Int64 read GetLongValue;
+    property Scale: Int32 read GetScale;
   end;
 
 implementation
 
 { TSimpleBigDecimal }
 
-procedure TSimpleBigDecimal.CheckScale(const b: TSimpleBigDecimal);
+constructor TSimpleBigDecimal.Create(const ABigInt: TBigInteger; AScale: Int32);
 begin
-  if (Fscale <> b.Fscale) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SUnEqualScale);
-  end;
+  if AScale < 0 then
+    raise EArgumentCryptoLibException.Create(SScaleMayNotBeNegative);
+  FBigInt := ABigInt;
+  FScale := AScale;
 end;
 
-function TSimpleBigDecimal.Add(const b: TSimpleBigDecimal): TSimpleBigDecimal;
+class function TSimpleBigDecimal.GetInstance(const AVal: TBigInteger; AScale: Int32): TSimpleBigDecimal;
 begin
-  CheckScale(b);
-  Result := TSimpleBigDecimal.Create(FbigInt.Add(b.FbigInt), Fscale);
+  Result := TSimpleBigDecimal.Create(AVal.ShiftLeft(AScale), AScale);
 end;
 
-function TSimpleBigDecimal.Add(const b: TBigInteger): TSimpleBigDecimal;
+procedure TSimpleBigDecimal.CheckScale(const AB: TSimpleBigDecimal);
 begin
-  Result := TSimpleBigDecimal.Create(FbigInt.Add(b.ShiftLeft(Fscale)), Fscale);
-end;
-
-function TSimpleBigDecimal.AdjustScale(newScale: Int32): TSimpleBigDecimal;
-begin
-  if (newScale < 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SNegativeScale);
-  end;
-
-  if (newScale = Fscale) then
-  begin
-    Result := Self;
-    Exit;
-  end;
-
-  Result := TSimpleBigDecimal.Create(FbigInt.ShiftLeft(newScale - Fscale),
-    newScale);
+  if FScale <> AB.FScale then
+    raise EArgumentCryptoLibException.Create(SSameScaleRequired);
 end;
 
-function TSimpleBigDecimal.CompareTo(const val: TBigInteger): Int32;
+function TSimpleBigDecimal.AdjustScale(ANewScale: Int32): TSimpleBigDecimal;
 begin
-  Result := FbigInt.CompareTo(val.ShiftLeft(Fscale));
+  if ANewScale < 0 then
+    raise EArgumentCryptoLibException.Create(SScaleMayNotBeNegative);
+  if ANewScale = FScale then
+    Exit(Self);
+  Result := TSimpleBigDecimal.Create(FBigInt.ShiftLeft(ANewScale - FScale), ANewScale);
 end;
 
-function TSimpleBigDecimal.CompareTo(const val: TSimpleBigDecimal): Int32;
+function TSimpleBigDecimal.Add(const AB: TSimpleBigDecimal): TSimpleBigDecimal;
 begin
-  CheckScale(val);
-  Result := FbigInt.CompareTo(val.FbigInt);
+  CheckScale(AB);
+  Result := TSimpleBigDecimal.Create(FBigInt.Add(AB.FBigInt), FScale);
 end;
 
-// constructor TSimpleBigDecimal.Create(const limBigDec: TSimpleBigDecimal);
-// begin
-// FbigInt := limBigDec.FbigInt;
-// Fscale := limBigDec.Fscale;
-// end;
-
-constructor TSimpleBigDecimal.Create(const bigInt: TBigInteger; scale: Int32);
+function TSimpleBigDecimal.Add(const AB: TBigInteger): TSimpleBigDecimal;
 begin
-  if (scale < 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidScale);
-  end;
-
-  FbigInt := bigInt;
-  Fscale := scale;
+  Result := TSimpleBigDecimal.Create(FBigInt.Add(AB.ShiftLeft(FScale)), FScale);
 end;
 
-function TSimpleBigDecimal.Divide(const b: TSimpleBigDecimal)
-  : TSimpleBigDecimal;
-var
-  dividend: TBigInteger;
+function TSimpleBigDecimal.Negate: TSimpleBigDecimal;
 begin
-  CheckScale(b);
-  dividend := FbigInt.ShiftLeft(Fscale);
-  Result := TSimpleBigDecimal.Create(dividend.Divide(b.FbigInt), Fscale);
+  Result := TSimpleBigDecimal.Create(FBigInt.Negate(), FScale);
 end;
 
-function TSimpleBigDecimal.Divide(const b: TBigInteger): TSimpleBigDecimal;
+function TSimpleBigDecimal.Subtract(const AB: TSimpleBigDecimal): TSimpleBigDecimal;
 begin
-  Result := TSimpleBigDecimal.Create(FbigInt.Divide(b), Fscale);
+  Result := Add(AB.Negate());
 end;
 
-function TSimpleBigDecimal.Equals(const other: TSimpleBigDecimal): Boolean;
+function TSimpleBigDecimal.Subtract(const AB: TBigInteger): TSimpleBigDecimal;
 begin
-  Result := ((FbigInt.Equals(other.FbigInt)) and (Fscale = other.Fscale));
+  Result := TSimpleBigDecimal.Create(FBigInt.Subtract(AB.ShiftLeft(FScale)), FScale);
 end;
 
-function TSimpleBigDecimal.Floor: TBigInteger;
+function TSimpleBigDecimal.Multiply(const AB: TSimpleBigDecimal): TSimpleBigDecimal;
 begin
-  Result := FbigInt.ShiftRight(Fscale);
+  CheckScale(AB);
+  Result := TSimpleBigDecimal.Create(FBigInt.Multiply(AB.FBigInt), FScale + FScale);
 end;
 
-function TSimpleBigDecimal.GetHashCode: Int32;
+function TSimpleBigDecimal.Multiply(const AB: TBigInteger): TSimpleBigDecimal;
 begin
-  Result := FbigInt.GetHashCode() xor Fscale;
+  Result := TSimpleBigDecimal.Create(FBigInt.Multiply(AB), FScale);
 end;
 
-class function TSimpleBigDecimal.GetInstance(const val: TBigInteger;
-  scale: Int32): TSimpleBigDecimal;
+function TSimpleBigDecimal.Divide(const AB: TSimpleBigDecimal): TSimpleBigDecimal;
+var
+  LDividend: TBigInteger;
 begin
-  Result := TSimpleBigDecimal.Create(val.ShiftLeft(scale), scale);
+  CheckScale(AB);
+  LDividend := FBigInt.ShiftLeft(FScale);
+  Result := TSimpleBigDecimal.Create(LDividend.Divide(AB.FBigInt), FScale);
 end;
 
-function TSimpleBigDecimal.GetInt32Value: Int32;
+function TSimpleBigDecimal.Divide(const AB: TBigInteger): TSimpleBigDecimal;
 begin
-  Result := Floor().Int32Value;
+  Result := TSimpleBigDecimal.Create(FBigInt.Divide(AB), FScale);
 end;
 
-function TSimpleBigDecimal.GetInt64Value: Int64;
+function TSimpleBigDecimal.ShiftLeft(AN: Int32): TSimpleBigDecimal;
 begin
-  Result := Floor().Int64Value;
+  Result := TSimpleBigDecimal.Create(FBigInt.ShiftLeft(AN), FScale);
 end;
 
-function TSimpleBigDecimal.GetScale: Int32;
+function TSimpleBigDecimal.CompareTo(const AVal: TSimpleBigDecimal): Int32;
 begin
-  Result := Fscale;
+  CheckScale(AVal);
+  Result := FBigInt.CompareTo(AVal.FBigInt);
 end;
 
-{$IFNDEF _FIXINSIGHT_}
-
-function TSimpleBigDecimal.Multiply(const b: TSimpleBigDecimal)
-  : TSimpleBigDecimal;
+function TSimpleBigDecimal.CompareTo(const AVal: TBigInteger): Int32;
 begin
-  CheckScale(b);
-  Result := TSimpleBigDecimal.Create(FbigInt.Multiply(b.FbigInt),
-    Fscale + Fscale);
+  Result := FBigInt.CompareTo(AVal.ShiftLeft(FScale));
 end;
-{$ENDIF}
 
-function TSimpleBigDecimal.Multiply(const b: TBigInteger): TSimpleBigDecimal;
+function TSimpleBigDecimal.Floor: TBigInteger;
 begin
-  Result := TSimpleBigDecimal.Create(FbigInt.Multiply(b), Fscale);
+  Result := FBigInt.ShiftRight(FScale);
 end;
 
-function TSimpleBigDecimal.Negate: TSimpleBigDecimal;
+function TSimpleBigDecimal.Round: TBigInteger;
+var
+  LOneHalf: TSimpleBigDecimal;
 begin
-  Result := TSimpleBigDecimal.Create(FbigInt.Negate(), Fscale);
+  LOneHalf := TSimpleBigDecimal.Create(TBigInteger.One, 1);
+  Result := Add(LOneHalf.AdjustScale(FScale)).Floor();
 end;
 
-function TSimpleBigDecimal.Round: TBigInteger;
-var
-  oneHalf: TSimpleBigDecimal;
+function TSimpleBigDecimal.GetBigInt: TBigInteger;
 begin
-  oneHalf := TSimpleBigDecimal.Create(TBigInteger.One, 1);
-  Result := Add(oneHalf.AdjustScale(Fscale)).Floor();
+  Result := FBigInt;
 end;
 
-function TSimpleBigDecimal.ShiftLeft(n: Int32): TSimpleBigDecimal;
+function TSimpleBigDecimal.GetIntValue: Int32;
 begin
-  Result := TSimpleBigDecimal.Create(FbigInt.ShiftLeft(n), Fscale);
+  Result := Floor().Int32Value;
 end;
 
-function TSimpleBigDecimal.Subtract(const b: TSimpleBigDecimal)
-  : TSimpleBigDecimal;
+function TSimpleBigDecimal.GetLongValue: Int64;
 begin
-  Result := Add(b.Negate());
+  Result := Floor().Int64Value;
 end;
 
-function TSimpleBigDecimal.Subtract(const b: TBigInteger): TSimpleBigDecimal;
+function TSimpleBigDecimal.GetScale: Int32;
 begin
-  Result := TSimpleBigDecimal.Create(FbigInt.Subtract(b.ShiftLeft(Fscale)
-    ), Fscale);
+  Result := FScale;
 end;
 
 function TSimpleBigDecimal.ToString: String;
 var
-  floorBigInt, fract: TBigInteger;
-  leftOfPoint, fractStr, rightOfPoint: String;
-  fractCharArr: TCryptoLibCharArray;
-  fractLen, zeroes, I, j: Int32;
+  LFloorBigInt, LFract: TBigInteger;
+  LLeftOfPoint, LFractStr: String;
+  LRightOfPoint: String;
+  LFractLen, LZeroes, LI: Int32;
 begin
-  if (Fscale = 0) then
-  begin
-    Result := FbigInt.ToString();
-    Exit;
-  end;
+  if FScale = 0 then
+    Exit(FBigInt.ToString());
 
-  floorBigInt := Floor();
+  LFloorBigInt := Floor();
+  LFract := FBigInt.Subtract(LFloorBigInt.ShiftLeft(FScale));
+  if FBigInt.SignValue = -1 then
+    LFract := TBigInteger.One.ShiftLeft(FScale).Subtract(LFract);
 
-  fract := FbigInt.Subtract(floorBigInt.ShiftLeft(Fscale));
-  if (FbigInt.SignValue < 0) then
-  begin
-    fract := TBigInteger.One.ShiftLeft(Fscale).Subtract(fract);
-  end;
+  if (LFloorBigInt.SignValue = -1) and (not LFract.Equals(TBigInteger.Zero)) then
+    LFloorBigInt := LFloorBigInt.Add(TBigInteger.One);
 
-  if ((floorBigInt.SignValue = -1) and (not(fract.Equals(TBigInteger.Zero))))
-  then
-  begin
-    floorBigInt := floorBigInt.Add(TBigInteger.One);
-  end;
-  leftOfPoint := floorBigInt.ToString();
-
-  System.SetLength(fractCharArr, Fscale);
-  fractStr := fract.ToString(2);
-  fractLen := System.Length(fractStr);
-  zeroes := Fscale - fractLen;
-  for I := 0 to System.Pred(zeroes) do
-  begin
-    fractCharArr[I] := '0';
-  end;
-  for j := 0 to System.Pred(fractLen) do
-  begin
-    fractCharArr[zeroes + j] := fractStr[j + 1];
-  end;
+  LLeftOfPoint := LFloorBigInt.ToString();
+
+  LFractStr := LFract.ToString(2);
+  LFractLen := System.Length(LFractStr);
+  LZeroes := FScale - LFractLen;
 
-  System.SetString(rightOfPoint, PChar(@fractCharArr[0]),
-    System.Length(fractCharArr));
+  LRightOfPoint := '';
+  for LI := 1 to LZeroes do
+    LRightOfPoint := LRightOfPoint + '0';
+  LRightOfPoint := LRightOfPoint + LFractStr;
 
-  Result := leftOfPoint + '.' + rightOfPoint;
+  Result := LLeftOfPoint + '.' + LRightOfPoint;
+end;
+
+function TSimpleBigDecimal.Equals(const AOther: TSimpleBigDecimal): Boolean;
+begin
+  Result := FBigInt.Equals(AOther.BigInt) and (FScale = AOther.Scale);
+end;
+
+function TSimpleBigDecimal.GetHashCode: Int32;
+begin
+  Result := FBigInt.GetHashCode() xor FScale;
 end;
 
 end.

+ 618 - 911
CryptoLib/src/Math/EC/Abc/ClpTnaf.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpTnaf;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -23,1128 +16,842 @@ interface
 
 uses
   SysUtils,
+  ClpBigInteger,
   ClpIZTauElement,
   ClpZTauElement,
-  ClpIECC,
-  ClpCryptoLibTypes,
-  ClpBigInteger,
-  ClpSimpleBigDecimal;
+  ClpSimpleBigDecimal,
+  ClpIECCore,
+  ClpIECFieldElement,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidMU = 'mu must be 1 or -1';
-  SDifferentScales = 'lambda0 and lambda1 do not have same scale';
+  SMuMustBe1OrMinus1 = 'mu must be 1 or -1';
   SNoKoblitzCurve = 'No Koblitz curve (ABC), TNAF multiplication not possible';
-  SNotKoblitzCurve = 'si is defined for Koblitz curves only';
-  SInvalidCoFactor = 'h (Cofactor) must be 2 or 4';
+  SSiDefinedForKoblitzOnly = 'si is defined for Koblitz curves only';
+  SCofactorMustBe2Or4 = 'h (Cofactor) must be 2 or 4';
+  SOnlyAbstractF2mPointAllowed = 'Only AbstractF2mPoint can be used in WTauNafMultiplier';
 
 type
-  /// **
-  // * Class holding methods for point multiplication based on the window
-  // * &#964;-adic nonadjacent form (WTNAF). The algorithms are based on the
-  // * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
-  // * by Jerome A. Solinas. The paper first appeared in the Proceedings of
-  // * Crypto 1997.
-  // */
   TTnaf = class sealed(TObject)
-
   strict private
-  class var
+    class var
+      FMinusOne: TBigInteger;
+      FMinusTwo: TBigInteger;
+      FMinusThree: TBigInteger;
+      FFour: TBigInteger;
 
-    FMinusOne, FMinusTwo, FMinusThree, FFour: TBigInteger;
-    FAlpha0, FAlpha1: TCryptoLibGenericArray<IZTauElement>;
-    FAlpha0Tnaf, FAlpha1Tnaf: TCryptoLibMatrixShortIntArray;
+    class function GetShiftsForCofactor(const AH: TBigInteger): Int32; static;
+  public
+    const
+      Width: ShortInt = 4;
+      PRECOMP_NAME = 'bc_tnaf_partmod';
 
-    class function GetAlpha0: TCryptoLibGenericArray<IZTauElement>;
-      static; inline;
-    class function GetAlpha0Tnaf: TCryptoLibMatrixShortIntArray; static; inline;
-    class function GetAlpha1Tnaf: TCryptoLibMatrixShortIntArray; static; inline;
-    class function GetAlpha1: TCryptoLibGenericArray<IZTauElement>;
-      static; inline;
+    class var
+      Alpha0: TCryptoLibGenericArray<IZTauElement>;
+      Alpha0Tnaf: TCryptoLibMatrixShortIntArray;
+      Alpha1: TCryptoLibGenericArray<IZTauElement>;
+      Alpha1Tnaf: TCryptoLibMatrixShortIntArray;
 
-    class function GetShiftsForCofactor(const h: TBigInteger): Int32;
-      static; inline;
+    class constructor Create;
 
-    class procedure Boot(); static;
-    class constructor Tnaf();
+    class function Norm(AMu: ShortInt; const ALambda: IZTauElement): TBigInteger; overload; static;
+    class function Norm(AMu: ShortInt; const AU, AV: TSimpleBigDecimal): TSimpleBigDecimal; overload; static;
 
-  public
+    class function Round(const ALambda0, ALambda1: TSimpleBigDecimal;
+      AMu: ShortInt): IZTauElement; static;
 
-  // /**
-  // * The window width of WTNAF. The standard value of 4 is slightly less
-  // * than optimal for running time, but keeps space requirements for
-  // * precomputation low. For typical curves, a value of 5 or 6 results in
-  // * a better running time. When changing this value, the
-  // * <code>&#945;<sub>u</sub></code>'s must be computed differently, see
-  // * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
-  // * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
-  // * p. 121-122
-  // */
-    const
-    Width = ShortInt(4);
-
-    // /**
-    // * 2<sup>4</sup>
-    // */
-    Pow2Width = ShortInt(16);
-    // /**
-    // * Computes the norm of an element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code>.
-    // * @param mu The parameter <code>&#956;</code> of the elliptic curve.
-    // * @param lambda The element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code>.
-    // * @return The norm of <code>&#955;</code>.
-    // */
-    class function Norm(mu: ShortInt; const lambda: IZTauElement): TBigInteger;
-      overload; static; inline;
-    // /**
-    // * Computes the norm of an element <code>&#955;</code> of
-    // * <code><b>R</b>[&#964;]</code>, where <code>&#955; = u + v&#964;</code>
-    // * and <code>u</code> and <code>u</code> are real numbers (elements of
-    // * <code><b>R</b></code>).
-    // * @param mu The parameter <code>&#956;</code> of the elliptic curve.
-    // * @param u The real part of the element <code>&#955;</code> of
-    // * <code><b>R</b>[&#964;]</code>.
-    // * @param v The <code>&#964;</code>-adic part of the element
-    // * <code>&#955;</code> of <code><b>R</b>[&#964;]</code>.
-    // * @return The norm of <code>&#955;</code>.
-    // */
-    class function Norm(mu: ShortInt; const u, v: TSimpleBigDecimal)
-      : TSimpleBigDecimal; overload; static; inline;
-    // /**
-    // * Rounds an element <code>&#955;</code> of <code><b>R</b>[&#964;]</code>
-    // * to an element of <code><b>Z</b>[&#964;]</code>, such that their difference
-    // * has minimal norm. <code>&#955;</code> is given as
-    // * <code>&#955; = &#955;<sub>0</sub> + &#955;<sub>1</sub>&#964;</code>.
-    // * @param lambda0 The component <code>&#955;<sub>0</sub></code>.
-    // * @param lambda1 The component <code>&#955;<sub>1</sub></code>.
-    // * @param mu The parameter <code>&#956;</code> of the elliptic curve. Must
-    // * equal 1 or -1.
-    // * @return The rounded element of <code><b>Z</b>[&#964;]</code>.
-    // * @throws ArgumentException if <code>lambda0</code> and
-    // * <code>lambda1</code> do not have same scale.
-    // */
-    class function Round(const lambda0, lambda1: TSimpleBigDecimal;
-      mu: ShortInt): IZTauElement; static;
-    // /**
-    // * Approximate division by <code>n</code>. For an integer
-    // * <code>k</code>, the value <code>&#955; = s k / n</code> is
-    // * computed to <code>c</code> bits of accuracy.
-    // * @param k The parameter <code>k</code>.
-    // * @param s The curve parameter <code>s<sub>0</sub></code> or
-    // * <code>s<sub>1</sub></code>.
-    // * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
-    // * @param a The parameter <code>a</code> of the elliptic curve.
-    // * @param m The bit length of the finite field
-    // * <code><b>F</b><sub>m</sub></code>.
-    // * @param c The number of bits of accuracy, i.e. the scale of the returned
-    // * <code>SimpleBigDecimal</code>.
-    // * @return The value <code>&#955; = s k / n</code> computed to
-    // * <code>c</code> bits of accuracy.
-    // */
-    class function ApproximateDivisionByN(const k, s, vm: TBigInteger;
-      a: ShortInt; m, c: Int32): TSimpleBigDecimal; static; inline;
-    // /**
-    // * Computes the <code>&#964;</code>-adic NAF (non-adjacent form) of an
-    // * element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>.
-    // * @param mu The parameter <code>&#956;</code> of the elliptic curve.
-    // * @param lambda The element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code>.
-    // * @return The <code>&#964;</code>-adic NAF of <code>&#955;</code>.
-    // */
-    class function TauAdicNaf(mu: ShortInt; const lambda: IZTauElement)
-      : TCryptoLibShortIntArray; static;
-    // /**
-    // * Applies the operation <code>&#964;()</code> to an
-    // * <code>AbstractF2mPoint</code>.
-    // * @param p The AbstractF2mPoint to which <code>&#964;()</code> is applied.
-    // * @return <code>&#964;(p)</code>
-    // */
-    class function Tau(const p: IAbstractF2mPoint): IAbstractF2mPoint;
-      static; inline;
-    // /**
-    // * Returns the parameter <code>&#956;</code> of the elliptic curve.
-    // * @param curve The elliptic curve from which to obtain <code>&#956;</code>.
-    // * The curve must be a Koblitz curve, i.e. <code>a</code> Equals
-    // * <code>0</code> or <code>1</code> and <code>b</code> Equals
-    // * <code>1</code>.
-    // * @return <code>&#956;</code> of the elliptic curve.
-    // * @throws ArgumentException if the given ECCurve is not a Koblitz
-    // * curve.
-    // */
-    class function GetMu(const curve: IAbstractF2mCurve): ShortInt; overload;
-      static; inline;
-
-    class function GetMu(const curveA: IECFieldElement): ShortInt; overload;
-      static; inline;
-
-    class function GetMu(curveA: Int32): ShortInt; overload; static; inline;
-    // /**
-    // * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
-    // * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
-    // * <code>V<sub>k</sub></code>.
-    // * @param mu The parameter <code>&#956;</code> of the elliptic curve.
-    // * @param k The index of the second element of the Lucas Sequence to be
-    // * returned.
-    // * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
-    // * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
-    // * <code>U<sub>k</sub></code>.
-    // * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
-    // * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
-    // * and <code>V<sub>k</sub></code>.
-    // */
-    class function GetLucas(mu: ShortInt; k: Int32; doV: Boolean)
-      : TCryptoLibGenericArray<TBigInteger>; static;
-    // /**
-    // * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
-    // * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
-    // * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code>
-    // * @param mu The parameter <code>&#956;</code> of the elliptic curve.
-    // * @param w The window width of the WTNAF.
-    // * @return the auxiliary value <code>t<sub>w</sub></code>
-    // */
-    class function GetTw(mu: ShortInt; w: Int32): TBigInteger; static;
-    // /**
-    // * Computes the auxiliary values <code>s<sub>0</sub></code> and
-    // * <code>s<sub>1</sub></code> used for partial modular reduction.
-    // * @param curve The elliptic curve for which to compute
-    // * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
-    // * @throws ArgumentException if <code>curve</code> is not a
-    // * Koblitz curve (Anomalous Binary Curve, ABC).
-    // */
-    class function GetSi(const curve: IAbstractF2mCurve)
-      : TCryptoLibGenericArray<TBigInteger>; overload; static;
-
-    class function GetSi(fieldSize, curveA: Int32; const cofactor: TBigInteger)
-      : TCryptoLibGenericArray<TBigInteger>; overload; static;
-
-    // /**
-    // * Partial modular reduction modulo
-    // * <code>(&#964;<sup>m</sup> - 1)/(&#964; - 1)</code>.
-    // * @param k The integer to be reduced.
-    // * @param m The bitlength of the underlying finite field.
-    // * @param a The parameter <code>a</code> of the elliptic curve.
-    // * @param s The auxiliary values <code>s<sub>0</sub></code> and
-    // * <code>s<sub>1</sub></code>.
-    // * @param mu The parameter &#956; of the elliptic curve.
-    // * @param c The precision (number of bits of accuracy) of the partial
-    // * modular reduction.
-    // * @return <code>&#961; := k partmod (&#964;<sup>m</sup> - 1)/(&#964; - 1)</code>
-    // */
-    class function PartModReduction(const k: TBigInteger; m: Int32; a: ShortInt;
-      const s: TCryptoLibGenericArray<TBigInteger>; mu, c: ShortInt)
-      : IZTauElement; static;
-
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
-    // * using the <code>&#964;</code>-adic NAF (TNAF) method.
-    // * @param p The AbstractF2mPoint to Multiply.
-    // * @param lambda The element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code>.
-    // * @return <code>&#955; * p</code>
-    // */
-    class function MultiplyTnaf(const p: IAbstractF2mPoint;
-      const lambda: IZTauElement): IAbstractF2mPoint; static; inline;
-
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
-    // * using the <code>&#964;</code>-adic NAF (TNAF) method, given the TNAF
-    // * of <code>&#955;</code>.
-    // * @param p The AbstractF2mPoint to Multiply.
-    // * @param u The the TNAF of <code>&#955;</code>..
-    // * @return <code>&#955; * p</code>
-    // */
-    class function MultiplyFromTnaf(const p: IAbstractF2mPoint;
-      const u: TCryptoLibShortIntArray): IAbstractF2mPoint; static;
-
-    // /**
-    // * Computes the <code>[&#964;]</code>-adic window NAF of an element
-    // * <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>.
-    // * @param mu The parameter &#956; of the elliptic curve.
-    // * @param lambda The element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code> of which to compute the
-    // * <code>[&#964;]</code>-adic NAF.
-    // * @param width The window width of the resulting WNAF.
-    // * @param pow2w 2<sup>width</sup>.
-    // * @param tw The auxiliary value <code>t<sub>w</sub></code>.
-    // * @param alpha The <code>&#945;<sub>u</sub></code>'s for the window width.
-    // * @return The <code>[&#964;]</code>-adic window NAF of
-    // * <code>&#955;</code>.
-    // */
-    class function TauAdicWNaf(mu: ShortInt; const lambda: IZTauElement;
-      Width: ShortInt; const pow2w, tw: TBigInteger;
-      const alpha: TCryptoLibGenericArray<IZTauElement>)
-      : TCryptoLibShortIntArray; static;
-
-    // /**
-    // * Does the precomputation for WTNAF multiplication.
-    // * @param p The <code>ECPoint</code> for which to do the precomputation.
-    // * @param a The parameter <code>a</code> of the elliptic curve.
-    // * @return The precomputation array for <code>p</code>.
-    // */
-    class function GetPreComp(const p: IAbstractF2mPoint; a: ShortInt)
-      : TCryptoLibGenericArray<IAbstractF2mPoint>; static;
-
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by a <code>BigInteger</code> using the reduced <code>&#964;</code>-adic
-    // * NAF (RTNAF) method.
-    // * @param p The AbstractF2mPoint to Multiply.
-    // * @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
-    // * @return <code>k * p</code>
-    // */
-    class function MultiplyRTnaf(const p: IAbstractF2mPoint;
-      const k: TBigInteger): IAbstractF2mPoint; static; inline;
-
-    // /**
-    // * The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
-    // * of <code>ZTauElement</code>s.
-    // */
-    class property Alpha0: TCryptoLibGenericArray<IZTauElement> read GetAlpha0;
-    // /**
-    // * The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
-    // * of <code>ZTauElement</code>s.
-    // */
-    class property Alpha1: TCryptoLibGenericArray<IZTauElement> read GetAlpha1;
-    // /**
-    // * The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
-    // * of TNAFs.
-    // */
-    class property Alpha0Tnaf: TCryptoLibMatrixShortIntArray read GetAlpha0Tnaf;
-
-    // /**
-    // * The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
-    // * of TNAFs.
-    // */
-    class property Alpha1Tnaf: TCryptoLibMatrixShortIntArray read GetAlpha1Tnaf;
+    class function ApproximateDivisionByN(const AK, AS_, AVm: TBigInteger;
+      AA: ShortInt; AM, AC: Int32): TSimpleBigDecimal; static;
 
-  end;
+    class function TauAdicNaf(AMu: ShortInt; const ALambda: IZTauElement): TCryptoLibShortIntArray; static;
 
-implementation
+    class function Tau(const AP: IAbstractF2mPoint): IAbstractF2mPoint; static;
 
-{ TTnaf }
+    class function GetMu(const ACurve: IAbstractF2mCurve): ShortInt; overload; static;
+    class function GetMu(const ACurveA: IECFieldElement): ShortInt; overload; static;
+    class function GetMu(ACurveA: Int32): ShortInt; overload; static;
 
-class function TTnaf.ApproximateDivisionByN(const k, s, vm: TBigInteger;
-  a: ShortInt; m, c: Int32): TSimpleBigDecimal;
-var
-  _k: Int32;
-  ns, gs, hs, js, gsPlusJs, ls: TBigInteger;
-begin
-  _k := ((m + 5) shr 1) + c;
-  ns := k.ShiftRight(m - _k - 2 + a);
+    class function GetLucas(AMu: ShortInt; AK: Int32; ADoV: Boolean): TCryptoLibGenericArray<TBigInteger>; static;
 
-  gs := s.Multiply(ns);
+    class function GetTw(AMu: ShortInt; AW: Int32): TBigInteger; static;
 
-  hs := gs.ShiftRight(m);
+    class function GetSi(const ACurve: IAbstractF2mCurve): TCryptoLibGenericArray<TBigInteger>; overload; static;
+    class function GetSi(AFieldSize, ACurveA: Int32; const ACofactor: TBigInteger): TCryptoLibGenericArray<TBigInteger>; overload; static;
 
-  js := vm.Multiply(hs);
+    class function PartModReduction(const ACurve: IAbstractF2mCurve;
+      const AK: TBigInteger; AA, AMu, AC: ShortInt): IZTauElement; static;
 
-  gsPlusJs := gs.Add(js);
-  ls := gsPlusJs.ShiftRight(_k - c);
-  if (gsPlusJs.TestBit(_k - c - 1)) then
-  begin
-    // round up
-    ls := ls.Add(TBigInteger.One);
+    class function MultiplyRTnaf(const AP: IAbstractF2mPoint;
+      const AK: TBigInteger): IAbstractF2mPoint; static;
+
+    class function MultiplyTnaf(const AP: IAbstractF2mPoint;
+      const ALambda: IZTauElement): IAbstractF2mPoint; static;
+
+    class function MultiplyFromTnaf(const AP, APNeg: IAbstractF2mPoint;
+      const AU: TCryptoLibShortIntArray): IAbstractF2mPoint; static;
+
+    class function TauAdicWNaf(AMu: ShortInt; const ALambda: IZTauElement;
+      AWidth, ATw: Int32; const AAlpha: TCryptoLibGenericArray<IZTauElement>): TCryptoLibShortIntArray; static;
+
+    class function GetPreComp(const AP: IAbstractF2mPoint;
+      AA: ShortInt): TCryptoLibGenericArray<IAbstractF2mPoint>; static;
   end;
 
-  Result := TSimpleBigDecimal.Create(ls, c);
-end;
+implementation
 
-class procedure TTnaf.Boot;
-begin
+uses
+  ClpECPoint,
+  ClpArrayUtilities,
+  ClpBitOperations;
 
-  FMinusOne := TBigInteger.One.Negate();
-  FMinusTwo := TBigInteger.Two.Negate();
-  FMinusThree := TBigInteger.Three.Negate();
-  FFour := TBigInteger.ValueOf(4);
-  FAlpha0 := TCryptoLibGenericArray<IZTauElement>.Create(Nil,
-    TZTauElement.Create(TBigInteger.One, TBigInteger.Zero), Nil,
-    TZTauElement.Create(FMinusThree, FMinusOne), Nil,
-    TZTauElement.Create(FMinusOne, FMinusOne), Nil,
-    TZTauElement.Create(TBigInteger.One, FMinusOne), Nil);
-
-  FAlpha1 := TCryptoLibGenericArray<IZTauElement>.Create(Nil,
-    TZTauElement.Create(TBigInteger.One, TBigInteger.Zero), Nil,
-    TZTauElement.Create(FMinusThree, TBigInteger.One), Nil,
-    TZTauElement.Create(FMinusOne, TBigInteger.One), Nil,
-    TZTauElement.Create(TBigInteger.One, TBigInteger.One), Nil);
-
-  FAlpha0Tnaf := TCryptoLibMatrixShortIntArray.Create(Nil,
-    TCryptoLibShortIntArray.Create(1), Nil, TCryptoLibShortIntArray.Create(-1,
-    0, 1), Nil, TCryptoLibShortIntArray.Create(1, 0, 1), Nil,
-    TCryptoLibShortIntArray.Create(-1, 0, 0, 1));
-
-  FAlpha1Tnaf := TCryptoLibMatrixShortIntArray.Create(Nil,
-    TCryptoLibShortIntArray.Create(1), Nil, TCryptoLibShortIntArray.Create(-1,
-    0, 1), Nil, TCryptoLibShortIntArray.Create(1, 0, 1), Nil,
-    TCryptoLibShortIntArray.Create(-1, 0, 0, -1));
+type
+  IPartModPreCompInfo = interface(IPreCompInfo)
+    ['{B1C2D3E4-F5A6-7890-BCDE-F23456789012}']
+    function GetLucas: TBigInteger;
+    function GetS0: TBigInteger;
+    function GetS1: TBigInteger;
+    property Lucas: TBigInteger read GetLucas;
+    property S0: TBigInteger read GetS0;
+    property S1: TBigInteger read GetS1;
+  end;
+
+  TPartModPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo, IPartModPreCompInfo)
+  strict private
+    FLucas: TBigInteger;
+    FS0: TBigInteger;
+    FS1: TBigInteger;
+    function GetLucas: TBigInteger;
+    function GetS0: TBigInteger;
+    function GetS1: TBigInteger;
+  public
+    constructor Create(const ALucas, AS0, AS1: TBigInteger);
+  end;
+
+  TPartModPreCompCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FCurve: IAbstractF2mCurve;
+    FMu: ShortInt;
+    FDoV: Boolean;
+  public
+    constructor Create(const ACurve: IAbstractF2mCurve; AMu: ShortInt; ADoV: Boolean);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+{ TPartModPreCompInfo }
+
+constructor TPartModPreCompInfo.Create(const ALucas, AS0, AS1: TBigInteger);
+begin
+  inherited Create;
+  FLucas := ALucas;
+  FS0 := AS0;
+  FS1 := AS1;
 end;
 
-class function TTnaf.GetAlpha0: TCryptoLibGenericArray<IZTauElement>;
+function TPartModPreCompInfo.GetLucas: TBigInteger;
 begin
-  Result := FAlpha0;
+  Result := FLucas;
 end;
 
-class function TTnaf.GetAlpha0Tnaf: TCryptoLibMatrixShortIntArray;
+function TPartModPreCompInfo.GetS0: TBigInteger;
 begin
-  Result := FAlpha0Tnaf;
+  Result := FS0;
 end;
 
-class function TTnaf.GetAlpha1Tnaf: TCryptoLibMatrixShortIntArray;
+function TPartModPreCompInfo.GetS1: TBigInteger;
 begin
-  Result := FAlpha1Tnaf;
+  Result := FS1;
 end;
 
-class function TTnaf.GetAlpha1: TCryptoLibGenericArray<IZTauElement>;
+{ TPartModPreCompCallback }
+
+constructor TPartModPreCompCallback.Create(const ACurve: IAbstractF2mCurve;
+  AMu: ShortInt; ADoV: Boolean);
 begin
-  Result := FAlpha1;
+  inherited Create;
+  FCurve := ACurve;
+  FMu := AMu;
+  FDoV := ADoV;
 end;
 
-class function TTnaf.GetLucas(mu: ShortInt; k: Int32; doV: Boolean)
-  : TCryptoLibGenericArray<TBigInteger>;
+function TPartModPreCompCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
 var
-  u0, u1, u2, s: TBigInteger;
-  i: Int32;
+  LPartMod: IPartModPreCompInfo;
+  LLucas: TBigInteger;
+  LSi: TCryptoLibGenericArray<TBigInteger>;
 begin
+  if Supports(AExisting, IPartModPreCompInfo, LPartMod) then
+    Exit(LPartMod);
 
-  if (not((mu = 1) or (mu = -1))) then
+  if FCurve.IsKoblitz then
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidMU);
-  end;
-
-  if (doV) then
-  begin
-    u0 := TBigInteger.Two;
-    u1 := TBigInteger.ValueOf(mu);
+    // Koblitz path -- Jerome A. Solinas, (21)
+    LLucas := TBigInteger.One.ShiftLeft(FCurve.FieldSize)
+      .Add(TBigInteger.One)
+      .Subtract(FCurve.Order.Multiply(FCurve.Cofactor));
   end
   else
   begin
-    u0 := TBigInteger.Zero;
-    u1 := TBigInteger.One;
-  end;
-
-  i := 1;
-
-  while i < k do
-  begin
-    // u2 = mu*u1 - 2*u0;
-    s := TBigInteger.GetDefault;
-    if (mu = 1) then
-    begin
-      s := u1;
-    end
-    else
-    begin
-      // mu == -1
-      s := u1.Negate();
-    end;
-
-    u2 := s.Subtract(u0.ShiftLeft(1));
-    u0 := u1;
-    u1 := u2;
-    // System.out.println(i + ": " + u2);
-    // System.out.println();
-    System.Inc(i);
+    LLucas := TTnaf.GetLucas(FMu, FCurve.FieldSize, FDoV)[1];
   end;
 
-  Result := TCryptoLibGenericArray<TBigInteger>.Create(u0, u1);
+  LSi := TTnaf.GetSi(FCurve);
 
+  Result := TPartModPreCompInfo.Create(LLucas, LSi[0], LSi[1]);
 end;
 
-class function TTnaf.GetMu(curveA: Int32): ShortInt;
+{ TTnaf }
+
+class constructor TTnaf.Create;
 begin
-  if (curveA = 0) then
-  begin
-    Result := ShortInt(-1);
-  end
-  else
-  begin
-    Result := ShortInt(1);
-  end;
+  FMinusOne := TBigInteger.One.Negate();
+  FMinusTwo := TBigInteger.Two.Negate();
+  FMinusThree := TBigInteger.Three.Negate();
+  FFour := TBigInteger.Four;
+
+  Alpha0 := TCryptoLibGenericArray<IZTauElement>.Create(
+    nil, TZTauElement.Create(TBigInteger.One, TBigInteger.Zero) as IZTauElement,
+    nil, TZTauElement.Create(FMinusThree, FMinusOne) as IZTauElement,
+    nil, TZTauElement.Create(FMinusOne, FMinusOne) as IZTauElement,
+    nil, TZTauElement.Create(TBigInteger.One, FMinusOne) as IZTauElement,
+    nil, TZTauElement.Create(FMinusOne, TBigInteger.One) as IZTauElement,
+    nil, TZTauElement.Create(TBigInteger.One, TBigInteger.One) as IZTauElement,
+    nil, TZTauElement.Create(TBigInteger.Three, TBigInteger.One) as IZTauElement,
+    nil, TZTauElement.Create(FMinusOne, TBigInteger.Zero) as IZTauElement
+  );
+
+  Alpha0Tnaf := TCryptoLibMatrixShortIntArray.Create(
+    nil, TCryptoLibShortIntArray.Create(1),
+    nil, TCryptoLibShortIntArray.Create(-1, 0, 1),
+    nil, TCryptoLibShortIntArray.Create(1, 0, 1),
+    nil, TCryptoLibShortIntArray.Create(-1, 0, 0, 1)
+  );
+
+  Alpha1 := TCryptoLibGenericArray<IZTauElement>.Create(
+    nil, TZTauElement.Create(TBigInteger.One, TBigInteger.Zero) as IZTauElement,
+    nil, TZTauElement.Create(FMinusThree, TBigInteger.One) as IZTauElement,
+    nil, TZTauElement.Create(FMinusOne, TBigInteger.One) as IZTauElement,
+    nil, TZTauElement.Create(TBigInteger.One, TBigInteger.One) as IZTauElement,
+    nil, TZTauElement.Create(FMinusOne, FMinusOne) as IZTauElement,
+    nil, TZTauElement.Create(TBigInteger.One, FMinusOne) as IZTauElement,
+    nil, TZTauElement.Create(TBigInteger.Three, FMinusOne) as IZTauElement,
+    nil, TZTauElement.Create(FMinusOne, TBigInteger.Zero) as IZTauElement
+  );
+
+  Alpha1Tnaf := TCryptoLibMatrixShortIntArray.Create(
+    nil, TCryptoLibShortIntArray.Create(1),
+    nil, TCryptoLibShortIntArray.Create(-1, 0, 1),
+    nil, TCryptoLibShortIntArray.Create(1, 0, 1),
+    nil, TCryptoLibShortIntArray.Create(-1, 0, 0, -1)
+  );
 end;
 
-class function TTnaf.GetMu(const curve: IAbstractF2mCurve): ShortInt;
+class function TTnaf.Norm(AMu: ShortInt; const ALambda: IZTauElement): TBigInteger;
 var
-  a: TBigInteger;
-  mu: ShortInt;
+  LS1: TBigInteger;
 begin
-  a := curve.a.ToBigInteger();
+  // s1 = u^2
+  LS1 := ALambda.U.Square();
 
-  if (a.SignValue = 0) then
+  if AMu = 1 then
   begin
-    mu := -1;
+    Result := ALambda.V.ShiftLeft(1).Add(ALambda.U).Multiply(ALambda.V).Add(LS1);
   end
-  else if (a.Equals(TBigInteger.One)) then
+  else if AMu = -1 then
   begin
-    mu := 1;
+    Result := ALambda.V.ShiftLeft(1).Subtract(ALambda.U).Multiply(ALambda.V).Add(LS1);
   end
   else
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SNoKoblitzCurve);
-  end;
-  Result := mu;
+    raise EArgumentCryptoLibException.Create(SMuMustBe1OrMinus1);
 end;
 
-class function TTnaf.GetMu(const curveA: IECFieldElement): ShortInt;
+class function TTnaf.Norm(AMu: ShortInt; const AU, AV: TSimpleBigDecimal): TSimpleBigDecimal;
+var
+  LS1, LS2, LS3, LNorm: TSimpleBigDecimal;
 begin
-  if curveA.IsZero then
+  // s1 = u^2
+  LS1 := AU.Multiply(AU);
+  // s2 = u * v
+  LS2 := AU.Multiply(AV);
+  // s3 = 2 * v^2
+  LS3 := AV.Multiply(AV).ShiftLeft(1);
+
+  if AMu = 1 then
   begin
-    Result := ShortInt(-1);
+    LNorm := LS1.Add(LS2).Add(LS3);
   end
-  else
+  else if AMu = -1 then
   begin
-    Result := ShortInt(1);
-  end;
+    LNorm := LS1.Subtract(LS2).Add(LS3);
+  end
+  else
+    raise EArgumentCryptoLibException.Create(SMuMustBe1OrMinus1);
+
+  Result := LNorm;
 end;
 
-class function TTnaf.GetPreComp(const p: IAbstractF2mPoint; a: ShortInt)
-  : TCryptoLibGenericArray<IAbstractF2mPoint>;
+class function TTnaf.Round(const ALambda0, ALambda1: TSimpleBigDecimal;
+  AMu: ShortInt): IZTauElement;
 var
-  alphaTnaf: TCryptoLibMatrixShortIntArray;
-  pu: TCryptoLibGenericArray<IAbstractF2mPoint>;
-  precompLen, i: UInt32;
-  ecPoints: TCryptoLibGenericArray<IECPoint>;
-  j: Int32;
+  LScale: Int32;
+  LF0, LF1: TBigInteger;
+  LEta0, LEta1, LEta: TSimpleBigDecimal;
+  LThreeEta1, LFourEta1, LCheck1, LCheck2: TSimpleBigDecimal;
+  LH0, LH1: ShortInt;
+  LQ0, LQ1: TBigInteger;
 begin
+  LScale := ALambda0.Scale;
+  if ALambda1.Scale <> LScale then
+    raise EArgumentCryptoLibException.Create('lambda0 and lambda1 do not have same scale');
+
+  if not ((AMu = 1) or (AMu = -1)) then
+    raise EArgumentCryptoLibException.Create(SMuMustBe1OrMinus1);
 
-  if (a = 0) then
+  LF0 := ALambda0.Round();
+  LF1 := ALambda1.Round();
+
+  LEta0 := ALambda0.Subtract(LF0);
+  LEta1 := ALambda1.Subtract(LF1);
+
+  // eta = 2*eta0 + mu*eta1
+  LEta := LEta0.Add(LEta0);
+  if AMu = 1 then
+    LEta := LEta.Add(LEta1)
+  else
+    LEta := LEta.Subtract(LEta1);
+
+  // check1 = eta0 - 3*mu*eta1
+  // check2 = eta0 + 4*mu*eta1
+  LThreeEta1 := LEta1.Add(LEta1).Add(LEta1);
+  LFourEta1 := LThreeEta1.Add(LEta1);
+  if AMu = 1 then
   begin
-    alphaTnaf := TTnaf.Alpha0Tnaf;
+    LCheck1 := LEta0.Subtract(LThreeEta1);
+    LCheck2 := LEta0.Add(LFourEta1);
   end
   else
   begin
-    alphaTnaf := TTnaf.Alpha1Tnaf;
+    LCheck1 := LEta0.Add(LThreeEta1);
+    LCheck2 := LEta0.Subtract(LFourEta1);
   end;
 
-  System.SetLength(pu, UInt32(System.Length(alphaTnaf) + 1) shr 1);
-
-  pu[0] := p.Clone() as IAbstractF2mPoint;
+  LH0 := 0;
+  LH1 := 0;
 
-  precompLen := UInt32(System.Length(alphaTnaf));
-
-  i := 3;
-  while i < precompLen do
+  // if eta >= 1
+  if LEta.CompareTo(TBigInteger.One) >= 0 then
   begin
-    pu[i shr 1] := TTnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
-    System.Inc(i, 2);
-  end;
-
-  // Since Generic Covariance and Contravariance are not supported in Delphi,
-  // We have to manually loop through the array and convert its content to our desired type using an "as, Supports or Cast".
-  System.SetLength(ecPoints, System.Length(pu));
-  for j := System.Low(pu) to System.High(pu) do
+    if LCheck1.CompareTo(FMinusOne) < 0 then
+      LH1 := AMu
+    else
+      LH0 := 1;
+  end
+  else
   begin
-    ecPoints[j] := pu[j] as IECPoint;
+    // eta < 1
+    if LCheck2.CompareTo(TBigInteger.Two) >= 0 then
+      LH1 := AMu;
   end;
 
-  p.curve.NormalizeAll(ecPoints);
-  // after normalizing, convert back
-  for j := System.Low(ecPoints) to System.High(ecPoints) do
+  // if eta < -1
+  if LEta.CompareTo(FMinusOne) < 0 then
   begin
-    pu[j] := ecPoints[j] as IAbstractF2mPoint;
+    if LCheck1.CompareTo(TBigInteger.One) >= 0 then
+      LH1 := ShortInt(-AMu)
+    else
+      LH0 := -1;
+  end
+  else
+  begin
+    // eta >= -1
+    if LCheck2.CompareTo(FMinusTwo) < 0 then
+      LH1 := ShortInt(-AMu);
   end;
 
-  Result := pu;
+  LQ0 := LF0.Add(TBigInteger.ValueOf(LH0));
+  LQ1 := LF1.Add(TBigInteger.ValueOf(LH1));
+  Result := TZTauElement.Create(LQ0, LQ1) as IZTauElement;
 end;
 
-class function TTnaf.GetShiftsForCofactor(const h: TBigInteger): Int32;
+class function TTnaf.ApproximateDivisionByN(const AK, AS_, AVm: TBigInteger;
+  AA: ShortInt; AM, AC: Int32): TSimpleBigDecimal;
 var
-  hi: Int32;
+  L_K: Int32;
+  LNs, LGs, LHs, LJs, LGsPlusJs, LLs: TBigInteger;
 begin
-  if ((h.IsInitialized) and (h.BitLength < 4)) then
-  begin
-    hi := h.Int32Value;
-    if (hi = 2) then
-    begin
-      Result := 1;
-      Exit;
-    end;
-    if (hi = 4) then
-    begin
-      Result := 2;
-      Exit;
-    end;
-  end;
+  L_K := (AM + 5) div 2 + AC;
+  LNs := AK.ShiftRight(AM - L_K - 2 + AA);
 
-  raise EArgumentCryptoLibException.CreateRes(@SInvalidCoFactor);
-end;
+  LGs := AS_.Multiply(LNs);
 
-class function TTnaf.GetSi(fieldSize, curveA: Int32;
-  const cofactor: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
-var
-  mu: ShortInt;
-  shifts, index: Int32;
-  ui: TCryptoLibGenericArray<TBigInteger>;
-  dividend0, dividend1: TBigInteger;
-begin
+  LHs := LGs.ShiftRight(AM);
 
-  mu := GetMu(curveA);
-  shifts := GetShiftsForCofactor(cofactor);
-  index := fieldSize + 3 - curveA;
-  ui := GetLucas(mu, index, false);
+  LJs := AVm.Multiply(LHs);
 
-  if (mu = 1) then
+  LGsPlusJs := LGs.Add(LJs);
+  LLs := LGsPlusJs.ShiftRight(L_K - AC);
+  if LGsPlusJs.TestBit(L_K - AC - 1) then
   begin
-    ui[0] := ui[0].Negate();
-    ui[1] := ui[1].Negate();
+    // round up
+    LLs := LLs.Add(TBigInteger.One);
   end;
 
-  dividend0 := TBigInteger.One.Add(ui[1]).ShiftRight(shifts);
-  dividend1 := TBigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
-
-  Result := TCryptoLibGenericArray<TBigInteger>.Create(dividend0, dividend1);
+  Result := TSimpleBigDecimal.Create(LLs, AC);
 end;
 
-class function TTnaf.GetSi(const curve: IAbstractF2mCurve)
-  : TCryptoLibGenericArray<TBigInteger>;
+class function TTnaf.TauAdicNaf(AMu: ShortInt; const ALambda: IZTauElement): TCryptoLibShortIntArray;
 var
-  m, a, shifts, index: Int32;
-  mu: ShortInt;
-  ui: TCryptoLibGenericArray<TBigInteger>;
-  dividend0, dividend1: TBigInteger;
+  LNorm: TBigInteger;
+  LLog2Norm, LMaxLength, LI, LLength: Int32;
+  LU: TCryptoLibShortIntArray;
+  LR0, LR1, LT, LS: TBigInteger;
+  LTnaf: TCryptoLibShortIntArray;
 begin
-  if (not curve.IsKoblitz) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SNotKoblitzCurve);
-  end;
+  if not ((AMu = 1) or (AMu = -1)) then
+    raise EArgumentCryptoLibException.Create(SMuMustBe1OrMinus1);
 
-  m := curve.fieldSize;
-  a := curve.a.ToBigInteger().Int32Value;
-  mu := GetMu(a);
-  shifts := GetShiftsForCofactor(curve.cofactor);
-  index := m + 3 - a;
-  ui := GetLucas(mu, index, false);
+  LNorm := Norm(AMu, ALambda);
 
-  if (mu = 1) then
-  begin
-    ui[0] := ui[0].Negate();
-    ui[1] := ui[1].Negate();
-  end;
+  // Ceiling of log2 of the norm
+  LLog2Norm := LNorm.BitLength;
+
+  // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+  if LLog2Norm > 30 then
+    LMaxLength := LLog2Norm + 4
+  else
+    LMaxLength := 34;
 
-  dividend0 := TBigInteger.One.Add(ui[1]).ShiftRight(shifts);
-  dividend1 := TBigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
+  SetLength(LU, LMaxLength);
+  LI := 0;
 
-  Result := TCryptoLibGenericArray<TBigInteger>.Create(dividend0, dividend1);
-end;
+  LLength := 0;
 
-class function TTnaf.GetTw(mu: ShortInt; w: Int32): TBigInteger;
-var
-  us: TCryptoLibGenericArray<TBigInteger>;
-  twoToW, u1invert: TBigInteger;
-begin
-  if (w = 4) then
+  LR0 := ALambda.U;
+  LR1 := ALambda.V;
+
+  while not (LR0.Equals(TBigInteger.Zero) and LR1.Equals(TBigInteger.Zero)) do
   begin
-    if (mu = 1) then
+    // If r0 is odd
+    if LR0.TestBit(0) then
+    begin
+      LU[LI] := ShortInt(TBigInteger.Two.Subtract(
+        (LR0.Subtract(LR1.ShiftLeft(1))).&Mod(FFour)).Int32Value);
+
+      // r0 = r0 - u[i]
+      if LU[LI] = 1 then
+        LR0 := LR0.ClearBit(0)
+      else
+        // u[i] == -1
+        LR0 := LR0.Add(TBigInteger.One);
+
+      LLength := LI;
+    end
+    else
     begin
-      Result := TBigInteger.ValueOf(6);
-      Exit;
+      LU[LI] := 0;
     end;
 
-    // mu == -1
-    Result := TBigInteger.ValueOf(10);
-    Exit;
+    LT := LR0;
+    LS := LR0.ShiftRight(1);
+    if AMu = 1 then
+      LR0 := LR1.Add(LS)
+    else
+      LR0 := LR1.Subtract(LS);
 
+    LR1 := LT.ShiftRight(1).Negate();
+    System.Inc(LI);
   end;
 
-  // For w <> 4, the values must be computed
-  us := GetLucas(mu, w, false);
-  twoToW := TBigInteger.Zero.SetBit(w);
-  u1invert := us[1].ModInverse(twoToW);
+  System.Inc(LLength);
 
-  Result := TBigInteger.Two.Multiply(us[0]).Multiply(u1invert).&Mod(twoToW);
-  // System.out.println("mu = " + mu);
-  // System.out.println("tw = " + tw);
+  // Reduce the TNAF array to its actual length
+  SetLength(LTnaf, LLength);
+  System.Move(LU[0], LTnaf[0], LLength * SizeOf(ShortInt));
+  Result := LTnaf;
 end;
 
-class function TTnaf.MultiplyFromTnaf(const p: IAbstractF2mPoint;
-  const u: TCryptoLibShortIntArray): IAbstractF2mPoint;
-var
-  curve: IECCurve;
-  q, pNeg: IAbstractF2mPoint;
-  tauCount, i: Int32;
-  ui: ShortInt;
-  x: IECPoint;
+class function TTnaf.Tau(const AP: IAbstractF2mPoint): IAbstractF2mPoint;
 begin
-  curve := p.curve;
-  q := curve.Infinity as IAbstractF2mPoint;
-  pNeg := p.Negate() as IAbstractF2mPoint;
-  tauCount := 0;
-
-  i := System.Length(u) - 1;
-
-  while i >= 0 do
-  begin
-    System.Inc(tauCount);
-    ui := u[i];
-    if (ui <> 0) then
-    begin
-      q := q.TauPow(tauCount);
-      tauCount := 0;
-
-      if ui > 0 then
-      begin
-        x := p;
-      end
-      else
-      begin
-        x := pNeg;
-      end;
-
-      q := q.Add(x) as IAbstractF2mPoint;
-    end;
-    System.Dec(i);
-  end;
-  if (tauCount > 0) then
-  begin
-    q := q.TauPow(tauCount);
-  end;
-  Result := q;
+  Result := AP.Tau();
 end;
 
-class function TTnaf.MultiplyTnaf(const p: IAbstractF2mPoint;
-  const lambda: IZTauElement): IAbstractF2mPoint;
+class function TTnaf.GetMu(const ACurve: IAbstractF2mCurve): ShortInt;
 var
-  curve: IAbstractF2mCurve;
-  mu: ShortInt;
-  u: TCryptoLibShortIntArray;
-  q: IAbstractF2mPoint;
+  LA: TBigInteger;
 begin
-  curve := p.curve as IAbstractF2mCurve;
-  mu := GetMu(curve.a);
-  u := TauAdicNaf(mu, lambda);
+  LA := ACurve.A.ToBigInteger();
 
-  q := MultiplyFromTnaf(p, u);
+  if LA.SignValue = 0 then
+    Result := -1
+  else if LA.Equals(TBigInteger.One) then
+    Result := 1
+  else
+    raise EArgumentCryptoLibException.Create(SNoKoblitzCurve);
+end;
 
-  Result := q;
+class function TTnaf.GetMu(const ACurveA: IECFieldElement): ShortInt;
+begin
+  if ACurveA.IsZero then
+    Result := -1
+  else
+    Result := 1;
 end;
 
-class function TTnaf.MultiplyRTnaf(const p: IAbstractF2mPoint;
-  const k: TBigInteger): IAbstractF2mPoint;
-var
-  curve: IAbstractF2mCurve;
-  m, a: Int32;
-  mu: ShortInt;
-  s: TCryptoLibGenericArray<TBigInteger>;
-  rho: IZTauElement;
+class function TTnaf.GetMu(ACurveA: Int32): ShortInt;
 begin
-  curve := p.curve as IAbstractF2mCurve;
-  m := curve.fieldSize;
-  a := curve.a.ToBigInteger().Int32Value;
-  mu := GetMu(a);
-  s := curve.GetSi();
-  rho := PartModReduction(k, m, ShortInt(a), s, mu, ShortInt(10));
-
-  Result := MultiplyTnaf(p, rho);
+  if ACurveA = 0 then
+    Result := -1
+  else
+    Result := 1;
 end;
 
-class function TTnaf.Norm(mu: ShortInt; const lambda: IZTauElement)
-  : TBigInteger;
+class function TTnaf.GetLucas(AMu: ShortInt; AK: Int32; ADoV: Boolean): TCryptoLibGenericArray<TBigInteger>;
 var
-  LNorm, s1, s2, s3: TBigInteger;
+  LU0, LU1, LU2, LS: TBigInteger;
+  LI: Int32;
 begin
-  // s1 = u^2
-  s1 := lambda.u.Multiply(lambda.u);
-
-  // s2 = u * v
-  s2 := lambda.u.Multiply(lambda.v);
+  if not ((AMu = 1) or (AMu = -1)) then
+    raise EArgumentCryptoLibException.Create(SMuMustBe1OrMinus1);
 
-  // s3 = 2 * v^2
-  s3 := lambda.v.Multiply(lambda.v).ShiftLeft(1);
-
-  if (mu = 1) then
+  if ADoV then
   begin
-    LNorm := s1.Add(s2).Add(s3);
-  end
-  else if (mu = -1) then
-  begin
-    LNorm := s1.Subtract(s2).Add(s3);
+    LU0 := TBigInteger.Two;
+    LU1 := TBigInteger.ValueOf(AMu);
   end
   else
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidMU);
+    LU0 := TBigInteger.Zero;
+    LU1 := TBigInteger.One;
   end;
 
-  Result := LNorm;
+  for LI := 1 to AK - 1 do
+  begin
+    // u2 = mu*u1 - 2*u0
+    LS := LU1;
+    if AMu < 0 then
+      LS := LS.Negate();
+
+    LU2 := LS.Subtract(LU0.ShiftLeft(1));
+    LU0 := LU1;
+    LU1 := LU2;
+  end;
+
+  Result := TCryptoLibGenericArray<TBigInteger>.Create(LU0, LU1);
 end;
 
-class function TTnaf.Norm(mu: ShortInt; const u, v: TSimpleBigDecimal)
-  : TSimpleBigDecimal;
+class function TTnaf.GetTw(AMu: ShortInt; AW: Int32): TBigInteger;
 var
-  LNorm, s1, s2, s3: TSimpleBigDecimal;
+  LUs: TCryptoLibGenericArray<TBigInteger>;
 begin
-  // s1 = u^2
-  s1 := u.Multiply(u);
-
-  // s2 = u * v
-  s2 := u.Multiply(v);
-
-  // s3 = 2 * v^2
-  s3 := v.Multiply(v).ShiftLeft(1);
-
-  if (mu = 1) then
+  if AW = 4 then
   begin
-    LNorm := s1.Add(s2).Add(s3);
-  end
-  else if (mu = -1) then
-  begin
-    LNorm := s1.Subtract(s2).Add(s3);
+    if AMu = 1 then
+      Result := TBigInteger.Six
+    else
+      Result := TBigInteger.Ten;
   end
   else
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidMU);
+    LUs := GetLucas(AMu, AW, False);
+    Result := LUs[0].ShiftLeft(1).ModDivide(LUs[1], TBigInteger.One.ShiftLeft(AW));
   end;
+end;
 
-  Result := LNorm;
+class function TTnaf.GetSi(const ACurve: IAbstractF2mCurve): TCryptoLibGenericArray<TBigInteger>;
+begin
+  if not ACurve.IsKoblitz then
+    raise EArgumentCryptoLibException.Create(SSiDefinedForKoblitzOnly);
+
+  Result := GetSi(ACurve.FieldSize,
+    ACurve.A.ToBigInteger().Int32Value,
+    ACurve.Cofactor);
 end;
 
-class function TTnaf.PartModReduction(const k: TBigInteger; m: Int32;
-  a: ShortInt; const s: TCryptoLibGenericArray<TBigInteger>; mu, c: ShortInt)
-  : IZTauElement;
+class function TTnaf.GetSi(AFieldSize, ACurveA: Int32;
+  const ACofactor: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
 var
-  d0, vm, r0, r1: TBigInteger;
-  v: TCryptoLibGenericArray<TBigInteger>;
-  lambda0, lambda1: TSimpleBigDecimal;
-  q: IZTauElement;
+  LMu: ShortInt;
+  LShifts, LIndex: Int32;
+  LUi: TCryptoLibGenericArray<TBigInteger>;
+  LDividend0, LDividend1: TBigInteger;
 begin
-  // d0 = s[0] + mu*s[1]; mu is either 1 or -1
-
-  if (mu = 1) then
-  begin
-    d0 := s[0].Add(s[1]);
-  end
-  else
+  LMu := GetMu(ACurveA);
+  LShifts := GetShiftsForCofactor(ACofactor);
+  LIndex := AFieldSize + 3 - ACurveA;
+  LUi := GetLucas(LMu, LIndex, False);
+  if LMu = 1 then
   begin
-    d0 := s[0].Subtract(s[1]);
+    LUi[0] := LUi[0].Negate();
+    LUi[1] := LUi[1].Negate();
   end;
 
-  v := GetLucas(mu, m, True);
-  vm := v[1];
-
-  lambda0 := ApproximateDivisionByN(k, s[0], vm, a, m, c);
-
-  lambda1 := ApproximateDivisionByN(k, s[1], vm, a, m, c);
-
-  q := Round(lambda0, lambda1, mu);
+  LDividend0 := TBigInteger.One.Add(LUi[1]).ShiftRight(LShifts);
+  LDividend1 := TBigInteger.One.Add(LUi[0]).ShiftRight(LShifts).Negate();
 
-  // r0 = n - d0*q0 - 2*s1*q1
-  r0 := k.Subtract(d0.Multiply(q.u))
-    .Subtract(TBigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v));
-
-  // r1 = s1*q0 - s0*q1
-  r1 := s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v));
-
-  Result := TZTauElement.Create(r0, r1);
+  Result := TCryptoLibGenericArray<TBigInteger>.Create(LDividend0, LDividend1);
 end;
 
-class function TTnaf.Round(const lambda0, lambda1: TSimpleBigDecimal;
-  mu: ShortInt): IZTauElement;
+class function TTnaf.GetShiftsForCofactor(const AH: TBigInteger): Int32;
 var
-  threeEta1, fourEta1, check1, check2, eta0, eta1, eta: TSimpleBigDecimal;
-  f0, f1, q0, q1: TBigInteger;
-  scale: Int32;
-  h0, h1: ShortInt;
+  LHi: Int32;
 begin
-  scale := lambda0.scale;
-  if (lambda1.scale <> scale) then
+  if (AH <> nil) and (AH.BitLength < 4) then
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SDifferentScales);
+    LHi := AH.Int32Value;
+    if LHi = 2 then
+      Exit(1);
+    if LHi = 4 then
+      Exit(2);
   end;
 
-  if (not((mu = 1) or (mu = -1))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidMU);
-  end;
+  raise EArgumentCryptoLibException.Create(SCofactorMustBe2Or4);
+end;
 
-  f0 := lambda0.Round();
-  f1 := lambda1.Round();
+class function TTnaf.PartModReduction(const ACurve: IAbstractF2mCurve;
+  const AK: TBigInteger; AA, AMu, AC: ShortInt): IZTauElement;
+var
+  LCallback: IPreCompCallback;
+  LPreCompInfo: IPartModPreCompInfo;
+  LVm, LS0, LS1, LD0: TBigInteger;
+  LM: Int32;
+  LLambda0, LLambda1: TSimpleBigDecimal;
+  LQ: IZTauElement;
+  LR0, LR1: TBigInteger;
+begin
+  LCallback := TPartModPreCompCallback.Create(ACurve, AMu, True);
+  if not Supports(ACurve.Precompute(PRECOMP_NAME, LCallback), IPartModPreCompInfo, LPreCompInfo) then
+    raise EInvalidOperationCryptoLibException.Create('PartMod precomp failed');
 
-  eta0 := lambda0.Subtract(f0);
-  eta1 := lambda1.Subtract(f1);
+  LVm := LPreCompInfo.Lucas;
+  LS0 := LPreCompInfo.S0;
+  LS1 := LPreCompInfo.S1;
 
-  // eta = 2*eta0 + mu*eta1
-  eta := eta0.Add(eta0);
-  if (mu = 1) then
-  begin
-    eta := eta.Add(eta1);
-  end
+  // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+  if AMu = 1 then
+    LD0 := LS0.Add(LS1)
   else
-  begin
-    // mu == -1
-    eta := eta.Subtract(eta1);
-  end;
+    LD0 := LS0.Subtract(LS1);
 
-  // check1 = eta0 - 3*mu*eta1
-  // check2 = eta0 + 4*mu*eta1
-  threeEta1 := eta1.Add(eta1).Add(eta1);
-  fourEta1 := threeEta1.Add(eta1);
+  LM := ACurve.FieldSize;
+  LLambda0 := ApproximateDivisionByN(AK, LS0, LVm, AA, LM, AC);
+  LLambda1 := ApproximateDivisionByN(AK, LS1, LVm, AA, LM, AC);
 
-  if (mu = 1) then
-  begin
-    check1 := eta0.Subtract(threeEta1);
-    check2 := eta0.Add(fourEta1);
-  end
-  else
-  begin
-    // mu == -1
-    check1 := eta0.Add(threeEta1);
-    check2 := eta0.Subtract(fourEta1);
-  end;
+  LQ := Round(LLambda0, LLambda1, AMu);
 
-  h0 := 0;
-  h1 := 0;
+  // r0 = n - d0*q0 - 2*s1*q1
+  LR0 := AK.Subtract(LD0.Multiply(LQ.U)).Subtract(
+    LS1.Multiply(LQ.V).ShiftLeft(1));
 
-  // if eta >= 1
-  if (eta.CompareTo(TBigInteger.One) >= 0) then
-  begin
-    if (check1.CompareTo(FMinusOne) < 0) then
-    begin
-      h1 := mu;
-    end
-    else
-    begin
-      h0 := 1;
-    end;
-  end
-  else
-  begin
-    // eta < 1
-    if (check2.CompareTo(TBigInteger.Two) >= 0) then
-    begin
-      h1 := mu;
-    end;
-  end;
+  // r1 = s1*q0 - s0*q1
+  LR1 := LS1.Multiply(LQ.U).Subtract(LS0.Multiply(LQ.V));
 
-  // if eta < -1
-  if (eta.CompareTo(FMinusOne) < 0) then
-  begin
-    if (check1.CompareTo(TBigInteger.One) >= 0) then
-    begin
-      h1 := ShortInt(-mu);
-    end
-    else
-    begin
-      h0 := -1;
-    end
-  end
-  else
-  begin
-    // eta >= -1
-    if (check2.CompareTo(FMinusTwo) < 0) then
-    begin
-      h1 := ShortInt(-mu);
-    end;
-  end;
+  Result := TZTauElement.Create(LR0, LR1) as IZTauElement;
+end;
 
-  q0 := f0.Add(TBigInteger.ValueOf(h0));
-  q1 := f1.Add(TBigInteger.ValueOf(h1));
-  Result := TZTauElement.Create(q0, q1);
+class function TTnaf.MultiplyRTnaf(const AP: IAbstractF2mPoint;
+  const AK: TBigInteger): IAbstractF2mPoint;
+var
+  LCurve: IAbstractF2mCurve;
+  LA: Int32;
+  LMu: ShortInt;
+  LRho: IZTauElement;
+begin
+  LCurve := AP.Curve as IAbstractF2mCurve;
+  LA := LCurve.A.ToBigInteger().Int32Value;
+  LMu := GetMu(LA);
+
+  LRho := PartModReduction(LCurve, AK, ShortInt(LA), LMu, ShortInt(10));
+
+  Result := MultiplyTnaf(AP, LRho);
 end;
 
-class function TTnaf.Tau(const p: IAbstractF2mPoint): IAbstractF2mPoint;
+class function TTnaf.MultiplyTnaf(const AP: IAbstractF2mPoint;
+  const ALambda: IZTauElement): IAbstractF2mPoint;
+var
+  LCurve: IAbstractF2mCurve;
+  LPNeg: IAbstractF2mPoint;
+  LMu: ShortInt;
+  LU: TCryptoLibShortIntArray;
 begin
-  Result := p.Tau();
+  LCurve := AP.Curve as IAbstractF2mCurve;
+  LPNeg := AP.Negate() as IAbstractF2mPoint;
+  LMu := GetMu(LCurve.A);
+  LU := TauAdicNaf(LMu, ALambda);
+
+  Result := MultiplyFromTnaf(AP, LPNeg, LU);
 end;
 
-class function TTnaf.TauAdicNaf(mu: ShortInt; const lambda: IZTauElement)
-  : TCryptoLibShortIntArray;
+class function TTnaf.MultiplyFromTnaf(const AP, APNeg: IAbstractF2mPoint;
+  const AU: TCryptoLibShortIntArray): IAbstractF2mPoint;
 var
-  LNorm, r0, r1, t, s: TBigInteger;
-  log2Norm, maxLength, i, &length: Int32;
-  u, LTnaf: TCryptoLibShortIntArray;
+  LCurve: IECCurve;
+  LQ: IAbstractF2mPoint;
+  LTauCount, LI: Int32;
+  LUi: ShortInt;
+  LX: IECPoint;
 begin
+  LCurve := AP.Curve;
+  LQ := LCurve.Infinity as IAbstractF2mPoint;
+  LTauCount := 0;
+  for LI := System.Length(AU) - 1 downto 0 do
+  begin
+    System.Inc(LTauCount);
+    LUi := AU[LI];
+    if LUi <> 0 then
+    begin
+      LQ := LQ.TauPow(LTauCount);
+      LTauCount := 0;
 
-  if (not((mu = 1) or (mu = -1))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidMU);
+      if LUi > 0 then
+        LX := AP
+      else
+        LX := APNeg;
+      LQ := LQ.Add(LX) as IAbstractF2mPoint;
+    end;
   end;
+  if LTauCount > 0 then
+    LQ := LQ.TauPow(LTauCount);
+
+  Result := LQ;
+end;
+
+class function TTnaf.TauAdicWNaf(AMu: ShortInt; const ALambda: IZTauElement;
+  AWidth, ATw: Int32; const AAlpha: TCryptoLibGenericArray<IZTauElement>): TCryptoLibShortIntArray;
+var
+  LNorm: TBigInteger;
+  LLog2Norm, LMaxLength: Int32;
+  LU: TCryptoLibShortIntArray;
+  LPow2Width, LPow2Mask, LS: Int32;
+  LR0, LR1: TBigInteger;
+  LUPos: Int32;
+  LR0_64, LR1_64, LT_64: Int64;
+  LAlphaUs, LAlphaVs: TCryptoLibInt32Array;
+  LI, LUVal, LAlphaPos: Int32;
+  LT: TBigInteger;
+begin
+  if not ((AMu = 1) or (AMu = -1)) then
+    raise EArgumentCryptoLibException.Create(SMuMustBe1OrMinus1);
 
-  LNorm := TTnaf.Norm(mu, lambda);
+  LNorm := Norm(AMu, ALambda);
 
   // Ceiling of log2 of the norm
-  log2Norm := LNorm.BitLength;
+  LLog2Norm := LNorm.BitLength;
 
   // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
-  if log2Norm > 30 then
-  begin
-    maxLength := log2Norm + 4;
-  end
+  if LLog2Norm > 30 then
+    LMaxLength := LLog2Norm + 4 + AWidth
   else
-  begin
-    maxLength := 34;
-  end;
+    LMaxLength := 34 + AWidth;
 
-  // The array holding the TNAF
-  System.SetLength(u, maxLength);
+  SetLength(LU, LMaxLength);
 
-  i := 0;
+  LPow2Width := 1 shl AWidth;
+  LPow2Mask := LPow2Width - 1;
+  LS := 32 - AWidth;
 
-  // The actual length of the TNAF
-  Length := 0;
+  // Split lambda into two BigIntegers
+  LR0 := ALambda.U;
+  LR1 := ALambda.V;
+  LUPos := 0;
 
-  r0 := lambda.u;
-  r1 := lambda.v;
+  SetLength(LAlphaUs, System.Length(AAlpha));
+  SetLength(LAlphaVs, System.Length(AAlpha));
+  LI := 1;
+  while LI < System.Length(AAlpha) do
+  begin
+    LAlphaUs[LI] := AAlpha[LI].U.Int32ValueExact();
+    LAlphaVs[LI] := AAlpha[LI].V.Int32ValueExact();
+    System.Inc(LI, 2);
+  end;
 
-  while (not((r0.Equals(TBigInteger.Zero)) and
-    (r1.Equals(TBigInteger.Zero)))) do
+  // BigInteger path: while lambda <> (0, 0)
+  while (LR0.BitLength > 62) or (LR1.BitLength > 62) do
   begin
-    // If r0 is odd
-    if (r0.TestBit(0)) then
+    if LR0.TestBit(0) then
     begin
-      u[i] := ShortInt(TBigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1)))
-        .&Mod(FFour)).Int32Value);
+      LUVal := LR0.Int32Value + (LR1.Int32Value * ATw);
+      LAlphaPos := LUVal and LPow2Mask;
 
-      // r0 = r0 - u[i]
-      if (u[i] = 1) then
-      begin
-        r0 := r0.ClearBit(0);
-      end
-      else
-      begin
-        // u[i] == -1
-        r0 := r0.Add(TBigInteger.One);
-      end;
-      Length := i;
-    end
-    else
-    begin
-      u[i] := 0;
+      LU[LUPos] := ShortInt(TBitOperations.Asr32(LUVal shl LS, LS));
+      LR0 := LR0.Subtract(AAlpha[LAlphaPos].U);
+      LR1 := LR1.Subtract(AAlpha[LAlphaPos].V);
     end;
 
-    t := r0;
-    s := r0.ShiftRight(1);
-    if (mu = 1) then
-    begin
-      r0 := r1.Add(s);
-    end
+    System.Inc(LUPos);
+
+    LT := LR0.ShiftRight(1);
+    if AMu = 1 then
+      LR0 := LR1.Add(LT)
     else
-    begin
-      // mu == -1
-      r0 := r1.Subtract(s);
-    end;
+      LR0 := LR1.Subtract(LT);
 
-    r1 := t.ShiftRight(1).Negate();
-    System.Inc(i);
+    LR1 := LT.Negate();
   end;
 
-  System.Inc(Length);
-
-  // Reduce the TNAF array to its actual length
-  System.SetLength(LTnaf, Length);
-  System.Move(u[0], LTnaf[0], Length * System.SizeOf(ShortInt));
-
-  Result := LTnaf;
-end;
-
-class function TTnaf.TauAdicWNaf(mu: ShortInt; const lambda: IZTauElement;
-  Width: ShortInt; const pow2w, tw: TBigInteger;
-  const alpha: TCryptoLibGenericArray<IZTauElement>): TCryptoLibShortIntArray;
-var
-  LNorm, pow2wMin1, r0, r1, t, uUnMod: TBigInteger;
-  log2Norm, maxLength, i: Int32;
-  u: TCryptoLibShortIntArray;
-  uLocal: ShortInt;
-  s: Boolean;
-begin
+  LR0_64 := LR0.Int64ValueExact();
+  LR1_64 := LR1.Int64ValueExact();
 
-  if (not((mu = 1) or (mu = -1))) then
+  // Small-value loop using Int64 arithmetic
+  while (LR0_64 or LR1_64) <> Int64(0) do
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidMU);
-  end;
+    if (LR0_64 and Int64(1)) <> Int64(0) then
+    begin
+      LUVal := Int32(LR0_64) + (Int32(LR1_64) * ATw);
+      LAlphaPos := LUVal and LPow2Mask;
+
+      LU[LUPos] := ShortInt(TBitOperations.Asr32(LUVal shl LS, LS));
+      LR0_64 := LR0_64 - LAlphaUs[LAlphaPos];
+      LR1_64 := LR1_64 - LAlphaVs[LAlphaPos];
+    end;
 
-  LNorm := Norm(mu, lambda);
+    System.Inc(LUPos);
 
-  // Ceiling of log2 of the norm
-  log2Norm := LNorm.BitLength;
+    LT_64 := TBitOperations.Asr64(LR0_64, 1);
+    if AMu = 1 then
+      LR0_64 := LR1_64 + LT_64
+    else
+      LR0_64 := LR1_64 - LT_64;
 
-  // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
-  if log2Norm > 30 then
-  begin
-    maxLength := log2Norm + 4 + Width;
-  end
-  else
-  begin
-    maxLength := 34 + Width;
+    LR1_64 := -LT_64;
   end;
 
-  // The array holding the TNAF
-  System.SetLength(u, maxLength);
+  Result := LU;
+end;
 
-  // 2^(width - 1)
-  pow2wMin1 := pow2w.ShiftRight(1);
+class function TTnaf.GetPreComp(const AP: IAbstractF2mPoint;
+  AA: ShortInt): TCryptoLibGenericArray<IAbstractF2mPoint>;
+var
+  LPNeg: IAbstractF2mPoint;
+  LAlphaTnaf: TCryptoLibMatrixShortIntArray;
+  LPu: TCryptoLibGenericArray<IECPoint>;
+  LPrecompLen: Int32;
+  LI: UInt32;
+begin
+  LPNeg := AP.Negate() as IAbstractF2mPoint;
+  if AA = 0 then
+    LAlphaTnaf := Alpha0Tnaf
+  else
+    LAlphaTnaf := Alpha1Tnaf;
 
-  // Split lambda into two BigIntegers to simplify calculations
-  r0 := lambda.u;
-  r1 := lambda.v;
-  i := 0;
+  SetLength(LPu, (UInt32(System.Length(LAlphaTnaf)) + 1) shr 1);
+  LPu[0] := AP;
 
-  // while lambda <> (0, 0)
-  while (not((r0.Equals(TBigInteger.Zero)) and
-    (r1.Equals(TBigInteger.Zero)))) do
+  LPrecompLen := System.Length(LAlphaTnaf);
+  LI := 3;
+  while LI < UInt32(LPrecompLen) do
   begin
-    // if r0 is odd
-    if (r0.TestBit(0)) then
-    begin
-      // uUnMod = r0 + r1*tw Mod 2^width
-      uUnMod := r0.Add(r1.Multiply(tw)).&Mod(pow2w);
-
-      // if uUnMod >= 2^(width - 1)
-      if (uUnMod.CompareTo(pow2wMin1) >= 0) then
-      begin
-        uLocal := ShortInt(uUnMod.Subtract(pow2w).Int32Value);
-      end
-      else
-      begin
-        uLocal := ShortInt(uUnMod.Int32Value);
-      end;
-      // uLocal is now in [-2^(width-1), 2^(width-1)-1]
-
-      u[i] := uLocal;
-      s := True;
-      if (uLocal < 0) then
-      begin
-        s := false;
-        uLocal := ShortInt(-uLocal);
-      end;
-      // uLocal is now >= 0
-
-      if (s) then
-      begin
-        r0 := r0.Subtract(alpha[uLocal].u);
-        r1 := r1.Subtract(alpha[uLocal].v);
-      end
-      else
-      begin
-        r0 := r0.Add(alpha[uLocal].u);
-        r1 := r1.Add(alpha[uLocal].v);
-      end;
-    end
-    else
-    begin
-      u[i] := 0;
-    end;
+    LPu[LI shr 1] := MultiplyFromTnaf(AP, LPNeg, LAlphaTnaf[LI]);
+    System.Inc(LI, 2);
+  end;
 
-    t := r0;
+  AP.Curve.NormalizeAll(LPu);
 
-    if (mu = 1) then
+  Result := TArrayUtilities.Map<IECPoint, IAbstractF2mPoint>(LPu,
+    function(APoint: IECPoint): IAbstractF2mPoint
     begin
-      r0 := r1.Add(r0.ShiftRight(1));
-    end
-    else
-    begin
-      // mu == -1
-      r0 := r1.Subtract(r0.ShiftRight(1));
-    end;
-    r1 := t.ShiftRight(1).Negate();
-    System.Inc(i);
-
-  end;
-  Result := u;
-end;
-
-class constructor TTnaf.Tnaf;
-begin
-  TTnaf.Boot();
+      Result := APoint as IAbstractF2mPoint;
+    end);
 end;
 
 end.

+ 17 - 45
CryptoLib/src/Math/EC/Abc/ClpZTauElement.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpZTauElement;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -26,63 +19,42 @@ uses
   ClpIZTauElement;
 
 type
-  /// **
-  // * Class representing an element of <code><b>Z</b>[&#964;]</code>. Let
-  // * <code>&#955;</code> be an element of <code><b>Z</b>[&#964;]</code>. Then
-  // * <code>&#955;</code> is given as <code>&#955; = u + v&#964;</code>. The
-  // * components <code>u</code> and <code>v</code> may be used directly, there
-  // * are no accessor methods.
-  // * Immutable class.
-  // */
-  TZTauElement = class(TInterfacedObject, IZTauElement)
-
+  /// <summary>
+  /// Class representing an element of Z[tau]. Let lambda be an element of
+  /// Z[tau]. Then lambda is given as lambda = u + v*tau. The components
+  /// u and v may be used directly via properties.
+  /// Immutable class.
+  /// </summary>
+  TZTauElement = class sealed(TInterfacedObject, IZTauElement)
   strict private
-  var
-    Fu, Fv: TBigInteger;
-
-    function GetU: TBigInteger; inline;
-    function GetV: TBigInteger; inline;
-
+    FU, FV: TBigInteger;
+    function GetU: TBigInteger;
+    function GetV: TBigInteger;
   public
-    // /**
-    // * The &quot;real&quot; part of <code>&#955;</code>.
-    // */
+    constructor Create(const AU, AV: TBigInteger);
     property U: TBigInteger read GetU;
-    // /**
-    // * The &quot;<code>&#964;</code>-adic&quot; part of <code>&#955;</code>.
-    // */
     property V: TBigInteger read GetV;
-
-    // /**
-    // * Constructor for an element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code>.
-    // * @param u The &quot;real&quot; part of <code>&#955;</code>.
-    // * @param v The &quot;<code>&#964;</code>-adic&quot; part of
-    // * <code>&#955;</code>.
-    // */
-    constructor Create(const U, V: TBigInteger);
-
   end;
 
 implementation
 
 { TZTauElement }
 
-constructor TZTauElement.Create(const U, V: TBigInteger);
+constructor TZTauElement.Create(const AU, AV: TBigInteger);
 begin
-  inherited Create();
-  Fu := U;
-  Fv := V;
+  inherited Create;
+  FU := AU;
+  FV := AV;
 end;
 
 function TZTauElement.GetU: TBigInteger;
 begin
-  Result := Fu;
+  Result := FU;
 end;
 
 function TZTauElement.GetV: TBigInteger;
 begin
-  Result := Fv;
+  Result := FV;
 end;
 
 end.

+ 14 - 12
CryptoLib/src/Interfaces/Math/EC/Endo/ClpIGlvEndomorphism.pas → CryptoLib/src/Math/EC/ClpAbstractECLookupTable.pas

@@ -15,27 +15,29 @@
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 
-unit ClpIGlvEndomorphism;
+unit ClpAbstractECLookupTable;
 
-{$I ..\..\..\..\Include\CryptoLib.inc}
+{$I ..\..\Include\CryptoLib.inc}
 
 interface
 
 uses
-  ClpCryptoLibTypes,
-  ClpBigInteger,
-  ClpIECC;
+  ClpIECCore;
 
 type
-  IGlvEndomorphism = interface(IECEndomorphism)
-
-    ['{FC8EE19A-A707-438F-81CF-C6C6C7D7C36C}']
-
-    function DecomposeScalar(const k: TBigInteger)
-      : TCryptoLibGenericArray<TBigInteger>;
-
+  TAbstractECLookupTable = class abstract(TInterfacedObject, IECLookupTable)
+  public
+    function Lookup(AIndex: Int32): IECPoint; virtual; abstract;
+    function GetSize: Int32; virtual; abstract;
+    function LookupVar(AIndex: Int32): IECPoint; virtual;
+    property Size: Int32 read GetSize;
   end;
 
 implementation
 
+function TAbstractECLookupTable.LookupVar(AIndex: Int32): IECPoint;
+begin
+  Result := Lookup(AIndex);
+end;
+
 end.

+ 586 - 899
CryptoLib/src/Math/EC/ClpECAlgorithms.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpECAlgorithms;
 
 {$I ..\..\Include\CryptoLib.inc}
@@ -23,1020 +16,714 @@ interface
 
 uses
   SysUtils,
-  Math,
-  ClpCryptoLibTypes,
   ClpBigInteger,
-  ClpBitOperations,
-  ClpNat,
-  ClpIECC,
-  ClpECCompUtilities,
-  ClpIWNafPreCompInfo,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpIFiniteField,
-  ClpIFixedPointPreCompInfo,
-  ClpIGlvEndomorphism,
-  ClpIMultipliers,
-  ClpMultipliers,
-  ClpIPolynomialExtensionField;
-
-resourcestring
-  SInvalidArray =
-    'Point and Scalar Arrays Should be Non-Null, and of Equal, Non-Zero, Length';
-  SInvalidPointLocation = 'Point Must be on the Same Curve';
-  SInvalidPoint = 'Invalid Point, "P"';
-  SInvalidResult = 'Invalid Result';
-  SInvalidComputation =
-    'Fixed-Point Comb Doesn''t Support Scalars Larger Than The Curve Order';
+  ClpIPolynomialExtensionField,
+  ClpCryptoLibTypes;
 
 type
-  TECAlgorithms = class sealed(TObject)
-
-  strict private
-    class function ImplShamirsTrickWNaf(const preCompP,
-      preCompNegP: TCryptoLibGenericArray<IECPoint>;
-      const wnafP: TCryptoLibByteArray;
-      const preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
-      const wnafQ: TCryptoLibByteArray): IECPoint; overload; static;
-
-    class function ImplSumOfMultiplies(const negs: TCryptoLibBooleanArray;
-      const infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
-      const wnafs: TCryptoLibMatrixByteArray): IECPoint; overload; static;
-
-    class function ImplShamirsTrickFixedPoint(const p: IECPoint;
-      const k: TBigInteger; const q: IECPoint; const l: TBigInteger)
-      : IECPoint; static;
-
+  TECAlgorithms = class(TObject)
   public
-    class function IsF2mCurve(const c: IECCurve): Boolean; static;
-    class function IsF2mField(const field: IFiniteField): Boolean; static;
-    class function IsFpCurve(const c: IECCurve): Boolean; static;
-    class function IsFpField(const field: IFiniteField): Boolean; static;
-
-    class function SumOfMultiplies(const ps: TCryptoLibGenericArray<IECPoint>;
-      const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint; static;
-
-    class function SumOfTwoMultiplies(const p: IECPoint; const a: TBigInteger;
-      const q: IECPoint; const b: TBigInteger): IECPoint; static;
-
-    // /*
-    // * "Shamir's Trick", originally due to E. G. Straus
-    // * (Addition chains of vectors. American Mathematical Monthly,
-    // * 71(7):806-808, Aug./Sept. 1964)
-    // *
-    // * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
-    // * and scalar l = (lm?, ... , l1, l0).
-    // * Output: R = k * P + l * Q.
-    // * 1: Z <- P + Q
-    // * 2: R <- O
-    // * 3: for i from m-1 down to 0 do
-    // * 4:        R <- R + R        {point doubling}
-    // * 5:        if (ki = 1) and (li = 0) then R <- R + P end if
-    // * 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
-    // * 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
-    // * 8: end for
-    // * 9: return R
-    // */
-    class function ShamirsTrick(const p: IECPoint; const k: TBigInteger;
-      const q: IECPoint; const l: TBigInteger): IECPoint; static;
-
-    class function ImportPoint(const c: IECCurve; const p: IECPoint)
-      : IECPoint; static;
-
-    class procedure MontgomeryTrick(const zs
-      : TCryptoLibGenericArray<IECFieldElement>; off, len: Int32); overload;
-      static; inline;
-
-    class procedure MontgomeryTrick(const zs
-      : TCryptoLibGenericArray<IECFieldElement>; off, len: Int32;
-      const scale: IECFieldElement); overload; static;
-
-    // /**
-    // * Simple shift-and-add multiplication. Serves as reference implementation
-    // * to verify (possibly faster) implementations, and for very small scalars.
-    // *
-    // * @param p
-    // *            The point to multiply.
-    // * @param k
-    // *            The multiplier.
-    // * @return The result of the point multiplication <code>kP</code>.
-    // */
-    class function ReferenceMultiply(const p: IECPoint; const k: TBigInteger)
-      : IECPoint; static;
-
-    class function ImplCheckResult(const p: IECPoint): IECPoint; static;
-
-    class function ValidatePoint(const p: IECPoint): IECPoint; static;
-
-    class function CleanPoint(const c: IECCurve; const p: IECPoint)
-      : IECPoint; static;
-
-    class function ImplShamirsTrickJsf(const p: IECPoint; const k: TBigInteger;
-      const q: IECPoint; const l: TBigInteger): IECPoint; static;
+    class procedure MontgomeryTrick(const AZs: TCryptoLibGenericArray<IECFieldElement>;
+      AOff, ALen: Int32); overload; static;
+    class procedure MontgomeryTrick(const AZs: TCryptoLibGenericArray<IECFieldElement>;
+      AOff, ALen: Int32; const AScale: IECFieldElement); overload; static;  // AZs modified in place
+    class function ReferenceMultiply(const AP: IECPoint; const AK: TBigInteger): IECPoint; static;
+    class function ValidatePoint(const AP: IECPoint): IECPoint; static;
+    class function CleanPoint(const AC: IECCurve; const AP: IECPoint): IECPoint; static;
+    class function ImportPoint(const AC: IECCurve; const AP: IECPoint): IECPoint; static;
+    class function SumOfMultiplies(const APs: TCryptoLibGenericArray<IECPoint>;
+      const AKs: TCryptoLibGenericArray<TBigInteger>): IECPoint; static;
+    class function SumOfTwoMultiplies(const AP: IECPoint; const AK: TBigInteger;
+      const AQ: IECPoint; const AL: TBigInteger): IECPoint; static;
+    class function ShamirsTrick(const AP: IECPoint; const AK: TBigInteger;
+      const AQ: IECPoint; const AL: TBigInteger): IECPoint; static;
+    class function IsFpCurve(const AC: IECCurve): Boolean; static;
+    class function IsFpField(const AField: IFiniteField): Boolean; static;
+    class function IsF2mCurve(const AC: IECCurve): Boolean; static;
+    class function IsF2mField(const AField: IFiniteField): Boolean; static;
+    class function ImplCheckResult(const AP: IECPoint): IECPoint; static;
+    class function ImplShamirsTrickJsf(const AP: IECPoint; const AK: TBigInteger;
+      const AQ: IECPoint; const AL: TBigInteger): IECPoint; static;
+    class function ImplShamirsTrickWNaf(const AP: IECPoint; const AK: TBigInteger;
+      const AQ: IECPoint; const AL: TBigInteger): IECPoint; overload; static;
+    class function ImplShamirsTrickWNaf(const AEndomorphism: IECEndomorphism;
+      const AP: IECPoint; const AK: TBigInteger; const AL: TBigInteger): IECPoint; overload; static;
+    class function ImplShamirsTrickWNaf(
+      const APreCompP, APreCompNegP: TCryptoLibGenericArray<IECPoint>;
+      const AWnafP: TCryptoLibByteArray;
+      const APreCompQ, APreCompNegQ: TCryptoLibGenericArray<IECPoint>;
+      const AWnafQ: TCryptoLibByteArray): IECPoint; overload; static;
+    class function ImplShamirsTrickFixedPoint(const AP: IECPoint; const AK: TBigInteger;
+      const AQ: IECPoint; const AL: TBigInteger): IECPoint; static;
+    class function ImplSumOfMultiplies(const APs: TCryptoLibGenericArray<IECPoint>;
+      const AKs: TCryptoLibGenericArray<TBigInteger>): IECPoint; overload; static;
+    class function ImplSumOfMultiplies(const AEndomorphism: IECEndomorphism;
+      const APs: TCryptoLibGenericArray<IECPoint>;
+      const AKs: TCryptoLibGenericArray<TBigInteger>): IECPoint; overload; static;
+    class function ImplSumOfMultiplies(
+      const ANegs: TCryptoLibBooleanArray;
+      const AInfos: TCryptoLibGenericArray<IWNafPreCompInfo>;
+      const AWnafs: TCryptoLibGenericArray<TCryptoLibByteArray>): IECPoint; overload; static;
+    class function ImplSumOfMultipliesGlv(const APs: TCryptoLibGenericArray<IECPoint>;
+      const AKs: TCryptoLibGenericArray<TBigInteger>;
+      const AGlvEndomorphism: IGlvEndomorphism): IECPoint; static;
+  end;
 
-    class function ImplShamirsTrickWNaf(const p: IECPoint; const k: TBigInteger;
-      const q: IECPoint; const l: TBigInteger): IECPoint; overload; static;
+implementation
 
-    class function ImplShamirsTrickWNaf(const endomorphism: IECEndomorphism;
-      const p: IECPoint; const k, l: TBigInteger): IECPoint; overload; static;
+uses
+  System.Math,
+  ClpBitOperations,
+  ClpECCurve,
+  ClpFixedPointUtilities,
+  ClpIFixedPointPreCompInfo,
+  ClpFixedPointPreCompInfo,
+  ClpMultipliers,
+  ClpWNafUtilities,
+  ClpWNafPreCompInfo,
+  ClpEndoUtilities,
+  ClpNat,
+  ClpCryptoLibTypes;
 
-    class function ImplSumOfMultiplies
-      (const ps: TCryptoLibGenericArray<IECPoint>;
-      const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
-      overload; static;
+{ TECAlgorithms }
 
-    class function ImplSumOfMultipliesGlv
-      (const ps: TCryptoLibGenericArray<IECPoint>;
-      const ks: TCryptoLibGenericArray<TBigInteger>;
-      const glvEndomorphism: IGlvEndomorphism): IECPoint; static;
+class procedure TECAlgorithms.MontgomeryTrick(
+  const AZs: TCryptoLibGenericArray<IECFieldElement>; AOff, ALen: Int32);
+begin
+  MontgomeryTrick(AZs, AOff, ALen, nil);
+end;
 
-    class function ImplSumOfMultiplies(const endomorphism: IECEndomorphism;
-      const ps: TCryptoLibGenericArray<IECPoint>;
-      const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
-      overload; static;
+class procedure TECAlgorithms.MontgomeryTrick(
+  const AZs: TCryptoLibGenericArray<IECFieldElement>; AOff, ALen: Int32;
+  const AScale: IECFieldElement);
+var
+  LC: TCryptoLibGenericArray<IECFieldElement>;
+  I, J: Int32;
+  LU: IECFieldElement;
+  LTmp: IECFieldElement;
+begin
+  System.SetLength(LC, ALen);
+  LC[0] := AZs[AOff];
 
+  I := 0;
+  while I + 1 < ALen do
+  begin
+    Inc(I);
+    LC[I] := LC[I - 1].Multiply(AZs[AOff + I]);
   end;
 
-implementation
+  if AScale <> nil then
+    LC[I] := LC[I].Multiply(AScale);
 
-{ TECAlgorithms }
+  LU := LC[I].Invert();
 
-class function TECAlgorithms.ImplCheckResult(const p: IECPoint): IECPoint;
-begin
-  if (not(p.IsValidPartial())) then
+  while I > 0 do
   begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidResult);
+    J := AOff + I;
+    Dec(I);
+    LTmp := AZs[J];
+    AZs[J] := LC[I].Multiply(LU);
+    LU := LU.Multiply(LTmp);
   end;
 
-  result := p;
+  AZs[AOff] := LU;
 end;
 
-class function TECAlgorithms.CleanPoint(const c: IECCurve; const p: IECPoint)
-  : IECPoint;
+class function TECAlgorithms.ReferenceMultiply(const AP: IECPoint;
+  const AK: TBigInteger): IECPoint;
 var
-  cp: IECCurve;
+  LX: TBigInteger;
+  LP, LQ: IECPoint;
+  LT, LI: Int32;
 begin
-  cp := p.Curve;
-  if (not c.Equals(cp)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointLocation);
+  LX := AK.Abs();
+  LQ := AP.Curve.Infinity;
+  LT := LX.BitLength;
+  if LT > 0 then
+  begin
+    if LX.TestBit(0) then
+      LQ := AP;
+    LP := AP;
+    LI := 1;
+    while LI < LT do
+    begin
+      LP := LP.Twice();
+      if LX.TestBit(LI) then
+        LQ := LQ.Add(LP);
+      Inc(LI);
+    end;
   end;
-
-  result := c.DecodePoint(p.getEncoded(false));
+  if AK.SignValue < 0 then
+    Result := LQ.Negate()
+  else
+    Result := LQ;
 end;
 
-class function TECAlgorithms.ValidatePoint(const p: IECPoint): IECPoint;
+class function TECAlgorithms.ValidatePoint(const AP: IECPoint): IECPoint;
 begin
-  if (not p.IsValid()) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPoint);
-  end;
+  if not AP.IsValid() then
+    raise EInvalidOperationCryptoLibException.Create('Invalid point');
+  Result := AP;
+end;
 
-  result := p;
+class function TECAlgorithms.CleanPoint(const AC: IECCurve; const AP: IECPoint): IECPoint;
+var
+  LEncoded: TCryptoLibByteArray;
+  LCurve: IECCurve;
+begin
+  LCurve := AP.Curve;
+  if not AC.Equals(LCurve) then
+    raise EArgumentCryptoLibException.Create('Point must be on the same curve');
+  LEncoded := AP.GetEncoded(False);
+  Result := AC.DecodePoint(LEncoded);
 end;
 
-class function TECAlgorithms.ImplShamirsTrickFixedPoint(const p: IECPoint;
-  const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
+class function TECAlgorithms.ImportPoint(const AC: IECCurve; const AP: IECPoint): IECPoint;
 var
-  c: IECCurve;
-  combSize, widthP, widthQ, width, d, fullComb, i, top, j: Int32;
-  infoP, infoQ: IFixedPointPreCompInfo;
-  lookupTableP, lookupTableQ: IECLookupTable;
-  m: IFixedPointCombMultiplier;
-  r1, r2, R, addP, addQ, t: IECPoint;
-  BigK, BigL: TCryptoLibUInt32Array;
-  secretBitK, secretBitL, secretIndexK, secretIndexL: UInt32;
+  LCurve: IECCurve;
 begin
-  c := p.Curve;
-  combSize := TFixedPointUtilities.GetCombSize(c);
+  LCurve := AP.Curve;
+  if not AC.Equals(LCurve) then
+    raise EArgumentCryptoLibException.Create('Point must be on the same curve');
+  Result := AC.ImportPoint(AP);
+end;
 
-  if (((k.BitLength) > combSize) or (l.BitLength > combSize)) then
+class function TECAlgorithms.SumOfMultiplies(const APs: TCryptoLibGenericArray<IECPoint>;
+  const AKs: TCryptoLibGenericArray<TBigInteger>): IECPoint;
+var
+  LCount, I: Int32;
+  LP: IECPoint;
+  LC: IECCurve;
+  LImported: TCryptoLibGenericArray<IECPoint>;
+  LGlv: IGlvEndomorphism;
+begin
+  if (APs = nil) or (AKs = nil) or (System.Length(APs) <> System.Length(AKs)) or
+    (System.Length(APs) < 1) then
+    raise EArgumentCryptoLibException.Create(
+      'point and scalar arrays should be non-null, and of equal, non-zero, length');
+  LCount := System.Length(APs);
+  case LCount of
+    1:
+      Exit(APs[0].Multiply(AKs[0]));
+    2:
+      Exit(SumOfTwoMultiplies(APs[0], AKs[0], APs[1], AKs[1]));
+  else
+    ;
+  end;
+  LP := APs[0];
+  LC := LP.Curve;
+  System.SetLength(LImported, LCount);
+  LImported[0] := LP;
+  I := 1;
+  while I < LCount do
   begin
-    (*
-      * TODO The comb works best when the scalars are less than the (possibly unknown) order.
-      * Still, if we want to handle larger scalars, we could allow customization of the comb
-      * size, or alternatively we could deal with the 'extra' bits either by running the comb
-      * multiple times as necessary, or by using an alternative multiplier as prelude.
-    *)
-    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidComputation);
+    LImported[I] := ImportPoint(LC, APs[I]);
+    Inc(I);
   end;
+  if Supports(LC.GetEndomorphism(), IGlvEndomorphism, LGlv) then
+    Result := ImplCheckResult(ImplSumOfMultipliesGlv(LImported, AKs, LGlv))
+  else
+    Result := ImplCheckResult(ImplSumOfMultiplies(LImported, AKs));
+end;
 
-  infoP := TFixedPointUtilities.Precompute(p);
-  infoQ := TFixedPointUtilities.Precompute(q);
-
-  lookupTableP := infoP.LookupTable;
-  lookupTableQ := infoQ.LookupTable;
+class function TECAlgorithms.ShamirsTrick(const AP: IECPoint; const AK: TBigInteger;
+  const AQ: IECPoint; const AL: TBigInteger): IECPoint;
+var
+  LCp: IECCurve;
+  LQ: IECPoint;
+begin
+  LCp := AP.Curve;
+  LQ := ImportPoint(LCp, AQ);
+  Result := ImplCheckResult(ImplShamirsTrickJsf(AP, AK, LQ, AL));
+end;
 
-  widthP := infoP.width;
-  widthQ := infoQ.width;
+class function TECAlgorithms.SumOfTwoMultiplies(const AP: IECPoint; const AK: TBigInteger;
+  const AQ: IECPoint; const AL: TBigInteger): IECPoint;
+var
+  LCurve: IECCurve;
+  LQ: IECPoint;
+  LF2mCurve: IAbstractF2mCurve;
+  LGlv: IGlvEndomorphism;
+begin
+  LCurve := AP.Curve;
+  LQ := ImportPoint(LCurve, AQ);
 
-  // TODO This shouldn't normally happen, but a better "solution" is desirable anyway
-  if (widthP <> widthQ) then
+  if Supports(LCurve, IAbstractF2mCurve, LF2mCurve) and LF2mCurve.IsKoblitz then
   begin
-    m := TFixedPointCombMultiplier.Create();
-    r1 := m.Multiply(p, k);
-    r2 := m.Multiply(q, l);
-    result := r1.Add(r2);
+    Result := ImplCheckResult(AP.Multiply(AK).Add(LQ.Multiply(AL)));
     Exit;
   end;
-
-  width := widthP;
-
-  d := ((combSize + width) - 1) div width;
-
-  R := c.Infinity;
-
-  fullComb := d * width;
-  BigK := TNat.FromBigInteger(fullComb, k);
-  BigL := TNat.FromBigInteger(fullComb, l);
-
-  top := fullComb - 1;
-
-  for i := 0 to System.Pred(d) do
+  if Supports(LCurve.GetEndomorphism(), IGlvEndomorphism, LGlv) then
   begin
-    secretIndexK := 0;
-    secretIndexL := 0;
-
-    j := top - i;
-
-    while j >= 0 do
-    begin
-
-      secretBitK := BigK[TBitOperations.Asr32(j, 5)] shr (j and $1F);
-      secretIndexK := secretIndexK xor (secretBitK shr 1);
-      secretIndexK := secretIndexK shl 1;
-      secretIndexK := secretIndexK xor secretBitK;
-
-      secretBitL := BigL[TBitOperations.Asr32(j, 5)] shr (j and $1F);
-      secretIndexL := secretIndexL xor (secretBitL shr 1);
-      secretIndexL := secretIndexL shl 1;
-      secretIndexL := secretIndexL xor secretBitL;
-
-      System.Dec(j, d);
-    end;
-
-    addP := lookupTableP.LookupVar(Int32(secretIndexK));
-    addQ := lookupTableQ.LookupVar(Int32(secretIndexL));
-
-    t := addP.Add(addQ);
-
-    R := R.TwicePlus(t);
+    Result := ImplCheckResult(ImplSumOfMultipliesGlv(
+      TCryptoLibGenericArray<IECPoint>.Create(AP, LQ),
+      TCryptoLibGenericArray<TBigInteger>.Create(AK, AL), LGlv));
+    Exit;
   end;
 
-  result := R.Add(infoP.Offset).Add(infoQ.Offset);
+  Result := ImplCheckResult(ImplShamirsTrickWNaf(AP, AK, LQ, AL));
 end;
 
-class function TECAlgorithms.ImplShamirsTrickJsf(const p: IECPoint;
-  const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
-var
-  Curve: IECCurve;
-  Infinity, R: IECPoint;
-  PaddQ, PsubQ: IECPoint;
-  points, table: TCryptoLibGenericArray<IECPoint>;
-  jsf: TCryptoLibByteArray;
-  i, jsfi, kDigit, lDigit, index: Int32;
+class function TECAlgorithms.IsFpCurve(const AC: IECCurve): Boolean;
 begin
-  Curve := p.Curve;
-  Infinity := Curve.Infinity;
-
-  // TODO conjugate co-Z addition (ZADDC) can return both of these
-  PaddQ := p.Add(q);
-  PsubQ := p.Subtract(q);
-
-  points := TCryptoLibGenericArray<IECPoint>.Create(q, PsubQ, p, PaddQ);
-  Curve.NormalizeAll(points);
-
-  table := TCryptoLibGenericArray<IECPoint>.Create(points[3].Negate(),
-    points[2].Negate(), points[1].Negate(), points[0].Negate(), Infinity,
-    points[0], points[1], points[2], points[3]);
-
-  jsf := TWNafUtilities.GenerateJsf(k, l);
-
-  R := Infinity;
+  Result := IsFpField(AC.Field);
+end;
 
-  i := System.length(jsf);
-  System.Dec(i);
-  while (i >= 0) do
-  begin
-    jsfi := jsf[i];
+class function TECAlgorithms.IsFpField(const AField: IFiniteField): Boolean;
+begin
+  Result := AField.Dimension = 1;
+end;
 
-    // NOTE: The shifting ensures the sign is extended correctly
-    kDigit := (TBitOperations.Asr32((jsfi shl 24), 28));
-    lDigit := (TBitOperations.Asr32((jsfi shl 28), 28));
+class function TECAlgorithms.IsF2mCurve(const AC: IECCurve): Boolean;
+begin
+  Result := IsF2mField(AC.Field);
+end;
 
-    index := 4 + (kDigit * 3) + lDigit;
-    R := R.TwicePlus(table[index]);
-    System.Dec(i);
-  end;
+class function TECAlgorithms.IsF2mField(const AField: IFiniteField): Boolean;
+begin
+  Result := (AField.Dimension > 1) and
+    AField.Characteristic.Equals(TBigInteger.Two) and
+    Supports(AField, IPolynomialExtensionField);
+end;
 
-  result := R;
+class function TECAlgorithms.ImplCheckResult(const AP: IECPoint): IECPoint;
+begin
+  if not AP.IsValidPartial() then
+    raise EInvalidOperationCryptoLibException.Create('Invalid result');
+  Result := AP;
 end;
 
-class function TECAlgorithms.ImplShamirsTrickWNaf(const endomorphism
-  : IECEndomorphism; const p: IECPoint; const k, l: TBigInteger): IECPoint;
+class function TECAlgorithms.ImplShamirsTrickJsf(const AP: IECPoint; const AK: TBigInteger;
+  const AQ: IECPoint; const AL: TBigInteger): IECPoint;
 var
-  negK, negL: Boolean;
-  minWidth, widthP, widthQ: Int32;
-  q: IECPoint;
-  infoP, infoQ: IWNafPreCompInfo;
-  preCompP, preCompQ, preCompNegP, preCompNegQ
-    : TCryptoLibGenericArray<IECPoint>;
-  wnafP, wnafQ: TCryptoLibByteArray;
-  LK, LL: TBigInteger;
+  LCurve: IECCurve;
+  LInfinity, LPaddQ, LPsubQ: IECPoint;
+  LPoints: TCryptoLibGenericArray<IECPoint>;
+  LTable: TCryptoLibGenericArray<IECPoint>;
+  LJsf: TCryptoLibByteArray;
+  LI, LJsfi, LKDigit, LLDigit, LIndex: Int32;
+  LR: IECPoint;
 begin
-  LK := k;
-  LL := l;
-  negK := LK.SignValue < 0;
-  negL := LL.SignValue < 0;
-
-  LK := LK.Abs();
-  LL := LL.Abs();
-
-  minWidth := TWNafUtilities.GetWindowSize(Max(k.BitLength, l.BitLength), 8);
-
-  infoP := TWNafUtilities.Precompute(p, minWidth, true);
-  q := TEndoUtilities.MapPoint(endomorphism, p);
-  infoQ := TWNafUtilities.PrecomputeWithPointMap(q, endomorphism.pointMap,
-    infoP, true);
-
-  widthP := Min(8, infoP.width);
-  widthQ := Min(8, infoQ.width);
-
-  case negK of
-    true:
-      preCompP := infoP.PreCompNeg;
-    false:
-      preCompP := infoP.PreComp;
-  end;
-
-  case negL of
-    true:
-      preCompQ := infoQ.PreCompNeg;
-    false:
-      preCompQ := infoQ.PreComp
-  end;
-
-  case negK of
-    true:
-      preCompNegP := infoP.PreComp;
-    false:
-      preCompNegP := infoP.PreCompNeg;
-  end;
-
-  case negL of
-    true:
-      preCompNegQ := infoQ.PreComp;
-    false:
-      preCompNegQ := infoQ.PreCompNeg
-  end;
-
-  wnafP := TWNafUtilities.GenerateWindowNaf(widthP, LK);
-  wnafQ := TWNafUtilities.GenerateWindowNaf(widthQ, LL);
-
-  result := ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ,
-    preCompNegQ, wnafQ);
-
+  LCurve := AP.Curve;
+  LInfinity := LCurve.Infinity;
+  LPaddQ := AP.Add(AQ);
+  LPsubQ := AP.Subtract(AQ);
+  LPoints := TCryptoLibGenericArray<IECPoint>.Create(AQ, LPsubQ, AP, LPaddQ);
+  LCurve.NormalizeAll(LPoints);
+  LTable := TCryptoLibGenericArray<IECPoint>.Create(
+    LPoints[3].Negate(), LPoints[2].Negate(), LPoints[1].Negate(),
+    LPoints[0].Negate(), LInfinity, LPoints[0],
+    LPoints[1], LPoints[2], LPoints[3]);
+  LJsf := TWNafUtilities.GenerateJsf(AK, AL);
+  LR := LInfinity;
+  LI := System.Length(LJsf);
+  while LI > 0 do
+  begin
+    Dec(LI);
+    LJsfi := Int32(LJsf[LI]);
+    LKDigit := TBitOperations.Asr32(Int32(LJsfi shl 24), 28);
+    LLDigit := TBitOperations.Asr32(Int32(LJsfi shl 28), 28);
+    LIndex := 4 + (LKDigit * 3) + LLDigit;
+    LR := LR.TwicePlus(LTable[LIndex]);
+  end;
+  Result := LR;
 end;
 
-class function TECAlgorithms.ImplShamirsTrickWNaf(const p: IECPoint;
-  const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
+class function TECAlgorithms.ImplShamirsTrickWNaf(const AP: IECPoint; const AK: TBigInteger;
+  const AQ: IECPoint; const AL: TBigInteger): IECPoint;
 var
-  negK, negL: Boolean;
-  minWidthP, minWidthQ, widthP, widthQ, combSize: Int32;
-  infoP, infoQ: IWNafPreCompInfo;
-  preCompP, preCompQ, preCompNegP, preCompNegQ
-    : TCryptoLibGenericArray<IECPoint>;
-  wnafP, wnafQ: TCryptoLibByteArray;
-  kAbs, lAbs: TBigInteger;
-  c: IECCurve;
+  LNegK, LNegL: Boolean;
+  LKAbs, LLAbs: TBigInteger;
+  LCombSize, LMinWidthP, LMinWidthQ, LWidthP, LWidthQ: Int32;
+  LInfoP, LInfoQ: IWNafPreCompInfo;
+  LPreCompP, LPreCompQ, LPreCompNegP, LPreCompNegQ: TCryptoLibGenericArray<IECPoint>;
+  LWnafP, LWnafQ: TCryptoLibByteArray;
 begin
-
-  negK := k.SignValue < 0;
-  negL := l.SignValue < 0;
-
-  kAbs := k.Abs();
-  lAbs := l.Abs();
-
-  minWidthP := TWNafUtilities.GetWindowSize(kAbs.BitLength, 8);
-  minWidthQ := TWNafUtilities.GetWindowSize(lAbs.BitLength, 8);
-
-  infoP := TWNafUtilities.Precompute(p, minWidthP, true);
-  infoQ := TWNafUtilities.Precompute(q, minWidthQ, true);
-
-  // When P, Q are 'promoted' (i.e. reused several times), switch to fixed-point algorithm
-
-  c := p.Curve;
-  combSize := TFixedPointUtilities.GetCombSize(c);
-  if ((not negK) and (not negL) and (k.BitLength <= combSize) and
-    (l.BitLength <= combSize) and (infoP.IsPromoted) and (infoQ.IsPromoted))
-  then
-  begin
-    result := ImplShamirsTrickFixedPoint(p, k, q, l);
-    Exit;
-  end;
-
-  widthP := Min(8, infoP.width);
-  widthQ := Min(8, infoQ.width);
-
-  if negK then
-  begin
-    preCompP := infoP.PreCompNeg
+  LNegK := AK.SignValue < 0;
+  LNegL := AL.SignValue < 0;
+  LKAbs := AK.Abs();
+  LLAbs := AL.Abs();
+  LMinWidthP := TWNafUtilities.GetWindowSize(LKAbs.BitLength, 8);
+  LMinWidthQ := TWNafUtilities.GetWindowSize(LLAbs.BitLength, 8);
+  LInfoP := TWNafUtilities.Precompute(AP, LMinWidthP, True);
+  LInfoQ := TWNafUtilities.Precompute(AQ, LMinWidthQ, True);
+  LCombSize := TFixedPointUtilities.GetCombSize(AP.Curve);
+  if (not LNegK) and (not LNegL) and (AK.BitLength <= LCombSize) and (AL.BitLength <= LCombSize)
+    and LInfoP.IsPromoted and LInfoQ.IsPromoted then
+    Exit(ImplShamirsTrickFixedPoint(AP, AK, AQ, AL));
+  LWidthP := System.Math.Min(8, LInfoP.Width);
+  LWidthQ := System.Math.Min(8, LInfoQ.Width);
+  if LNegK then
+  begin
+    LPreCompP := LInfoP.PreCompNeg;
+    LPreCompNegP := LInfoP.PreComp;
   end
   else
   begin
-    preCompP := infoP.PreComp
+    LPreCompP := LInfoP.PreComp;
+    LPreCompNegP := LInfoP.PreCompNeg;
   end;
-
-  if negL then
+  if LNegL then
   begin
-    preCompQ := infoQ.PreCompNeg
+    LPreCompQ := LInfoQ.PreCompNeg;
+    LPreCompNegQ := LInfoQ.PreComp;
   end
   else
   begin
-    preCompQ := infoQ.PreComp
+    LPreCompQ := LInfoQ.PreComp;
+    LPreCompNegQ := LInfoQ.PreCompNeg;
   end;
+  LWnafP := TWNafUtilities.GenerateWindowNaf(LWidthP, LKAbs);
+  LWnafQ := TWNafUtilities.GenerateWindowNaf(LWidthQ, LLAbs);
+  Result := ImplShamirsTrickWNaf(LPreCompP, LPreCompNegP, LWnafP, LPreCompQ, LPreCompNegQ, LWnafQ);
+end;
 
-  if negK then
-  begin
-    preCompNegP := infoP.PreComp
+class function TECAlgorithms.ImplShamirsTrickFixedPoint(const AP: IECPoint; const AK: TBigInteger;
+  const AQ: IECPoint; const AL: TBigInteger): IECPoint;
+var
+  LC: IECCurve;
+  LCombSize, LWidthP, LWidthQ, LWidth, LD, LFullComb, LI, LJ: Int32;
+  LInfoP, LInfoQ: IFixedPointPreCompInfo;
+  LLookupTableP, LLookupTableQ: IECLookupTable;
+  LK, LL: TCryptoLibUInt32Array;
+  LSecretIndexK, LSecretIndexL: UInt32;
+  LSecretBitK, LSecretBitL: UInt32;
+  LR, LAddP, LAddQ, LT: IECPoint;
+  LMultiplier: IECMultiplier;
+begin
+  LC := AP.Curve;
+  LCombSize := TFixedPointUtilities.GetCombSize(LC);
+  if (AK.BitLength > LCombSize) or (AL.BitLength > LCombSize) then
+    raise EInvalidOperationCryptoLibException.Create(
+      'fixed-point comb doesn''t support scalars larger than the curve order');
+  LInfoP := TFixedPointUtilities.Precompute(AP);
+  LInfoQ := TFixedPointUtilities.Precompute(AQ);
+  LLookupTableP := LInfoP.LookupTable;
+  LLookupTableQ := LInfoQ.LookupTable;
+  LWidthP := LInfoP.Width;
+  LWidthQ := LInfoQ.Width;
+  if LWidthP <> LWidthQ then
+  begin
+    LMultiplier := TFixedPointCombMultiplier.Create() as IECMultiplier;
+    Result := LMultiplier.Multiply(AP, AK).Add(LMultiplier.Multiply(AQ, AL));
+    Exit;
+  end;
+  LWidth := LWidthP;
+  LD := (LCombSize + LWidth - 1) div LWidth;
+  LFullComb := LD * LWidth;
+  LK := TNat.FromBigInteger(LFullComb, AK);
+  LL := TNat.FromBigInteger(LFullComb, AL);
+  LR := LC.Infinity;
+  for LI := 1 to LD do
+  begin
+    LSecretIndexK := 0;
+    LSecretIndexL := 0;
+    LJ := LFullComb - LI;
+    while LJ >= 0 do
+    begin
+      LSecretBitK := LK[TBitOperations.Asr32(LJ, 5)] shr (LJ and $1F);
+      LSecretIndexK := LSecretIndexK xor (LSecretBitK shr 1);
+      LSecretIndexK := LSecretIndexK shl 1;
+      LSecretIndexK := LSecretIndexK xor LSecretBitK;
+
+      LSecretBitL := LL[TBitOperations.Asr32(LJ, 5)] shr (LJ and $1F);
+      LSecretIndexL := LSecretIndexL xor (LSecretBitL shr 1);
+      LSecretIndexL := LSecretIndexL shl 1;
+      LSecretIndexL := LSecretIndexL xor LSecretBitL;
+      LJ := LJ - LD;
+    end;
+    LAddP := LLookupTableP.LookupVar(Int32(LSecretIndexK));
+    LAddQ := LLookupTableQ.LookupVar(Int32(LSecretIndexL));
+    LT := LAddP.Add(LAddQ);
+    LR := LR.TwicePlus(LT);
+  end;
+  Result := LR.Add(LInfoP.Offset).Add(LInfoQ.Offset);
+end;
+
+class function TECAlgorithms.ImplShamirsTrickWNaf(const AEndomorphism: IECEndomorphism;
+  const AP: IECPoint; const AK: TBigInteger; const AL: TBigInteger): IECPoint;
+var
+  LNegK, LNegL: Boolean;
+  LK, LL: TBigInteger;
+  LMinWidth, LWidthP, LWidthQ: Int32;
+  LInfoP, LInfoQ: IWNafPreCompInfo;
+  LQ: IECPoint;
+  LPreCompP, LPreCompQ, LPreCompNegP, LPreCompNegQ: TCryptoLibGenericArray<IECPoint>;
+  LWnafP, LWnafQ: TCryptoLibByteArray;
+begin
+  LNegK := AK.SignValue < 0;
+  LNegL := AL.SignValue < 0;
+  LK := AK.Abs();
+  LL := AL.Abs();
+  LMinWidth := TWNafUtilities.GetWindowSize(System.Math.Max(LK.BitLength, LL.BitLength), 8);
+  LInfoP := TWNafUtilities.Precompute(AP, LMinWidth, True);
+  LQ := TEndoUtilities.MapPoint(AEndomorphism, AP);
+  LInfoQ := TWNafUtilities.PrecomputeWithPointMap(LQ, AEndomorphism.PointMap, LInfoP, True);
+  LWidthP := System.Math.Min(8, LInfoP.Width);
+  LWidthQ := System.Math.Min(8, LInfoQ.Width);
+  if LNegK then
+  begin
+    LPreCompP := LInfoP.PreCompNeg;
+    LPreCompNegP := LInfoP.PreComp;
   end
   else
   begin
-    preCompNegP := infoP.PreCompNeg
+    LPreCompP := LInfoP.PreComp;
+    LPreCompNegP := LInfoP.PreCompNeg;
   end;
-
-  if negL then
+  if LNegL then
   begin
-    preCompNegQ := infoQ.PreComp
+    LPreCompQ := LInfoQ.PreCompNeg;
+    LPreCompNegQ := LInfoQ.PreComp;
   end
   else
   begin
-    preCompNegQ := infoQ.PreCompNeg
+    LPreCompQ := LInfoQ.PreComp;
+    LPreCompNegQ := LInfoQ.PreCompNeg;
   end;
-
-  wnafP := TWNafUtilities.GenerateWindowNaf(widthP, kAbs);
-  wnafQ := TWNafUtilities.GenerateWindowNaf(widthQ, lAbs);
-
-  result := ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ,
-    preCompNegQ, wnafQ);
+  LWnafP := TWNafUtilities.GenerateWindowNaf(LWidthP, LK);
+  LWnafQ := TWNafUtilities.GenerateWindowNaf(LWidthQ, LL);
+  Result := ImplShamirsTrickWNaf(LPreCompP, LPreCompNegP, LWnafP, LPreCompQ, LPreCompNegQ, LWnafQ);
 end;
 
-class function TECAlgorithms.ImplShamirsTrickWNaf(const preCompP,
-  preCompNegP: TCryptoLibGenericArray<IECPoint>;
-  const wnafP: TCryptoLibByteArray;
-  const preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
-  const wnafQ: TCryptoLibByteArray): IECPoint;
+class function TECAlgorithms.ImplShamirsTrickWNaf(
+  const APreCompP, APreCompNegP: TCryptoLibGenericArray<IECPoint>;
+  const AWnafP: TCryptoLibByteArray;
+  const APreCompQ, APreCompNegQ: TCryptoLibGenericArray<IECPoint>;
+  const AWnafQ: TCryptoLibByteArray): IECPoint;
 var
-  len, zeroes, i, wiP, wiQ, nP, nQ: Int32;
-  Curve: IECCurve;
-  Infinity, R, point: IECPoint;
-  tableP, tableQ: TCryptoLibGenericArray<IECPoint>;
+  LLen, LI, LWiP, LWiQ, LZeroes, LnP, LnQ: Int32;
+  LCurve: IECCurve;
+  LInfinity, LR, LSmallR: IECPoint;
+  LTableP, LTableQ: TCryptoLibGenericArray<IECPoint>;
 begin
-  len := Max(System.length(wnafP), System.length(wnafQ));
-
-  Curve := preCompP[0].Curve;
-  Infinity := Curve.Infinity;
-
-  R := Infinity;
-  zeroes := 0;
-
-  i := len - 1;
-  while (i >= 0) do
-  begin
-
-    if i < System.length(wnafP) then
-    begin
-      wiP := Int32(ShortInt(wnafP[i]));
-    end
+  LLen := System.Math.Max(System.Length(AWnafP), System.Length(AWnafQ));
+  LCurve := APreCompP[0].Curve;
+  LInfinity := LCurve.Infinity;
+  LR := LInfinity;
+  LZeroes := 0;
+  LI := LLen;
+  while LI > 0 do
+  begin
+    Dec(LI);
+    if LI < System.Length(AWnafP) then
+      LWiP := Int32(ShortInt(AWnafP[LI]))
     else
-    begin
-      wiP := 0;
-    end;
-
-    if i < System.length(wnafQ) then
-    begin
-      wiQ := Int32(ShortInt(wnafQ[i]));
-    end
+      LWiP := 0;
+    if LI < System.Length(AWnafQ) then
+      LWiQ := Int32(ShortInt(AWnafQ[LI]))
     else
+      LWiQ := 0;
+    if (LWiP or LWiQ) = 0 then
     begin
-      wiQ := 0;
-    end;
-
-    if ((wiP or wiQ) = 0) then
-    begin
-      System.Inc(zeroes);
-      System.Dec(i);
+      Inc(LZeroes);
       continue;
     end;
-
-    point := Infinity;
-    if (wiP <> 0) then
+    LSmallR := LInfinity;
+    if LWiP <> 0 then
     begin
-      nP := System.Abs(wiP);
-      if wiP < 0 then
-      begin
-        tableP := preCompNegP;
-      end
+      LnP := System.Math.Abs(LWiP);
+      if LWiP < 0 then
+        LTableP := APreCompNegP
       else
-      begin
-        tableP := preCompP;
-      end;
-
-      point := point.Add(tableP[TBitOperations.Asr32(nP, 1)]);
+        LTableP := APreCompP;
+      LSmallR := LSmallR.Add(LTableP[TBitOperations.Asr32(LnP, 1)]);
     end;
-    if (wiQ <> 0) then
+    if LWiQ <> 0 then
     begin
-
-      nQ := System.Abs(wiQ);
-      if wiQ < 0 then
-      begin
-        tableQ := preCompNegQ;
-      end
+      LnQ := System.Math.Abs(LWiQ);
+      if LWiQ < 0 then
+        LTableQ := APreCompNegQ
       else
-      begin
-        tableQ := preCompQ;
-      end;
-
-      point := point.Add(tableQ[TBitOperations.Asr32(nQ, 1)]);
-
+        LTableQ := APreCompQ;
+      LSmallR := LSmallR.Add(LTableQ[TBitOperations.Asr32(LnQ, 1)]);
     end;
-
-    if (zeroes > 0) then
+    if LZeroes > 0 then
     begin
-      R := R.TimesPow2(zeroes);
-      zeroes := 0;
+      LR := LR.TimesPow2(LZeroes);
+      LZeroes := 0;
     end;
-
-    R := R.TwicePlus(point);
-    System.Dec(i);
-  end;
-
-  if (zeroes > 0) then
-  begin
-    R := R.TimesPow2(zeroes);
+    LR := LR.TwicePlus(LSmallR);
   end;
-
-  result := R;
+  if LZeroes > 0 then
+    LR := LR.TimesPow2(LZeroes);
+  Result := LR;
 end;
 
-class function TECAlgorithms.ImplSumOfMultiplies(const endomorphism
-  : IECEndomorphism; const ps: TCryptoLibGenericArray<IECPoint>;
-  const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
+class function TECAlgorithms.ImplSumOfMultiplies(const APs: TCryptoLibGenericArray<IECPoint>;
+  const AKs: TCryptoLibGenericArray<TBigInteger>): IECPoint;
 var
-  halfCount, fullCount: Int32;
-  negs: TCryptoLibBooleanArray;
-  infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
-  infoP, infoQ: IWNafPreCompInfo;
-  wnafs: TCryptoLibMatrixByteArray;
-  i, j0, j1, minWidth, widthP, widthQ: Int32;
-  kj0, kj1: TBigInteger;
-  p, q: IECPoint;
-  pointMap: IECPointMap;
+  LCount, I, LMinWidth, LWidth: Int32;
+  LKi: TBigInteger;
+  LNegs: TCryptoLibBooleanArray;
+  LInfos: TCryptoLibGenericArray<IWNafPreCompInfo>;
+  LWnafs: TCryptoLibGenericArray<TCryptoLibByteArray>;
 begin
-  halfCount := System.length(ps);
-  fullCount := halfCount shl 1;
-  System.SetLength(negs, fullCount);
-  System.SetLength(infos, fullCount);
-  System.SetLength(wnafs, fullCount);
-
-  pointMap := endomorphism.pointMap;
-
-  for i := 0 to System.Pred(halfCount) do
-  begin
-    j0 := i shl 1;
-    j1 := j0 + 1;
-
-    kj0 := ks[j0];
-    negs[j0] := kj0.SignValue < 0;
-    kj0 := kj0.Abs();
-    kj1 := ks[j1];
-    negs[j1] := kj1.SignValue < 0;
-    kj1 := kj1.Abs();
-
-    minWidth := TWNafUtilities.GetWindowSize
-      (Max(kj0.BitLength, kj1.BitLength), 8);
-
-    p := ps[i];
-    infoP := TWNafUtilities.Precompute(p, minWidth, true);
-    q := TEndoUtilities.MapPoint(endomorphism, p);
-    infoQ := TWNafUtilities.PrecomputeWithPointMap(q, pointMap, infoP, true);
-
-    widthP := Min(8, infoP.width);
-    widthQ := Min(8, infoQ.width);
-
-    infos[j0] := infoP;
-    infos[j1] := infoQ;
-    wnafs[j0] := TWNafUtilities.GenerateWindowNaf(widthP, kj0);
-    wnafs[j1] := TWNafUtilities.GenerateWindowNaf(widthQ, kj1);
-  end;
-
-  result := ImplSumOfMultiplies(negs, infos, wnafs);
+  LCount := System.Length(APs);
+  System.SetLength(LNegs, LCount);
+  System.SetLength(LInfos, LCount);
+  System.SetLength(LWnafs, LCount);
+  for I := 0 to LCount - 1 do
+  begin
+    LKi := AKs[I];
+    LNegs[I] := LKi.SignValue < 0;
+    LKi := LKi.Abs();
+    LMinWidth := TWNafUtilities.GetWindowSize(LKi.BitLength, 8);
+    LInfos[I] := TWNafUtilities.Precompute(APs[I], LMinWidth, True);
+    LWidth := System.Math.Min(8, LInfos[I].Width);
+    LWnafs[I] := TWNafUtilities.GenerateWindowNaf(LWidth, LKi);
+  end;
+  Result := ImplSumOfMultiplies(LNegs, LInfos, LWnafs);
 end;
 
-class function TECAlgorithms.ImplSumOfMultiplies
-  (const ps: TCryptoLibGenericArray<IECPoint>;
-  const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
+class function TECAlgorithms.ImplSumOfMultipliesGlv(const APs: TCryptoLibGenericArray<IECPoint>;
+  const AKs: TCryptoLibGenericArray<TBigInteger>;
+  const AGlvEndomorphism: IGlvEndomorphism): IECPoint;
 var
-  count, i, width, minWidth: Int32;
-  negs: TCryptoLibBooleanArray;
-  info: IWNafPreCompInfo;
-  infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
-  wnafs: TCryptoLibMatrixByteArray;
-  ki: TBigInteger;
+  LN: TBigInteger;
+  LLen, I, J: Int32;
+  LAbs: TCryptoLibGenericArray<TBigInteger>;
+  LAbPair: TCryptoLibGenericArray<TBigInteger>;
+  LPqs: TCryptoLibGenericArray<IECPoint>;
+  LP: IECPoint;
 begin
-  count := System.length(ps);
-  System.SetLength(negs, count);
-
-  System.SetLength(infos, count);
-
-  System.SetLength(wnafs, count);
-
-  for i := 0 to System.Pred(count) do
+  LN := APs[0].Curve.Order;
+  LLen := System.Length(APs);
+  System.SetLength(LAbs, LLen shl 1);
+  J := 0;
+  for I := 0 to LLen - 1 do
+  begin
+    LAbPair := AGlvEndomorphism.DecomposeScalar(AKs[I].Mod(LN));
+    LAbs[J] := LAbPair[0];
+    Inc(J);
+    LAbs[J] := LAbPair[1];
+    Inc(J);
+  end;
+  if AGlvEndomorphism.HasEfficientPointMap then
+    Result := ImplSumOfMultiplies(AGlvEndomorphism as IECEndomorphism, APs, LAbs)
+  else
   begin
-    ki := ks[i];
-    negs[i] := ki.SignValue < 0;
-    ki := ki.Abs();
-
-    minWidth := TWNafUtilities.GetWindowSize(ki.BitLength, 8);
-    info := TWNafUtilities.Precompute(ps[i], minWidth, true);
-    width := Min(8, info.width);
-
-    infos[i] := info;
-    wnafs[i] := TWNafUtilities.GenerateWindowNaf(width, ki);
+    System.SetLength(LPqs, LLen shl 1);
+    J := 0;
+    for I := 0 to LLen - 1 do
+    begin
+      LP := APs[I];
+      LPqs[J] := LP;
+      Inc(J);
+      LPqs[J] := TEndoUtilities.MapPoint(AGlvEndomorphism as IECEndomorphism, LP);
+      Inc(J);
+    end;
+    Result := ImplSumOfMultiplies(LPqs, LAbs);
   end;
-
-  result := ImplSumOfMultiplies(negs, infos, wnafs);
 end;
 
-class function TECAlgorithms.ImplSumOfMultiplies
-  (const negs: TCryptoLibBooleanArray;
-  const infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
-  const wnafs: TCryptoLibMatrixByteArray): IECPoint;
+class function TECAlgorithms.ImplSumOfMultiplies(const AEndomorphism: IECEndomorphism;
+  const APs: TCryptoLibGenericArray<IECPoint>;
+  const AKs: TCryptoLibGenericArray<TBigInteger>): IECPoint;
 var
-  len, count, zeroes: Int32;
-  i, j, wi, n: Int32;
-  Curve: IECCurve;
-  Infinity, R, point: IECPoint;
-  wnaf: TCryptoLibByteArray;
-  info: IWNafPreCompInfo;
-  table: TCryptoLibGenericArray<IECPoint>;
+  LHalfCount, LFullCount, I, J0, J1: Int32;
+  LKj0, LKj1: TBigInteger;
+  LNegs: TCryptoLibBooleanArray;
+  LInfos: TCryptoLibGenericArray<IWNafPreCompInfo>;
+  LWnafs: TCryptoLibGenericArray<TCryptoLibByteArray>;
+  LMinWidth, LWidthP, LWidthQ: Int32;
+  LP, LQ: IECPoint;
+  LPointMap: IECPointMap;
+  LInfoP, LInfoQ: IWNafPreCompInfo;
 begin
-  len := 0;
-  count := System.length(wnafs);
-
-  for i := 0 to System.Pred(count) do
-  begin
-    len := Max(len, System.length(wnafs[i]));
-  end;
-
-  Curve := infos[0].PreComp[0].Curve;
-  Infinity := Curve.Infinity;
-
-  R := Infinity;
-  zeroes := 0;
-
-  i := len - 1;
-  while (i >= 0) do
-  begin
-    point := Infinity;
+  LHalfCount := System.Length(APs);
+  LFullCount := LHalfCount shl 1;
+  System.SetLength(LNegs, LFullCount);
+  System.SetLength(LInfos, LFullCount);
+  System.SetLength(LWnafs, LFullCount);
+  for I := 0 to LHalfCount - 1 do
+  begin
+    J0 := I shl 1;
+    J1 := J0 + 1;
+    LKj0 := AKs[J0];
+    LNegs[J0] := LKj0.SignValue < 0;
+    LKj0 := LKj0.Abs();
+    LKj1 := AKs[J1];
+    LNegs[J1] := LKj1.SignValue < 0;
+    LKj1 := LKj1.Abs();
+    LMinWidth := TWNafUtilities.GetWindowSize(
+      System.Math.Max(LKj0.BitLength, LKj1.BitLength), 8);
+    LP := APs[I];
+    LInfoP := TWNafUtilities.Precompute(LP, LMinWidth, True);
+    LQ := TEndoUtilities.MapPoint(AEndomorphism, LP);
+    LPointMap := AEndomorphism.PointMap;
+    LInfoQ := TWNafUtilities.PrecomputeWithPointMap(LQ, LPointMap, LInfoP, True);
+    LWidthP := System.Math.Min(8, LInfoP.Width);
+    LWidthQ := System.Math.Min(8, LInfoQ.Width);
+    LInfos[J0] := LInfoP;
+    LInfos[J1] := LInfoQ;
+    LWnafs[J0] := TWNafUtilities.GenerateWindowNaf(LWidthP, LKj0);
+    LWnafs[J1] := TWNafUtilities.GenerateWindowNaf(LWidthQ, LKj1);
+  end;
+  Result := ImplSumOfMultiplies(LNegs, LInfos, LWnafs);
+end;
 
-    for j := 0 to System.Pred(count) do
+class function TECAlgorithms.ImplSumOfMultiplies(
+  const ANegs: TCryptoLibBooleanArray;
+  const AInfos: TCryptoLibGenericArray<IWNafPreCompInfo>;
+  const AWnafs: TCryptoLibGenericArray<TCryptoLibByteArray>): IECPoint;
+var
+  LLen, LCount, I, J, LWi, LN, LZeroes: Int32;
+  LCurve: IECCurve;
+  LInfinity, LR, LSmallR: IECPoint;
+  LWnaf: TCryptoLibByteArray;
+  LInfo: IWNafPreCompInfo;
+  LTable: TCryptoLibGenericArray<IECPoint>;
+begin
+  LLen := 0;
+  LCount := System.Length(AWnafs);
+  for I := 0 to LCount - 1 do
+    LLen := System.Math.Max(LLen, System.Length(AWnafs[I]));
+  LCurve := AInfos[0].PreComp[0].Curve;
+  LInfinity := LCurve.Infinity;
+  LR := LInfinity;
+  LZeroes := 0;
+  I := LLen;
+  while I > 0 do
+  begin
+    Dec(I);
+    LSmallR := LInfinity;
+    for J := 0 to LCount - 1 do
     begin
-      wnaf := wnafs[j];
-      if i < System.length(wnaf) then
-      begin
-        wi := Int32(ShortInt(wnaf[i]));
-      end
+      LWnaf := AWnafs[J];
+      if I < System.Length(LWnaf) then
+        LWi := Int32(ShortInt(LWnaf[I]))
       else
+        LWi := 0;
+      if LWi <> 0 then
       begin
-        wi := 0;
-      end;
-
-      if (wi <> 0) then
-      begin
-        n := System.Abs(wi);
-        info := infos[j];
-        if (wi < 0 = negs[j]) then
-        begin
-          table := info.PreComp;
-        end
+        LN := System.Math.Abs(LWi);
+        LInfo := AInfos[J];
+        if (LWi < 0) = ANegs[J] then
+          LTable := LInfo.PreComp
         else
-        begin
-          table := info.PreCompNeg;
-        end;
-
-        point := point.Add(table[TBitOperations.Asr32(n, 1)]);
+          LTable := LInfo.PreCompNeg;
+        LSmallR := LSmallR.Add(LTable[TBitOperations.Asr32(LN, 1)]);
       end;
     end;
-
-    if (point = Infinity) then
+    if LSmallR = LInfinity then
     begin
-      System.Inc(zeroes);
-      System.Dec(i);
+      Inc(LZeroes);
       continue;
     end;
-
-    if (zeroes > 0) then
-    begin
-      R := R.TimesPow2(zeroes);
-      zeroes := 0;
-    end;
-
-    R := R.TwicePlus(point);
-
-    System.Dec(i);
-  end;
-
-  if (zeroes > 0) then
-  begin
-    R := R.TimesPow2(zeroes);
-  end;
-
-  result := R;
-
-end;
-
-class function TECAlgorithms.ImplSumOfMultipliesGlv
-  (const ps: TCryptoLibGenericArray<IECPoint>;
-  const ks: TCryptoLibGenericArray<TBigInteger>;
-  const glvEndomorphism: IGlvEndomorphism): IECPoint;
-var
-  n: TBigInteger;
-  len, i, j: Int32;
-  &abs, ab: TCryptoLibGenericArray<TBigInteger>;
-  pqs: TCryptoLibGenericArray<IECPoint>;
-  p, q: IECPoint;
-begin
-  n := ps[0].Curve.Order;
-
-  len := System.length(ps);
-
-  System.SetLength(Abs, len shl 1);
-
-  i := 0;
-  j := 0;
-
-  while (i < len) do
-  begin
-    ab := glvEndomorphism.DecomposeScalar(ks[i].&Mod(n));
-
-    Abs[j] := ab[0];
-    System.Inc(j);
-    Abs[j] := ab[1];
-    System.Inc(j);
-    System.Inc(i);
-  end;
-
-  if (glvEndomorphism.HasEfficientPointMap) then
-  begin
-    result := ImplSumOfMultiplies(glvEndomorphism, ps, Abs);
-    Exit;
-  end;
-
-  System.SetLength(pqs, len shl 1);
-
-  i := 0;
-  j := 0;
-
-  while (i < len) do
-  begin
-    p := ps[i];
-    q := TEndoUtilities.MapPoint(glvEndomorphism, p);
-
-    pqs[j] := p;
-    System.Inc(j);
-    pqs[j] := q;
-    System.Inc(j);
-    System.Inc(i);
-  end;
-
-  result := ImplSumOfMultiplies(pqs, Abs);
-end;
-
-class function TECAlgorithms.ImportPoint(const c: IECCurve; const p: IECPoint)
-  : IECPoint;
-var
-  cp: IECCurve;
-begin
-  cp := p.Curve;
-  if (not c.Equals(cp)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointLocation);
-  end;
-
-  result := c.ImportPoint(p);
-end;
-
-class function TECAlgorithms.IsF2mField(const field: IFiniteField): Boolean;
-begin
-  result := (field.Dimension > 1) and
-    (field.Characteristic.Equals(TBigInteger.Two)) and
-    (Supports(field, IPolynomialExtensionField));
-end;
-
-class function TECAlgorithms.IsF2mCurve(const c: IECCurve): Boolean;
-begin
-  result := IsF2mField(c.field);
-end;
-
-class function TECAlgorithms.IsFpField(const field: IFiniteField): Boolean;
-begin
-  result := field.Dimension = 1;
-end;
-
-class function TECAlgorithms.IsFpCurve(const c: IECCurve): Boolean;
-begin
-  result := IsFpField(c.field);
-end;
-
-class procedure TECAlgorithms.MontgomeryTrick
-  (const zs: TCryptoLibGenericArray<IECFieldElement>; off, len: Int32;
-  const scale: IECFieldElement);
-var
-  c: TCryptoLibGenericArray<IECFieldElement>;
-  i, j: Int32;
-  u, tmp: IECFieldElement;
-begin
-  // /*
-  // * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
-  // * field inversion. See e.g. the paper:
-  // * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
-  // * by Katsuyuki Okeya, Kouichi Sakurai.
-  // */
-
-  System.SetLength(c, len);
-
-  c[0] := zs[off];
-
-  i := 0;
-  System.Inc(i);
-  while (i < len) do
-  begin
-    c[i] := c[i - 1].Multiply(zs[off + i]);
-    System.Inc(i);
-  end;
-  System.Dec(i);
-
-  if (scale <> Nil) then
-  begin
-    c[i] := c[i].Multiply(scale);
-  end;
-
-  u := c[i].Invert();
-
-  while (i > 0) do
-  begin
-    j := off + i;
-    System.Dec(i);
-    tmp := zs[j];
-    zs[j] := c[i].Multiply(u);
-    u := u.Multiply(tmp);
-  end;
-
-  zs[off] := u;
-end;
-
-class procedure TECAlgorithms.MontgomeryTrick
-  (const zs: TCryptoLibGenericArray<IECFieldElement>; off, len: Int32);
-begin
-  MontgomeryTrick(zs, off, len, Nil);
-end;
-
-class function TECAlgorithms.ReferenceMultiply(const p: IECPoint;
-  const k: TBigInteger): IECPoint;
-var
-  x: TBigInteger;
-  q, LP: IECPoint;
-  t, i: Int32;
-begin
-  LP := p;
-  x := k.Abs();
-  q := LP.Curve.Infinity;
-  t := x.BitLength;
-  if (t > 0) then
-  begin
-    if (x.TestBit(0)) then
-    begin
-      q := LP;
-    end;
-    i := 1;
-    while (i < t) do
+    if LZeroes > 0 then
     begin
-      LP := LP.Twice();
-      if (x.TestBit(i)) then
-      begin
-        q := q.Add(LP);
-      end;
-      System.Inc(i);
+      LR := LR.TimesPow2(LZeroes);
+      LZeroes := 0;
     end;
-
+    LR := LR.TwicePlus(LSmallR);
   end;
-
-  if k.SignValue < 0 then
-  begin
-    result := q.Negate();
-  end
-  else
-  begin
-    result := q;
-  end;
-
-end;
-
-class function TECAlgorithms.ShamirsTrick(const p: IECPoint;
-  const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
-var
-  cp: IECCurve;
-  LQ: IECPoint;
-begin
-  cp := p.Curve;
-  LQ := q;
-  LQ := ImportPoint(cp, LQ);
-
-  result := ImplCheckResult(ImplShamirsTrickJsf(p, k, LQ, l));
-end;
-
-class function TECAlgorithms.SumOfMultiplies
-  (const ps: TCryptoLibGenericArray<IECPoint>;
-  const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
-var
-  count: Int32;
-  p: IECPoint;
-  c: IECCurve;
-  i: Int32;
-  imported: TCryptoLibGenericArray<IECPoint>;
-  glvEndomorphism: IGlvEndomorphism;
-begin
-  if ((ps = Nil) or (ks = Nil) or (System.length(ps) <> System.length(ks)) or
-    (System.length(ps) < 1)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidArray);
-  end;
-
-  count := System.length(ps);
-
-  case count of
-    1:
-      begin
-        result := ps[0].Multiply(ks[0]);
-        Exit;
-      end;
-
-    2:
-      begin
-        result := SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
-        Exit;
-      end;
-
-  end;
-
-  p := ps[0];
-  c := p.Curve;
-  System.SetLength(imported, count);
-  imported[0] := p;
-
-  for i := 1 to System.Pred(count) do
-  begin
-    imported[i] := ImportPoint(c, ps[i]);
-  end;
-
-  if Supports(c.GetEndomorphism(), IGlvEndomorphism, glvEndomorphism) then
-  begin
-    result := ImplCheckResult(ImplSumOfMultipliesGlv(imported, ks,
-      glvEndomorphism));
-    Exit;
-  end;
-
-  result := ImplCheckResult(ImplSumOfMultiplies(imported, ks));
-end;
-
-class function TECAlgorithms.SumOfTwoMultiplies(const p: IECPoint;
-  const a: TBigInteger; const q: IECPoint; const b: TBigInteger): IECPoint;
-var
-  cp: IECCurve;
-  f2mCurve: IAbstractF2mCurve;
-  glvEndomorphism: IGlvEndomorphism;
-  LQ: IECPoint;
-begin
-  cp := p.Curve;
-  LQ := q;
-  LQ := ImportPoint(cp, LQ);
-
-  // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
-
-  if (Supports(cp, IAbstractF2mCurve, f2mCurve) and (f2mCurve.IsKoblitz)) then
-  begin
-    result := ImplCheckResult(p.Multiply(a).Add(LQ.Multiply(b)));
-    Exit;
-  end;
-
-  if Supports(cp.GetEndomorphism(), IGlvEndomorphism, glvEndomorphism) then
-  begin
-    result := ImplCheckResult
-      (ImplSumOfMultipliesGlv(TCryptoLibGenericArray<IECPoint>.Create(p, LQ),
-      TCryptoLibGenericArray<TBigInteger>.Create(a, b), glvEndomorphism));
-    Exit;
-  end;
-
-  result := ImplCheckResult(ImplShamirsTrickWNaf(p, a, LQ, b));
+  if LZeroes > 0 then
+    LR := LR.TimesPow2(LZeroes);
+  Result := LR;
 end;
 
 end.

+ 0 - 6809
CryptoLib/src/Math/EC/ClpECC.pas

@@ -1,6809 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpECC;
-
-{$I ..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  Classes,
-  SyncObjs,
-  SysUtils,
-  Generics.Collections,
-  ClpArrayUtilities,
-  ClpIPreCompCallback,
-  ClpCryptoLibTypes,
-  ClpBigInteger,
-  ClpBigIntegers,
-  ClpBitOperations,
-  ClpIGlvEndomorphism,
-  ClpECAlgorithms,
-  ClpLongArray,
-  ClpMultipliers,
-  ClpFiniteFields,
-  ClpWeakRef,
-  ClpECCurveConstants,
-  ClpTnaf,
-  ClpValidityPreCompInfo,
-  ClpIValidityPreCompInfo,
-  ClpIWNafPreCompInfo,
-  ClpIEndoPreCompInfo,
-  ClpIWTauNafPreCompInfo,
-  ClpIFixedPointPreCompInfo,
-  ClpIECC,
-  ClpIFiniteField,
-  ClpIPreCompInfo;
-
-resourcestring
-  SInvalidValue = 'Value Invalid in Fp Field Element, " x "';
-  SInvalidValue2 = 'Value Invalid in F2m Field Element, "x"';
-  SInvalidK2Value = 'k2 must be smaller than k3';
-  SInvalidK2Value2 = 'k2 must be larger than 0';
-  SInvalidFieldElement =
-    'Field elements are not both instances of F2mFieldElement';
-  SInvalidFieldElements =
-    'Field elements are not elements of the same field F2m';
-  SIncorrectRepresentation =
-    'One of the F2m field elements has incorrect representation';
-  SEvenValue = 'Even Value of Q';
-  STraceInternalErrorCalculation = 'Internal Error in Trace Calculation';
-  SHalfTraceUndefinedForM = 'Half-Trace Only Defined For Odd M';
-  SUnSupportedCoordinateSystem = 'UnSupported Coordinate System';
-  SCurrentCurve = 'Implementation returned Current Curve';
-  SInvalidPointCoordinates = 'Invalid Point Coordinates';
-  SInvalidAffineCoordinates = 'not valid for affine coordinates, "iso"';
-  SInvalidPointOnCurve = 'must be non-null and on this curve, "point"';
-  SInvalidPointOnCurve2 = 'Entries must be null or on this curve, "points"';
-  SPointsNil = 'points';
-  SInvalidRangeSpecified = 'Invalid Range Specified", "points"';
-  SInvalidPointCompression = 'Invalid Point Compression';
-  SInvalidK1 = 'k1 must be > 0';
-  SInvalidK3 = 'k3 must be 0 if k2 == 0';
-  SK2K1MisMatch = 'k2 must be > k1';
-  SK3K2Mismatch = 'k3 must be > k2';
-  SInvalidInfinityEncoding = 'Invalid Infinity Encoding, "encoded"';
-  SInvalidPointEncoding = 'Invalid Point Encoding %u';
-  SIncorrectLengthInfinityEncoding =
-    'Incorrect Length for infinity encoding", "encoded"';
-  SIncorrectLengthCompressedEncoding =
-    'Incorrect Length for Compressed Encoding", "encoded"';
-  SInvalidPoint = 'Invalid Point';
-  SIncorrectLengthUnCompressedEncoding =
-    'Incorrect Length for UnCompressed Encoding", "encoded"';
-  SIncorrectLengthHybridEncoding =
-    'Incorrect Length for Hybrid Encoding", "encoded"';
-  SInConsistentYCoord =
-    'Inconsistent Y Coordinate in Hybrid Encoding", "encoded"';
-  SUnknownCoordSystem = 'Unknown Coordinate System';
-  SPointNotInNormalForm = 'Point not in Normal Form';
-  SNotProjectiveCoordSystem = 'Not a Projective Coordinate System';
-  SCannotBeNegative = 'Cannot be Negative, "e"';
-  SNilFieldElement = 'Exactly one of the Field Elements is Nil';
-  SUnsupportedOperation = 'Constant-time Lookup not Supported';
-
-type
-  TECFieldElement = class abstract(TInterfacedObject, IECFieldElement)
-
-  strict protected
-
-    function GetBitLength: Int32; virtual;
-    function GetIsOne: Boolean; virtual;
-    function GetIsZero: Boolean; virtual;
-
-    function GetFieldName: String; virtual; abstract;
-    function GetFieldSize: Int32; virtual; abstract;
-
-  public
-
-    constructor Create();
-    destructor Destroy; override;
-
-    function ToBigInteger(): TBigInteger; virtual; abstract;
-    function Add(const b: IECFieldElement): IECFieldElement; virtual; abstract;
-    function AddOne(): IECFieldElement; virtual; abstract;
-    function Subtract(const b: IECFieldElement): IECFieldElement;
-      virtual; abstract;
-    function Multiply(const b: IECFieldElement): IECFieldElement;
-      virtual; abstract;
-    function Divide(const b: IECFieldElement): IECFieldElement;
-      virtual; abstract;
-    function Negate(): IECFieldElement; virtual; abstract;
-    function Square(): IECFieldElement; virtual; abstract;
-    function Invert(): IECFieldElement; virtual; abstract;
-    function Sqrt(): IECFieldElement; virtual; abstract;
-
-    function MultiplyMinusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; virtual;
-
-    function MultiplyPlusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; virtual;
-
-    function SquareMinusProduct(const x, y: IECFieldElement)
-      : IECFieldElement; virtual;
-
-    function SquarePlusProduct(const x, y: IECFieldElement)
-      : IECFieldElement; virtual;
-
-    function SquarePow(pow: Int32): IECFieldElement; virtual;
-
-    function TestBitZero(): Boolean; virtual;
-
-    function Equals(const other: IECFieldElement): Boolean;
-      reintroduce; virtual;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    function ToString(): String; override;
-
-    function GetEncoded(): TCryptoLibByteArray; virtual;
-    function GetEncodedLength(): Int32; virtual;
-
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-    property BitLength: Int32 read GetBitLength;
-    property IsOne: Boolean read GetIsOne;
-    property IsZero: Boolean read GetIsZero;
-
-  end;
-
-type
-  TAbstractFpFieldElement = class abstract(TECFieldElement,
-    IAbstractFpFieldElement)
-
-  end;
-
-type
-  TFpFieldElement = class(TAbstractFpFieldElement, IFpFieldElement)
-
-  strict private
-    Fq, Fr, Fx: TBigInteger;
-
-    function GetQ: TBigInteger; inline;
-
-    function CheckSqrt(const z: IECFieldElement): IECFieldElement; inline;
-    function LucasSequence(const P, Q, K: TBigInteger)
-      : TCryptoLibGenericArray<TBigInteger>;
-
-  strict protected
-    function ModAdd(const x1, x2: TBigInteger): TBigInteger; virtual;
-    function ModDouble(const x: TBigInteger): TBigInteger; virtual;
-    function ModHalf(const x: TBigInteger): TBigInteger; virtual;
-    function ModHalfAbs(const x: TBigInteger): TBigInteger; virtual;
-    function ModInverse(const x: TBigInteger): TBigInteger; virtual;
-    function ModMult(const x1, x2: TBigInteger): TBigInteger; virtual;
-    function ModReduce(const x: TBigInteger): TBigInteger; virtual;
-    function ModSubtract(const x1, x2: TBigInteger): TBigInteger; virtual;
-
-    /// <summary>
-    /// return the field name for this field.
-    /// </summary>
-    /// <returns>
-    /// return the string "Fp".
-    /// </returns>
-    function GetFieldName: String; override;
-    function GetFieldSize: Int32; override;
-
-  public
-    constructor Create(const Q, x: TBigInteger); overload;
-      deprecated 'Use ECCurve.FromBigInteger to construct field elements';
-
-    constructor Create(const Q, r, x: TBigInteger); overload;
-
-    destructor Destroy; override;
-
-    function ToBigInteger(): TBigInteger; override;
-
-    function Add(const b: IECFieldElement): IECFieldElement; override;
-    function AddOne(): IECFieldElement; override;
-    function Subtract(const b: IECFieldElement): IECFieldElement; override;
-
-    function Multiply(const b: IECFieldElement): IECFieldElement; override;
-    function Divide(const b: IECFieldElement): IECFieldElement; override;
-    function Negate(): IECFieldElement; override;
-    function Square(): IECFieldElement; override;
-
-    function Invert(): IECFieldElement; override;
-
-    /// <summary>
-    /// return a sqrt root - the routine verifies that the calculation
-    /// </summary>
-    /// <returns>
-    /// returns the right value - if none exists it returns null.
-    /// </returns>
-    function Sqrt(): IECFieldElement; override;
-
-    function MultiplyMinusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; override;
-    function MultiplyPlusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; override;
-
-    function SquareMinusProduct(const x, y: IECFieldElement)
-      : IECFieldElement; override;
-
-    function SquarePlusProduct(const x, y: IECFieldElement)
-      : IECFieldElement; override;
-
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    property Q: TBigInteger read GetQ;
-
-    function Equals(const other: IFpFieldElement): Boolean;
-      reintroduce; overload;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    class function CalculateResidue(const P: TBigInteger): TBigInteger; static;
-
-  end;
-
-type
-  TAbstractF2mFieldElement = class abstract(TECFieldElement,
-    IAbstractF2mFieldElement)
-
-  public
-    function Trace(): Int32; virtual;
-    function HalfTrace(): IECFieldElement; virtual;
-    function HasFastTrace(): Boolean; virtual;
-
-  end;
-
-type
-  /// **
-  // * Class representing the Elements of the finite field
-  // * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
-  // * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial
-  // * basis representations are supported. Gaussian normal basis (GNB)
-  // * representation is not supported.
-  // */
-  TF2mFieldElement = class(TAbstractF2mFieldElement, IF2mFieldElement)
-
-  strict private
-
-  var
-    Frepresentation, Fm: Int32;
-    FKs: TCryptoLibInt32Array;
-    Fx: TLongArray;
-    // /**
-    // * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
-    // */
-    function GetM: Int32; inline;
-    /// <summary>
-    /// Tpb or Ppb.
-    /// </summary>
-    function GetRepresentation: Int32; inline;
-    function GetKs: TCryptoLibInt32Array; inline;
-    function GetX: TLongArray; inline;
-
-    function GetK1: Int32; inline;
-    function GetK2: Int32; inline;
-    function GetK3: Int32; inline;
-
-  strict protected
-
-    function GetBitLength: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
-    function GetFieldName: String; override;
-    function GetFieldSize: Int32; override;
-
-  public
-
-    const
-
-    /// <summary>
-    /// Indicates gaussian normal basis representation (GNB). Number
-    /// chosen according to X9.62. GNB is not implemented at present. <br />
-    /// </summary>
-    Gnb = Int32(1);
-
-    /// <summary>
-    /// Indicates trinomial basis representation (Tpb). Number chosen
-    /// according to X9.62. <br />
-    /// </summary>
-    Tpb = Int32(2);
-
-    /// <summary>
-    /// Indicates pentanomial basis representation (Ppb). Number chosen
-    /// according to X9.62. <br />
-    /// </summary>
-    Ppb = Int32(3);
-
-    // /**
-    // * Constructor for Ppb.
-    // * @param m  The exponent <code>m</code> of
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param x The BigInteger representing the value of the field element.
-    // */
-    constructor Create(m, k1, k2, k3: Int32; const x: TBigInteger); overload;
-      deprecated 'Use ECCurve.FromBigInteger to construct field elements';
-    // /**
-    // * Constructor for Tpb.
-    // * @param m  The exponent <code>m</code> of
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
-    // * x<sup>k</sup> + 1</code> represents the reduction
-    // * polynomial <code>f(z)</code>.
-    // * @param x The BigInteger representing the value of the field element.
-    // */
-    constructor Create(m, K: Int32; const x: TBigInteger); overload;
-      deprecated 'Use ECCurve.FromBigInteger to construct field elements';
-
-    constructor Create(m: Int32; const ks: TCryptoLibInt32Array;
-      const x: TLongArray); overload;
-
-    destructor Destroy; override;
-
-    function TestBitZero(): Boolean; override;
-    function ToBigInteger(): TBigInteger; override;
-
-    function Add(const b: IECFieldElement): IECFieldElement; override;
-    function AddOne(): IECFieldElement; override;
-    function Subtract(const b: IECFieldElement): IECFieldElement; override;
-
-    function Multiply(const b: IECFieldElement): IECFieldElement; override;
-    function Divide(const b: IECFieldElement): IECFieldElement; override;
-    function Negate(): IECFieldElement; override;
-    function Square(): IECFieldElement; override;
-
-    function Invert(): IECFieldElement; override;
-
-    /// <summary>
-    /// return a sqrt root - the routine verifies that the calculation
-    /// </summary>
-    /// <returns>
-    /// returns the right value - if none exists it returns null.
-    /// </returns>
-    function Sqrt(): IECFieldElement; override;
-
-    function MultiplyMinusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; override;
-    function MultiplyPlusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; override;
-
-    function SquareMinusProduct(const x, y: IECFieldElement)
-      : IECFieldElement; override;
-
-    function SquarePlusProduct(const x, y: IECFieldElement)
-      : IECFieldElement; override;
-
-    function SquarePow(pow: Int32): IECFieldElement; override;
-
-    function Equals(const other: IF2mFieldElement): Boolean;
-      reintroduce; overload;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    // /**
-    // * Checks, if the ECFieldElements <code>a</code> and <code>b</code>
-    // * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
-    // * (having the same representation).
-    // * @param a field element.
-    // * @param b field element to be compared.
-    // * @throws ArgumentException if <code>a</code> and <code>b</code>
-    // * are not elements of the same field
-    // * <code>F<sub>2<sup>m</sup></sub></code> (having the same
-    // * representation).
-    // */
-    class procedure CheckFieldElements(const a, b: IECFieldElement); static;
-
-    // /**
-    // * @return the representation of the field
-    // * <code>F<sub>2<sup>m</sup></sub></code>, either of
-    // * {@link F2mFieldElement.Tpb} (trinomial
-    // * basis representation) or
-    // * {@link F2mFieldElement.Ppb} (pentanomial
-    // * basis representation).
-    // */
-    property Representation: Int32 read GetRepresentation;
-
-    // /**
-    // * @return the degree <code>m</code> of the reduction polynomial
-    // * <code>f(z)</code>.
-    // */
-    property m: Int32 read GetM;
-    // /**
-    // * @return Tpb: The integer <code>k</code> where <code>x<sup>m</sup> +
-    // * x<sup>k</sup> + 1</code> represents the reduction polynomial
-    // * <code>f(z)</code>.<br/>
-    // * Ppb: The integer <code>k1</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    property k1: Int32 read GetK1;
-    // /**
-    // * @return Tpb: Always returns <code>0</code><br/>
-    // * Ppb: The integer <code>k2</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    property k2: Int32 read GetK2;
-    // /**
-    // * @return Tpb: Always set to <code>0</code><br/>
-    // * Ppb: The integer <code>k3</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    property k3: Int32 read GetK3;
-
-    property ks: TCryptoLibInt32Array read GetKs;
-
-    /// <summary>
-    /// The <c>LongArray</c> holding the bits.
-    /// </summary>
-    property x: TLongArray read GetX;
-
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-    property BitLength: Int32 read GetBitLength;
-    property IsOne: Boolean read GetIsOne;
-    property IsZero: Boolean read GetIsZero;
-
-  end;
-
-type
-
-  /// <summary>
-  /// Base class for an elliptic curve.
-  /// </summary>
-  TECCurve = class abstract(TInterfacedObject, IECCurve)
-
-  strict protected
-
-  var
-    FLock: TCriticalSection;
-    Fm_field: IFiniteField;
-    Fm_order, Fm_cofactor: TBigInteger;
-
-    Fm_coord: Int32;
-
-    Fm_endomorphism: IECEndomorphism;
-    Fm_multiplier: IECMultiplier;
-    Fm_a, Fm_b: IECFieldElement;
-
-    constructor Create(const field: IFiniteField);
-
-    procedure SetCoord(const Value: Int32); inline;
-    procedure SetEndomorphism(const Value: IECEndomorphism); inline;
-    procedure SetMultiplier(const Value: IECMultiplier); inline;
-    function GetField: IFiniteField; virtual;
-    function GetA: IECFieldElement; virtual;
-    function GetB: IECFieldElement; virtual;
-    function GetOrder: TBigInteger; virtual;
-    function GetCofactor: TBigInteger; virtual;
-    function GetCoordinateSystem: Int32; virtual;
-    function GetFieldElementEncodingLength: Int32; virtual;
-
-    function GetFieldSize: Int32; virtual; abstract;
-    function GetInfinity: IECPoint; virtual; abstract;
-
-    function CloneCurve(): IECCurve; virtual; abstract;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      withCompression: Boolean): IECPoint; overload; virtual; abstract;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean): IECPoint; overload; virtual; abstract;
-
-    function CreateDefaultMultiplier(): IECMultiplier; virtual;
-
-    procedure CheckPoint(const point: IECPoint); virtual;
-
-    procedure CheckPoints(const points: TCryptoLibGenericArray<IECPoint>);
-      overload; virtual;
-
-    procedure CheckPoints(const points: TCryptoLibGenericArray<IECPoint>;
-      off, len: Int32); overload; virtual;
-
-    function DecompressPoint(yTilde: Int32; const x1: TBigInteger): IECPoint;
-      virtual; abstract;
-
-  public
-
-    type
-
-    TConfig = class(TInterfacedObject, IConfig)
-
-    strict protected
-    var
-      Fouter: IECCurve;
-      Fcoord: Int32;
-      Fendomorphism: IECEndomorphism;
-      Fmultiplier: IECMultiplier;
-
-    public
-      constructor Create(const outer: IECCurve; coord: Int32;
-        const endomorphism: IECEndomorphism;
-        const multiplier: IECMultiplier); overload;
-
-      destructor Destroy(); override;
-
-      function SetCoordinateSystem(coord: Int32): IConfig; inline;
-      function SetEndomorphism(const endomorphism: IECEndomorphism)
-        : IConfig; inline;
-      function SetMultiplier(const multiplier: IECMultiplier): IConfig; inline;
-      function CreateCurve(): IECCurve;
-
-    end;
-
-  function FromBigInteger(const x: TBigInteger): IECFieldElement;
-    virtual; abstract;
-  function IsValidFieldElement(const x: TBigInteger): Boolean; virtual;
-    abstract;
-
-  function Configure(): IConfig; virtual;
-  function ValidatePoint(const x, y: TBigInteger): IECPoint; overload; virtual;
-
-  function ValidatePoint(const x, y: TBigInteger; withCompression: Boolean)
-    : IECPoint; overload; virtual;
-    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(const points
-    : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-    : IECLookupTable; virtual;
-
-  function CreatePoint(const x, y: TBigInteger): IECPoint; overload; virtual;
-
-  function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
-    : IECPoint; overload; virtual;
-    deprecated 'Per-point compression property will be removed';
-
-  function SupportsCoordinateSystem(coord: Int32): Boolean; virtual;
-
-  function GetPreCompInfo(const point: IECPoint; const name: String)
-    : IPreCompInfo; virtual;
-
-  /// <summary>
-  /// Compute a <c>PreCompInfo</c> for a point on this curve, under a given
-  /// name. Used by <c>ECMultiplier</c> to save the precomputation for this <c>
-  /// ECPoint</c> for use by subsequent multiplication.
-  /// </summary>
-  /// <param name="point">
-  /// The <c>ECPoint</c> to store precomputations for.
-  /// </param>
-  /// <param name="name">
-  /// A <c>String</c> used to index precomputations of different types.
-  /// </param>
-  /// <param name="callback">
-  /// Called to calculate the <c>PreCompInfo</c>
-  /// </param>
-  function Precompute(const point: IECPoint; const name: String;
-    const callback: IPreCompCallback): IPreCompInfo; virtual;
-
-  function ImportPoint(const P: IECPoint): IECPoint; virtual;
-
-  /// <summary>
-  /// Normalization ensures that any projective coordinate is 1, and
-  /// therefore that the x, y coordinates reflect those of the equivalent
-  /// point in an affine coordinate system. Where more than one point is to
-  /// be normalized, this method will generally be more efficient than
-  /// normalizing each point separately.
-  /// </summary>
-  /// <param name="points">
-  /// An array of points that will be updated in place with their normalized
-  /// versions, where necessary
-  /// </param>
-  procedure NormalizeAll(const points: TCryptoLibGenericArray<IECPoint>);
-    overload; virtual;
-
-  /// <summary>
-  /// Normalization ensures that any projective coordinate is 1, and
-  /// therefore that the x, y coordinates reflect those of the equivalent
-  /// point in an affine coordinate system. Where more than one point is to
-  /// be normalized, this method will generally be more efficient than
-  /// normalizing each point separately. An (optional) z-scaling factor can
-  /// be applied; effectively each z coordinate is scaled by this value prior
-  /// to normalization (but only one actual multiplication is needed).
-  /// </summary>
-  /// <param name="points">
-  /// An array of points that will be updated in place with their normalized
-  /// versions, where necessary
-  /// </param>
-  /// <param name="off">
-  /// The start of the range of points to normalize
-  /// </param>
-  /// <param name="len">
-  /// The length of the range of points to normalize
-  /// </param>
-  /// <param name="iso">
-  /// The (optional) z-scaling factor - can be null
-  /// </param>
-  procedure NormalizeAll(const points: TCryptoLibGenericArray<IECPoint>;
-    off, len: Int32; const iso: IECFieldElement); overload; virtual;
-
-  function GetEndomorphism(): IECEndomorphism; virtual;
-
-  /// <summary>
-  /// Sets the default <c>ECMultiplier</c>, unless already set.
-  /// </summary>
-  function GetMultiplier(): IECMultiplier; virtual;
-
-  /// <summary>
-  /// Decode a point on this curve from its ASN.1 encoding. The different
-  /// encodings are taken account of, including point compression for <br /><c>
-  /// F</c><b>p</b> (X9.62 s 4.2.1 pg 17).
-  /// </summary>
-  /// <returns>
-  /// The decoded point.
-  /// </returns>
-  function DecodePoint(const encoded: TCryptoLibByteArray): IECPoint; virtual;
-
-  property coord: Int32 write SetCoord;
-  property endomorphism: IECEndomorphism write SetEndomorphism;
-  property multiplier: IECMultiplier write SetMultiplier;
-
-  property FieldSize: Int32 read GetFieldSize;
-
-  property Infinity: IECPoint read GetInfinity;
-
-  property field: IFiniteField read GetField;
-
-  property a: IECFieldElement read GetA;
-
-  property b: IECFieldElement read GetB;
-
-  property Order: TBigInteger read GetOrder;
-
-  property Cofactor: TBigInteger read GetCofactor;
-
-  property CoordinateSystem: Int32 read GetCoordinateSystem;
-
-  function Equals(const other: IECCurve): Boolean; reintroduce;
-  function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-  destructor Destroy; override;
-
-  class function GetAllCoordinateSystems(): TCryptoLibInt32Array;
-    static; inline;
-
-  end;
-
-type
-  TAbstractECLookupTable = class abstract(TInterfacedObject,
-    IAbstractECLookupTable, IECLookupTable)
-
-  strict protected
-    function GetSize: Int32; virtual; abstract;
-
-  public
-    function Lookup(index: Int32): IECPoint; virtual; abstract;
-    function LookupVar(index: Int32): IECPoint; virtual; abstract;
-    property Size: Int32 read GetSize;
-
-  end;
-
-type
-  TSimpleLookupTable = class abstract(TAbstractECLookupTable,
-    ISimpleLookupTable)
-
-  strict private
-  var
-    FPoints: TCryptoLibGenericArray<IECPoint>;
-
-    class function Copy(const points: TCryptoLibGenericArray<IECPoint>;
-      off, len: Int32): TCryptoLibGenericArray<IECPoint>; static;
-
-  strict protected
-    function GetSize: Int32; override;
-
-  public
-    constructor Create(const points: TCryptoLibGenericArray<IECPoint>;
-      off, len: Int32);
-
-    destructor Destroy; override;
-
-    function Lookup(index: Int32): IECPoint; override;
-    function LookupVar(index: Int32): IECPoint; override;
-
-  end;
-
-type
-  TDefaultLookupTable = class(TAbstractECLookupTable, IDefaultLookupTable)
-  strict private
-  var
-    Fm_outer: IECCurve;
-    Fm_table: TCryptoLibByteArray;
-    Fm_size: Int32;
-
-    function CreatePoint(const x, y: TCryptoLibByteArray): IECPoint;
-
-  strict protected
-    function GetSize: Int32; override;
-
-  public
-    constructor Create(const outer: IECCurve; const table: TCryptoLibByteArray;
-      Size: Int32);
-
-      destructor Destroy; override;
-
-    function Lookup(index: Int32): IECPoint; override;
-    function LookupVar(index: Int32): IECPoint; override;
-
-  end;
-
-type
-  TAbstractFpCurve = class(TECCurve, IAbstractFpCurve)
-
-  strict protected
-
-    constructor Create(const Q: TBigInteger);
-    function DecompressPoint(yTilde: Int32; const x1: TBigInteger)
-      : IECPoint; override;
-
-  public
-    destructor Destroy; override;
-    function IsValidFieldElement(const x: TBigInteger): Boolean; override;
-
-  end;
-
-type
-  TDefaultF2mLookupTable = class(TAbstractECLookupTable, IDefaultF2mLookupTable)
-  strict private
-  var
-    Fm_outer: IF2mCurve;
-    Fm_table: TCryptoLibUInt64Array;
-    Fm_size: Int32;
-
-    function CreatePoint(const x, y: TCryptoLibUInt64Array): IECPoint;
-
-  strict protected
-    function GetSize: Int32; override;
-
-  public
-    constructor Create(const outer: IF2mCurve;
-      const table: TCryptoLibUInt64Array; Size: Int32);
-
-    destructor Destroy; override;
-
-    function Lookup(index: Int32): IECPoint; override;
-    function LookupVar(index: Int32): IECPoint; override;
-
-  end;
-
-type
-  TFpCurve = class(TAbstractFpCurve, IFpCurve)
-
-  strict private
-  const
-    FP_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_JACOBIAN_MODIFIED);
-
-  strict protected
-  var
-    Fm_q, Fm_r: TBigInteger;
-
-    Fm_infinity: IFpPoint;
-
-    constructor Create(const Q, r: TBigInteger; const a, b: IECFieldElement);
-      overload; deprecated 'Use constructor taking order/cofactor';
-    constructor Create(const Q, r: TBigInteger; const a, b: IECFieldElement;
-      const Order, Cofactor: TBigInteger); overload;
-
-    function GetQ: TBigInteger; virtual;
-    function GetInfinity: IECPoint; override;
-    function GetFieldSize: Int32; override;
-
-    function CloneCurve(): IECCurve; override;
-    function CreateRawPoint(const x, y: IECFieldElement;
-      withCompression: Boolean): IECPoint; overload; override;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean): IECPoint; overload; override;
-
-  public
-    constructor Create(const Q, a, b: TBigInteger); overload;
-      deprecated 'Use constructor taking order/cofactor';
-    constructor Create(const Q, a, b, Order, Cofactor: TBigInteger); overload;
-
-    destructor Destroy; override;
-
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-    function ImportPoint(const P: IECPoint): IECPoint; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    property Q: TBigInteger read GetQ;
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-
-  end;
-
-type
-  TAbstractF2mCurve = class abstract(TECCurve, IAbstractF2mCurve)
-
-  strict private
-
-    /// <summary>
-    /// The auxiliary values <c>s</c><b>0</b> and <c>s</c><b>1</b> used for
-    /// partial modular reduction for Koblitz curves.
-    /// </summary>
-    Fsi: TCryptoLibGenericArray<TBigInteger>;
-
-    class function BuildField(m, k1, k2, k3: Int32): IFiniteField; static;
-
-  strict protected
-    constructor Create(m, k1, k2, k3: Int32);
-
-    /// <summary>
-    /// Returns true if this is a Koblitz curve (ABC curve).
-    /// </summary>
-    /// <returns>
-    /// true if this is a Koblitz curve (ABC curve), false otherwise
-    /// </returns>
-    function GetIsKoblitz: Boolean; virtual;
-
-    function DecompressPoint(yTilde: Int32; const x1: TBigInteger)
-      : IECPoint; override;
-
-    // /**
-    // * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-    // * D.1.6) The other solution is <code>z + 1</code>.
-    // *
-    // * @param beta
-    // *            The value to solve the qradratic equation for.
-    // * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-    // *         <code>null</code> if no solution exists.
-    // */
-    function SolveQuadraticEquation(const beta: IECFieldElement)
-      : IECFieldElement;
-
-  public
-
-    destructor Destroy; override;
-
-    function IsValidFieldElement(const x: TBigInteger): Boolean; override;
-
-    function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
-      : IECPoint; override;
-      deprecated 'Per-point compression property will be removed';
-
-    // /**
-    // * @return the auxiliary values <code>s<sub>0</sub></code> and
-    // * <code>s<sub>1</sub></code> used for partial modular reduction for
-    // * Koblitz curves.
-    // */
-    function GetSi(): TCryptoLibGenericArray<TBigInteger>; virtual;
-
-    property IsKoblitz: Boolean read GetIsKoblitz;
-
-    class function Inverse(m: Int32; const ks: TCryptoLibInt32Array;
-      const x: TBigInteger): TBigInteger; static; inline;
-
-  end;
-
-type
-  // /**
-  // * Elliptic curves over F2m. The Weierstrass equation is given by
-  // * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
-  // */
-  TF2mCurve = class sealed(TAbstractF2mCurve, IF2mCurve)
-
-  strict private
-  const
-    F2M_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_LAMBDA_PROJECTIVE);
-
-  var
-    // /**
-    // * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
-    // */
-    Fm: Int32;
-
-    // /**
-    // * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
-    // * x<sup>k</sup> + 1</code> represents the reduction polynomial
-    // * <code>f(z)</code>.<br/>
-    // * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    Fk1: Int32;
-
-    // /**
-    // * TPB: Always set to <code>0</code><br/>
-    // * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    Fk2: Int32;
-    //
-    // /**
-    // * TPB: Always set to <code>0</code><br/>
-    // * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.<br/>
-    // */
-    Fk3: Int32;
-
-    /// <summary>
-    /// The point at infinity on this curve.
-    /// </summary>
-    Fm_infinity: IF2mPoint;
-
-    constructor Create(m, k1, k2, k3: Int32; const a, b: IECFieldElement;
-      const Order, Cofactor: TBigInteger); overload;
-
-    function GetM: Int32; inline;
-    function GetK1: Int32; inline;
-    function GetK2: Int32; inline;
-    function GetK3: Int32; inline;
-
-  strict protected
-    function GetFieldSize: Int32; override;
-    function GetInfinity: IECPoint; override;
-
-    function CloneCurve(): IECCurve; override;
-    function CreateDefaultMultiplier(): IECMultiplier; override;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      withCompression: Boolean): IECPoint; overload; override;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean): IECPoint; overload; override;
-
-  public
-    // /**
-    // * Constructor for Trinomial Polynomial Basis (TPB).
-    // * @param m  The exponent <code>m</code> of
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
-    // * x<sup>k</sup> + 1</code> represents the reduction
-    // * polynomial <code>f(z)</code>.
-    // * @param a The coefficient <code>a</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param b The coefficient <code>b</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // */
-    constructor Create(m, K: Int32; const a, b: TBigInteger); overload;
-      deprecated 'Use constructor taking order/cofactor';
-    // /**
-    // * Constructor for Trinomial Polynomial Basis (TPB).
-    // * @param m  The exponent <code>m</code> of
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
-    // * x<sup>k</sup> + 1</code> represents the reduction
-    // * polynomial <code>f(z)</code>.
-    // * @param a The coefficient <code>a</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param b The coefficient <code>b</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param order The order of the main subgroup of the elliptic curve.
-    // * @param cofactor The cofactor of the elliptic curve, i.e.
-    // * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
-    // */
-    constructor Create(m, K: Int32;
-      const a, b, Order, Cofactor: TBigInteger); overload;
-
-    // /**
-    // * Constructor for Pentanomial Polynomial Basis (PPB).
-    // * @param m  The exponent <code>m</code> of
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param a The coefficient <code>a</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param b The coefficient <code>b</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // */
-
-    constructor Create(m, k1, k2, k3: Int32; const a, b: TBigInteger); overload;
-      deprecated 'Use constructor taking order/cofactor';
-    // /**
-    // * Constructor for Pentanomial Polynomial Basis (PPB).
-    // * @param m  The exponent <code>m</code> of
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
-    // * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-    // * represents the reduction polynomial <code>f(z)</code>.
-    // * @param a The coefficient <code>a</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param b The coefficient <code>b</code> in the Weierstrass equation
-    // * for non-supersingular elliptic curves over
-    // * <code>F<sub>2<sup>m</sup></sub></code>.
-    // * @param order The order of the main subgroup of the elliptic curve.
-    // * @param cofactor The cofactor of the elliptic curve, i.e.
-    // * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
-    // */
-    constructor Create(m, k1, k2, k3: Int32;
-      const a, b, Order, Cofactor: TBigInteger); overload;
-
-    destructor Destroy; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    /// <summary>
-    /// Return true if curve uses a Trinomial basis.
-    /// </summary>
-    /// <returns>
-    /// return true if curve Trinomial, false otherwise.
-    /// </returns>
-    function IsTrinomial(): Boolean; inline;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property FieldSize: Int32 read GetFieldSize;
-    property Infinity: IECPoint read GetInfinity;
-    property m: Int32 read GetM;
-    property k1: Int32 read GetK1;
-    property k2: Int32 read GetK2;
-    property k3: Int32 read GetK3;
-
-  end;
-
-type
-
-  /// <summary>
-  /// base class for points on elliptic curves.
-  /// </summary>
-  TECPoint = class abstract(TInterfacedObject, IECPoint)
-
-  strict private
-
-  type
-    IValidityCallback = interface(IPreCompCallback)
-      ['{FD571D52-9852-45A6-BD53-47765EB86F20}']
-
-    end;
-
-  type
-    TValidityCallback = class(TInterfacedObject, IPreCompCallback,
-      IValidityCallback)
-
-    strict private
-    var
-      Fm_outer: IECPoint;
-      Fm_decompressed, Fm_checkOrder: Boolean;
-
-    public
-      constructor Create(const outer: IECPoint;
-        decompressed, checkOrder: Boolean);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  class constructor ECPoint();
-
-  strict protected
-
-    class var
-
-      FEMPTY_ZS: TCryptoLibGenericArray<IECFieldElement>;
-
-  var
-    Fm_zs: TCryptoLibGenericArray<IECFieldElement>;
-    Fm_withCompression: Boolean;
-    Fm_curve: TWeakRef<IECCurve>;
-
-    Fm_x, Fm_y: IECFieldElement;
-
-    function GetIsInfinity: Boolean; inline;
-    function GetIsCompressed: Boolean; inline;
-    function GetpreCompTable: TDictionary<String, IPreCompInfo>; inline;
-    procedure SetpreCompTable(const Value
-      : TDictionary<String, IPreCompInfo>); inline;
-    function GetCurve: IECCurve; virtual;
-    function GetCurveCoordinateSystem: Int32; virtual;
-    function GetAffineXCoord: IECFieldElement; virtual;
-    function GetAffineYCoord: IECFieldElement; virtual;
-    function GetXCoord: IECFieldElement; virtual;
-
-    function GetCompressionYTilde: Boolean; virtual; abstract;
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-
-    function SatisfiesOrder(): Boolean; virtual;
-    function SatisfiesCurveEquation(): Boolean; virtual; abstract;
-    function Detach(): IECPoint; virtual; abstract;
-
-    function RawXCoord: IECFieldElement; inline;
-
-    function RawYCoord: IECFieldElement; inline;
-
-    function RawZCoords: TCryptoLibGenericArray<IECFieldElement>; inline;
-
-    function CreateScaledPoint(const sx, sy: IECFieldElement)
-      : IECPoint; virtual;
-
-    procedure CheckNormalized(); virtual;
-
-    property CurveCoordinateSystem: Int32 read GetCurveCoordinateSystem;
-
-    property CompressionYTilde: Boolean read GetCompressionYTilde;
-
-    class function GetInitialZCoords(const curve: IECCurve)
-      : TCryptoLibGenericArray<IECFieldElement>; static;
-
-  public
-  var
-    // Dictionary is (string -> PreCompInfo)
-    Fm_preCompTable: TDictionary<String, IPreCompInfo>;
-
-    function GetYCoord: IECFieldElement; virtual;
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-    destructor Destroy; override;
-
-    function GetDetachedPoint(): IECPoint; inline;
-    function GetZCoord(index: Int32): IECFieldElement; virtual;
-    function GetZCoords(): TCryptoLibGenericArray<IECFieldElement>; virtual;
-
-    function IsNormalized(): Boolean; virtual;
-
-    /// <summary>
-    /// Normalization ensures that any projective coordinate is 1, and
-    /// therefore that the x, y <br />coordinates reflect those of the
-    /// equivalent point in an affine coordinate system.
-    /// </summary>
-    /// <returns>
-    /// a new ECPoint instance representing the same point, but with
-    /// normalized coordinates
-    /// </returns>
-    function Normalize(): IECPoint; overload; virtual;
-
-    function Normalize(const zInv: IECFieldElement): IECPoint;
-      overload; virtual;
-
-    function ImplIsValid(decompressed, checkOrder: Boolean): Boolean;
-
-    function IsValid(): Boolean; inline;
-    function IsValidPartial(): Boolean; inline;
-
-    function ScaleX(const scale: IECFieldElement): IECPoint; virtual;
-    function ScaleY(const scale: IECFieldElement): IECPoint; virtual;
-
-    function ScaleXNegateY(const scale: IECFieldElement): IECPoint; virtual;
-    function ScaleYNegateX(const scale: IECFieldElement): IECPoint; virtual;
-
-    function GetEncoded(): TCryptoLibByteArray; overload; virtual;
-    function GetEncoded(compressed: Boolean): TCryptoLibByteArray; overload;
-      virtual; abstract;
-
-    function Add(const b: IECPoint): IECPoint; virtual; abstract;
-    function Subtract(const b: IECPoint): IECPoint; virtual; abstract;
-    function Negate(): IECPoint; virtual; abstract;
-    function TimesPow2(e: Int32): IECPoint; virtual;
-
-    function Twice(): IECPoint; virtual; abstract;
-    function Multiply(b: TBigInteger): IECPoint; virtual; abstract;
-
-    function TwicePlus(const b: IECPoint): IECPoint; virtual;
-
-    function ThreeTimes(): IECPoint; virtual;
-
-    function Clone(): IECPoint; virtual;
-
-    function Equals(const other: IECPoint): Boolean; reintroduce;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    function ToString(): String; override;
-
-    property preCompTable: TDictionary<String, IPreCompInfo>
-      read GetpreCompTable write SetpreCompTable;
-
-    /// <summary>
-    /// Returns the affine x-coordinate after checking that this point is
-    /// normalized.
-    /// </summary>
-    /// <value>
-    /// The affine x-coordinate of this point
-    /// </value>
-    /// <exception cref="ClpCryptoLibTypes|EInvalidOperationCryptoLibException">
-    /// if the point is not normalized
-    /// </exception>
-    property AffineXCoord: IECFieldElement read GetAffineXCoord;
-    /// <summary>
-    /// Returns the affine y-coordinate after checking that this point is
-    /// normalized.
-    /// </summary>
-    /// <value>
-    /// The affine y-coordinate of this point
-    /// </value>
-    /// <exception cref="ClpCryptoLibTypes|EInvalidOperationCryptoLibException">
-    /// if the point is not normalized
-    /// </exception>
-    property AffineYCoord: IECFieldElement read GetAffineYCoord;
-
-    /// <summary>
-    /// Returns the x-coordinate. <br />Caution: depending on the curve's
-    /// coordinate system, this may not be the same value as in an <br />
-    /// affine coordinate system; use Normalize() to get a point where the
-    /// coordinates have their <br />affine values, or use AffineXCoord if
-    /// you expect the point to already have been normalized.
-    /// </summary>
-    /// <value>
-    /// the x-coordinate of this point
-    /// </value>
-    property XCoord: IECFieldElement read GetXCoord;
-    /// <summary>
-    /// Returns the y-coordinate. <br />Caution: depending on the curve's
-    /// coordinate system, this may not be the same value as in an <br />
-    /// affine coordinate system; use Normalize() to get a point where the
-    /// coordinates have their <br />affine values, or use AffineYCoord if
-    /// you expect the point to already have been normalized.
-    /// </summary>
-    /// <value>
-    /// the y-coordinate of this point
-    /// </value>
-    property YCoord: IECFieldElement read GetYCoord;
-
-    property curve: IECCurve read GetCurve;
-
-    property IsInfinity: Boolean read GetIsInfinity;
-
-    property IsCompressed: Boolean read GetIsCompressed;
-
-  end;
-
-type
-  TECPointBase = class abstract(TECPoint, IECPointBase)
-
-  strict protected
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-
-  public
-
-    destructor Destroy; override;
-
-    /// <summary>
-    /// return the field element encoded with point compression. (S 4.3.6)
-    /// </summary>
-    function GetEncoded(compressed: Boolean): TCryptoLibByteArray; override;
-
-    /// <summary>
-    /// Multiplies this <c>ECPoint</c> by the given number.
-    /// </summary>
-    /// <param name="k">
-    /// The multiplicator.
-    /// </param>
-    /// <returns>
-    /// <c>k * this</c>
-    /// </returns>
-    function Multiply(K: TBigInteger): IECPoint; override;
-
-  end;
-
-type
-  TAbstractFpPoint = class abstract(TECPointBase, IAbstractFpPoint)
-
-  strict protected
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-
-    function GetCompressionYTilde(): Boolean; override;
-
-    function SatisfiesCurveEquation(): Boolean; override;
-
-    property CompressionYTilde: Boolean read GetCompressionYTilde;
-
-  public
-
-    destructor Destroy; override;
-    function Subtract(const b: IECPoint): IECPoint; override;
-
-  end;
-
-type
-
-  /// <summary>
-  /// Elliptic curve points over Fp
-  /// </summary>
-  TFpPoint = class(TAbstractFpPoint, IFpPoint)
-
-  strict protected
-
-    function Detach(): IECPoint; override;
-
-    function Two(const x: IECFieldElement): IECFieldElement; virtual;
-    function Three(const x: IECFieldElement): IECFieldElement; virtual;
-    function Four(const x: IECFieldElement): IECFieldElement; virtual;
-    function Eight(const x: IECFieldElement): IECFieldElement; virtual;
-    function DoubleProductFromSquares(const a, b, aSquared,
-      bSquared: IECFieldElement): IECFieldElement; virtual;
-
-    function CalculateJacobianModifiedW(const z: IECFieldElement;
-      const ZSquared: IECFieldElement): IECFieldElement; virtual;
-
-    function GetJacobianModifiedW(): IECFieldElement; virtual;
-
-    function TwiceJacobianModified(calculateW: Boolean): IFpPoint; virtual;
-
-  public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="curve">
-    /// curve the curve to use
-    /// </param>
-    /// <param name="x">
-    /// affine x co-ordinate
-    /// </param>
-    /// <param name="y">
-    /// affine y co-ordinate
-    /// </param>
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement);
-      overload; deprecated 'Use ECCurve.CreatePoint to construct points';
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="curve">
-    /// curve the curve to use
-    /// </param>
-    /// <param name="x">
-    /// affine x co-ordinate
-    /// </param>
-    /// <param name="y">
-    /// affine y co-ordinate
-    /// </param>
-    /// <param name="withCompression">
-    /// if true encode with point compression
-    /// </param>
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-      deprecated
-      'Per-point compression property will be removed, see GetEncoded(boolean)';
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-
-    destructor Destroy; override;
-
-    function GetZCoord(index: Int32): IECFieldElement; override;
-    // B.3 pg 62
-    function Add(const b: IECPoint): IECPoint; override;
-
-    // B.3 pg 62
-    function Twice(): IECPoint; override;
-
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function ThreeTimes(): IECPoint; override;
-
-    function TimesPow2(e: Int32): IECPoint; override;
-
-    function Negate(): IECPoint; override;
-
-  end;
-
-type
-  TAbstractF2mPoint = class abstract(TECPointBase, IAbstractF2mPoint)
-
-  strict protected
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-
-    function SatisfiesOrder(): Boolean; override;
-    function SatisfiesCurveEquation(): Boolean; override;
-
-  public
-    destructor Destroy; override;
-    function ScaleX(const scale: IECFieldElement): IECPoint; override;
-    function ScaleY(const scale: IECFieldElement): IECPoint; override;
-
-    function ScaleXNegateY(const scale: IECFieldElement): IECPoint; override;
-    function ScaleYNegateX(const scale: IECFieldElement): IECPoint; override;
-
-    function Subtract(const b: IECPoint): IECPoint; override;
-
-    function Tau(): IAbstractF2mPoint; virtual;
-
-    function TauPow(pow: Int32): IAbstractF2mPoint; virtual;
-  end;
-
-type
-
-  /// <summary>
-  /// Elliptic curve points over F2m
-  /// </summary>
-  TF2mPoint = class(TAbstractF2mPoint, IF2mPoint)
-
-  strict protected
-    function GetCompressionYTilde: Boolean; override;
-    function Detach(): IECPoint; override;
-    property CompressionYTilde: Boolean read GetCompressionYTilde;
-  public
-
-    function GetYCoord: IECFieldElement; override;
-
-    /// <param name="curve">
-    /// base curve
-    /// </param>
-    /// <param name="x">
-    /// x point
-    /// </param>
-    /// <param name="y">
-    /// y point
-    /// </param>
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement);
-      overload; deprecated 'Use ECCurve.CreatePoint to construct points';
-
-    /// <param name="curve">
-    /// base curve
-    /// </param>
-    /// <param name="x">
-    /// x point
-    /// </param>
-    /// <param name="y">
-    /// y point
-    /// </param>
-    /// <param name="withCompression">
-    /// true if encode with point compression.
-    /// </param>
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-      deprecated
-      'Per-point compression property will be removed, see GetEncoded(boolean)';
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-
-    destructor Destroy; override;
-
-    function Add(const b: IECPoint): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function Negate(): IECPoint; override;
-
-    property YCoord: IECFieldElement read GetYCoord;
-  end;
-
-implementation
-
-{ TF2mFieldElement }
-
-function TF2mFieldElement.GetKs: TCryptoLibInt32Array;
-begin
-  result := FKs;
-end;
-
-function TF2mFieldElement.GetM: Int32;
-begin
-  result := Fm;
-end;
-
-function TF2mFieldElement.GetRepresentation: Int32;
-begin
-  result := Frepresentation;
-end;
-
-function TF2mFieldElement.GetX: TLongArray;
-begin
-  result := Fx;
-end;
-
-function TF2mFieldElement.Add(const b: IECFieldElement): IECFieldElement;
-var
-  iarrClone: TLongArray;
-  bF2m: IF2mFieldElement;
-begin
-  // No check performed here for performance reasons. Instead the
-  // elements involved are checked in ECPoint.F2m
-  // checkFieldElements(this, b);
-  iarrClone := Fx.Copy();
-  bF2m := b as IF2mFieldElement;
-  iarrClone.AddShiftedByWords(bF2m.x, 0);
-  result := TF2mFieldElement.Create(Fm, FKs, iarrClone);
-end;
-
-function TF2mFieldElement.AddOne: IECFieldElement;
-begin
-  result := TF2mFieldElement.Create(Fm, FKs, Fx.AddOne());
-end;
-
-class procedure TF2mFieldElement.CheckFieldElements(const a,
-  b: IECFieldElement);
-var
-  aF2m, bF2m: IF2mFieldElement;
-begin
-  if (not(Supports(a, IF2mFieldElement, aF2m)) or
-    (not(Supports(b, IF2mFieldElement, bF2m)))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidFieldElement);
-  end;
-
-  if (aF2m.Representation <> bF2m.Representation) then
-  begin
-    // Should never occur
-    raise EArgumentCryptoLibException.CreateRes(@SIncorrectRepresentation);
-  end;
-
-  if ((aF2m.m <> bF2m.m) or (not TArrayUtilities.AreEqual<Int32>(aF2m.ks, bF2m.ks))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidFieldElements);
-  end;
-end;
-
-constructor TF2mFieldElement.Create(m, K: Int32; const x: TBigInteger);
-begin
-  Create(m, K, 0, 0, x);
-end;
-
-constructor TF2mFieldElement.Create(m, k1, k2, k3: Int32; const x: TBigInteger);
-begin
-  Inherited Create();
-  if (not(x.IsInitialized) or (x.SignValue < 0) or (x.BitLength > m)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidValue2);
-  end;
-
-  if ((k2 = 0) and (k3 = 0)) then
-  begin
-    Frepresentation := Tpb;
-    FKs := TCryptoLibInt32Array.Create(k1);
-  end
-  else
-  begin
-    if (k2 >= k3) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SInvalidK2Value);
-    end;
-    if (k2 <= 0) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SInvalidK2Value2);
-    end;
-
-    Frepresentation := Ppb;
-    FKs := TCryptoLibInt32Array.Create(k1, k2, k3);
-  end;
-
-  Fm := m;
-  Fx := TLongArray.Create(x);
-end;
-
-constructor TF2mFieldElement.Create(m: Int32; const ks: TCryptoLibInt32Array;
-  const x: TLongArray);
-begin
-  Inherited Create();
-  Fm := m;
-  if (System.Length(ks) = 1) then
-  begin
-    Frepresentation := Tpb
-  end
-  else
-  begin
-    Frepresentation := Ppb;
-  end;
-  FKs := ks;
-  Fx := x;
-end;
-
-destructor TF2mFieldElement.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TF2mFieldElement.Divide(const b: IECFieldElement): IECFieldElement;
-var
-  bInv: IECFieldElement;
-begin
-  // There may be more efficient implementations
-  bInv := b.Invert();
-  result := Multiply(bInv);
-end;
-
-function TF2mFieldElement.Equals(const other: IF2mFieldElement): Boolean;
-begin
-  if (other = Self as IF2mFieldElement) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (Nil = other) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := ((m = other.m) and (Representation = other.Representation) and
-    TArrayUtilities.AreEqual<Int32>(ks, other.ks) and (x.Equals(other.x)));
-end;
-
-function TF2mFieldElement.GetBitLength: Int32;
-begin
-  result := Fx.Degree();
-end;
-
-function TF2mFieldElement.GetFieldName: String;
-begin
-  result := 'F2m';
-end;
-
-function TF2mFieldElement.GetFieldSize: Int32;
-begin
-  result := Fm;
-end;
-
-function TF2mFieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-begin
-  result := Fx.GetHashCode() xor Fm xor TArrayUtilities.GetArrayHashCode(FKs);
-end;
-
-function TF2mFieldElement.GetIsOne: Boolean;
-begin
-  result := Fx.IsOne();
-end;
-
-function TF2mFieldElement.GetIsZero: Boolean;
-begin
-  result := Fx.IsZero();
-end;
-
-function TF2mFieldElement.GetK1: Int32;
-begin
-  result := FKs[0];
-end;
-
-function TF2mFieldElement.GetK2: Int32;
-begin
-  if (System.Length(FKs) >= 2) then
-  begin
-    result := FKs[1];
-  end
-  else
-  begin
-    result := 0;
-  end;
-end;
-
-function TF2mFieldElement.GetK3: Int32;
-begin
-  if (System.Length(FKs) >= 3) then
-  begin
-    result := FKs[2];
-  end
-  else
-  begin
-    result := 0;
-  end;
-end;
-
-function TF2mFieldElement.Invert: IECFieldElement;
-begin
-  result := TF2mFieldElement.Create(Fm, FKs, Fx.ModInverse(Fm, FKs));
-end;
-
-function TF2mFieldElement.Multiply(const b: IECFieldElement): IECFieldElement;
-begin
-  // Right-to-left comb multiplication in the LongArray
-  // Input: Binary polynomials a(z) and b(z) of degree at most m-1
-  // Output: c(z) = a(z) * b(z) mod f(z)
-
-  // No check performed here for performance reasons. Instead the
-  // elements involved are checked in ECPoint.F2m
-  // checkFieldElements(this, b);
-  result := TF2mFieldElement.Create(Fm, FKs,
-    Fx.ModMultiply((b as IF2mFieldElement).x, Fm, FKs));
-end;
-
-function TF2mFieldElement.MultiplyMinusProduct(const b, x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := MultiplyPlusProduct(b, x, y);
-end;
-
-function TF2mFieldElement.MultiplyPlusProduct(const b, x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, bx, xx, yx, ab, xy: TLongArray;
-begin
-  ax := Fx;
-  bx := (b as IF2mFieldElement).x;
-  xx := (x as IF2mFieldElement).x;
-  yx := (y as IF2mFieldElement).x;
-
-  ab := ax.Multiply(bx);
-  xy := xx.Multiply(yx);
-
-  if ((ab.Equals(ax)) or (ab.Equals(bx))) then
-  begin
-    ab := ab.Copy();
-  end;
-
-  ab.AddShiftedByWords(xy, 0);
-  ab.Reduce(Fm, FKs);
-
-  result := TF2mFieldElement.Create(Fm, FKs, ab);
-end;
-
-function TF2mFieldElement.Negate: IECFieldElement;
-begin
-  // -x == x holds for all x in F2m
-  result := Self as IECFieldElement;
-end;
-
-function TF2mFieldElement.Sqrt: IECFieldElement;
-begin
-  if ((Fx.IsZero()) or (Fx.IsOne())) then
-  begin
-    result := Self as IECFieldElement;
-  end
-  else
-  begin
-    result := SquarePow(Fm - 1);
-  end;
-end;
-
-function TF2mFieldElement.Square: IECFieldElement;
-begin
-  result := TF2mFieldElement.Create(Fm, FKs, Fx.ModSquare(Fm, FKs));
-end;
-
-function TF2mFieldElement.SquareMinusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := SquarePlusProduct(x, y);
-end;
-
-function TF2mFieldElement.SquarePlusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, xx, yx, aa, xy: TLongArray;
-begin
-  ax := Fx;
-  xx := (x as IF2mFieldElement).x;
-  yx := (y as IF2mFieldElement).x;
-
-  aa := ax.Square(Fm, FKs);
-  xy := xx.Multiply(yx);
-
-  if (aa.Equals(ax)) then
-  begin
-    aa := aa.Copy();
-  end;
-
-  aa.AddShiftedByWords(xy, 0);
-  aa.Reduce(Fm, FKs);
-
-  result := TF2mFieldElement.Create(Fm, FKs, aa);
-end;
-
-function TF2mFieldElement.SquarePow(pow: Int32): IECFieldElement;
-begin
-  if pow < 1 then
-  begin
-    result := Self as IECFieldElement
-  end
-  else
-  begin
-    result := TF2mFieldElement.Create(Fm, FKs, Fx.ModSquareN(pow, Fm, FKs));
-  end;
-end;
-
-function TF2mFieldElement.Subtract(const b: IECFieldElement): IECFieldElement;
-begin
-  // Addition and subtraction are the same in F2m
-  result := Add(b);
-end;
-
-function TF2mFieldElement.TestBitZero: Boolean;
-begin
-  result := Fx.TestBitZero();
-end;
-
-function TF2mFieldElement.ToBigInteger: TBigInteger;
-begin
-  result := Fx.ToBigInteger();
-end;
-
-{ TECFieldElement }
-
-constructor TECFieldElement.Create;
-begin
-  Inherited Create();
-end;
-
-destructor TECFieldElement.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TECFieldElement.Equals(const other: IECFieldElement): Boolean;
-begin
-  if (other = Self as IECFieldElement) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (Nil = other) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := ToBigInteger().Equals(other.ToBigInteger());
-end;
-
-function TECFieldElement.GetBitLength: Int32;
-begin
-  result := ToBigInteger().BitLength;
-end;
-
-function TECFieldElement.GetEncoded: TCryptoLibByteArray;
-begin
-  result := TBigIntegers.AsUnsignedByteArray(GetEncodedLength(),
-    ToBigInteger());
-end;
-
-function TECFieldElement.GetEncodedLength: Int32;
-begin
-  Result := (FieldSize + 7) div 8;
-end;
-
-function TECFieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-begin
-  result := ToBigInteger().GetHashCode();
-end;
-
-function TECFieldElement.GetIsOne: Boolean;
-begin
-  result := BitLength = 1;
-end;
-
-function TECFieldElement.GetIsZero: Boolean;
-begin
-  result := 0 = ToBigInteger().SignValue;
-end;
-
-function TECFieldElement.MultiplyMinusProduct(const b, x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := Multiply(b).Subtract(x.Multiply(y));
-end;
-
-function TECFieldElement.MultiplyPlusProduct(const b, x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := Multiply(b).Add(x.Multiply(y));
-end;
-
-function TECFieldElement.SquareMinusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := Square().Subtract(x.Multiply(y));
-end;
-
-function TECFieldElement.SquarePlusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := Square().Add(x.Multiply(y));
-end;
-
-function TECFieldElement.SquarePow(pow: Int32): IECFieldElement;
-var
-  r: IECFieldElement;
-  i: Int32;
-begin
-  r := Self as IECFieldElement;
-  i := 0;
-  while i < pow do
-  begin
-    r := r.Square();
-    System.Inc(i);
-  end;
-
-  result := r;
-end;
-
-function TECFieldElement.TestBitZero: Boolean;
-begin
-  result := ToBigInteger().TestBit(0);
-end;
-
-function TECFieldElement.ToString: String;
-begin
-  result := ToBigInteger().ToString(16);
-end;
-
-{ TFpFieldElement }
-
-function TFpFieldElement.GetQ: TBigInteger;
-begin
-  result := Fq;
-end;
-
-function TFpFieldElement.GetFieldSize: Int32;
-begin
-  result := Q.BitLength;
-end;
-
-function TFpFieldElement.Add(const b: IECFieldElement): IECFieldElement;
-begin
-  result := TFpFieldElement.Create(Fq, Fr, ModAdd(Fx, b.ToBigInteger()));
-end;
-
-function TFpFieldElement.AddOne: IECFieldElement;
-var
-  x2: TBigInteger;
-begin
-  x2 := Fx.Add(TBigInteger.One);
-  if (x2.CompareTo(Q) = 0) then
-  begin
-    x2 := TBigInteger.Zero;
-  end;
-  result := TFpFieldElement.Create(Fq, Fr, x2);
-end;
-
-class function TFpFieldElement.CalculateResidue(const P: TBigInteger)
-  : TBigInteger;
-var
-  BitLength: Int32;
-  firstWord: TBigInteger;
-begin
-  BitLength := P.BitLength;
-  if (BitLength >= 96) then
-  begin
-    firstWord := P.ShiftRight(BitLength - 64);
-    if (firstWord.Int64Value = Int64(-1)) then
-    begin
-      result := TBigInteger.One.ShiftLeft(BitLength).Subtract(P);
-      Exit;
-    end;
-    if ((BitLength and 7) = 0) then
-    begin
-      result := TBigInteger.One.ShiftLeft(BitLength shl 1).Divide(P).Negate();
-      Exit;
-    end;
-  end;
-  result := TBigInteger.GetDefault;
-end;
-
-function TFpFieldElement.CheckSqrt(const z: IECFieldElement): IECFieldElement;
-begin
-  if (z.Square().Equals(Self as IECFieldElement)) then
-  begin
-    result := z;
-  end
-  else
-  begin
-    result := Nil;
-  end;
-end;
-
-constructor TFpFieldElement.Create(const Q, x: TBigInteger);
-begin
-  Create(Q, CalculateResidue(Q), x);
-end;
-
-constructor TFpFieldElement.Create(const Q, r, x: TBigInteger);
-begin
-  Inherited Create();
-  if (not(x.IsInitialized) or (x.SignValue < 0) or (x.CompareTo(Q) >= 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidValue);
-  end;
-
-  Fq := Q;
-  Fr := r;
-  Fx := x;
-end;
-
-destructor TFpFieldElement.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TFpFieldElement.Divide(const b: IECFieldElement): IECFieldElement;
-begin
-  result := TFpFieldElement.Create(Fq, Fr,
-    ModMult(Fx, ModInverse(b.ToBigInteger())));
-end;
-
-function TFpFieldElement.Equals(const other: IFpFieldElement): Boolean;
-begin
-  if (other = Self as IFpFieldElement) then
-  begin
-    result := true;
-    Exit;
-  end;
-
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  result := (Q.Equals(other.Q) and (Inherited Equals(other)));
-end;
-
-function TFpFieldElement.GetFieldName: String;
-begin
-  result := 'Fp';
-end;
-
-function TFpFieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-begin
-  result := Q.GetHashCode() xor (Inherited GetHashCode());
-end;
-
-function TFpFieldElement.Invert: IECFieldElement;
-begin
-  // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
-  result := TFpFieldElement.Create(Fq, Fr, ModInverse(Fx));
-end;
-
-function TFpFieldElement.LucasSequence(const P, Q, K: TBigInteger)
-  : TCryptoLibGenericArray<TBigInteger>;
-var
-  n, s, j: Int32;
-  Uh, Vl, Vh, Ql, Qh: TBigInteger;
-begin
-  // TODO Research and apply "common-multiplicand multiplication here"
-
-  n := K.BitLength;
-  s := K.GetLowestSetBit();
-
-{$IFDEF DEBUG}
-  System.Assert(K.TestBit(s));
-{$ENDIF DEBUG}
-  Uh := TBigInteger.One;
-  Vl := TBigInteger.Two;
-  Vh := P;
-  Ql := TBigInteger.One;
-  Qh := TBigInteger.One;
-
-  j := n - 1;
-
-  while j >= s + 1 do
-  begin
-    Ql := ModMult(Ql, Qh);
-
-    if (K.TestBit(j)) then
-    begin
-      Qh := ModMult(Ql, Q);
-      Uh := ModMult(Uh, Vh);
-      Vl := ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
-      Vh := ModReduce(Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)));
-    end
-    else
-    begin
-      Qh := Ql;
-      Uh := ModReduce(Uh.Multiply(Vl).Subtract(Ql));
-      Vh := ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
-      Vl := ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
-    end;
-    System.Dec(j);
-  end;
-
-  Ql := ModMult(Ql, Qh);
-  Qh := ModMult(Ql, Q);
-  Uh := ModReduce(Uh.Multiply(Vl).Subtract(Ql));
-  Vl := ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
-  Ql := ModMult(Ql, Qh);
-
-  j := 1;
-
-  while j <= s do
-  begin
-    Uh := ModMult(Uh, Vl);
-    Vl := ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
-    Ql := ModMult(Ql, Ql);
-    System.Inc(j);
-  end;
-
-  result := TCryptoLibGenericArray<TBigInteger>.Create(Uh, Vl);
-end;
-
-function TFpFieldElement.ModAdd(const x1, x2: TBigInteger): TBigInteger;
-var
-  x3: TBigInteger;
-begin
-  x3 := x1.Add(x2);
-  if (x3.CompareTo(Q) >= 0) then
-  begin
-    x3 := x3.Subtract(Q);
-  end;
-  result := x3;
-end;
-
-function TFpFieldElement.ModDouble(const x: TBigInteger): TBigInteger;
-var
-  _2x: TBigInteger;
-begin
-  _2x := x.ShiftLeft(1);
-  if (_2x.CompareTo(Q) >= 0) then
-  begin
-    _2x := _2x.Subtract(Q);
-  end;
-  result := _2x;
-end;
-
-function TFpFieldElement.ModHalf(const x: TBigInteger): TBigInteger;
-var
-  Lx: TBigInteger;
-begin
-  Lx := x;
-  if (Lx.TestBit(0)) then
-  begin
-    Lx := Q.Add(Lx);
-  end;
-  result := Lx.ShiftRight(1);
-end;
-
-function TFpFieldElement.ModHalfAbs(const x: TBigInteger): TBigInteger;
-var
-  Lx: TBigInteger;
-begin
-  Lx := x;
-  if (Lx.TestBit(0)) then
-  begin
-    Lx := Q.Subtract(Lx);
-  end;
-  result := Lx.ShiftRight(1);
-end;
-
-function TFpFieldElement.ModInverse(const x: TBigInteger): TBigInteger;
-begin
-  Result := TBigIntegers.ModOddInverse(Q, x);
-end;
-
-function TFpFieldElement.ModMult(const x1, x2: TBigInteger): TBigInteger;
-begin
-  result := ModReduce(x1.Multiply(x2));
-end;
-
-function TFpFieldElement.ModReduce(const x: TBigInteger): TBigInteger;
-var
-  negative, rIsOne: Boolean;
-  qLen, d: Int32;
-  qMod, u, v, mu, quot, bk1, Lx: TBigInteger;
-begin
-  Lx := x;
-  if (not(Fr.IsInitialized)) then
-  begin
-    Lx := Lx.&Mod(Q);
-  end
-  else
-  begin
-    negative := Lx.SignValue < 0;
-    if (negative) then
-    begin
-      Lx := Lx.Abs();
-    end;
-    qLen := Q.BitLength;
-    if (Fr.SignValue > 0) then
-    begin
-      qMod := TBigInteger.One.ShiftLeft(qLen);
-      rIsOne := Fr.Equals(TBigInteger.One);
-      while (Lx.BitLength > (qLen + 1)) do
-      begin
-        u := Lx.ShiftRight(qLen);
-        v := Lx.Remainder(qMod);
-        if (not rIsOne) then
-        begin
-          u := u.Multiply(Fr);
-        end;
-        Lx := u.Add(v);
-      end
-    end
-    else
-    begin
-      d := ((qLen - 1) and 31) + 1;
-      mu := Fr.Negate();
-      u := mu.Multiply(Lx.ShiftRight(qLen - d));
-      quot := u.ShiftRight(qLen + d);
-      v := quot.Multiply(Q);
-      bk1 := TBigInteger.One.ShiftLeft(qLen + d);
-      v := v.Remainder(bk1);
-      Lx := Lx.Remainder(bk1);
-      Lx := Lx.Subtract(v);
-      if (Lx.SignValue < 0) then
-      begin
-        Lx := Lx.Add(bk1);
-      end
-    end;
-    while (Lx.CompareTo(Q) >= 0) do
-    begin
-      Lx := Lx.Subtract(Q);
-    end;
-    if ((negative) and (Lx.SignValue <> 0)) then
-    begin
-      Lx := Q.Subtract(Lx);
-    end;
-  end;
-  result := Lx;
-end;
-
-function TFpFieldElement.ModSubtract(const x1, x2: TBigInteger): TBigInteger;
-var
-  x3: TBigInteger;
-begin
-  x3 := x1.Subtract(x2);
-  if (x3.SignValue < 0) then
-  begin
-    x3 := x3.Add(Q);
-  end;
-  result := x3;
-end;
-
-function TFpFieldElement.Multiply(const b: IECFieldElement): IECFieldElement;
-begin
-  result := TFpFieldElement.Create(Fq, Fr, ModMult(Fx, b.ToBigInteger()));
-end;
-
-function TFpFieldElement.MultiplyMinusProduct(const b, x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, bx, xx, yx, ab, xy: TBigInteger;
-begin
-  ax := Fx;
-  bx := b.ToBigInteger();
-  xx := x.ToBigInteger();
-  yx := y.ToBigInteger();
-  ab := ax.Multiply(bx);
-  xy := xx.Multiply(yx);
-  result := TFpFieldElement.Create(Fq, Fr, ModReduce(ab.Subtract(xy)));
-end;
-
-function TFpFieldElement.MultiplyPlusProduct(const b, x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, bx, xx, yx, ab, xy, sum: TBigInteger;
-begin
-  ax := Fx;
-  bx := b.ToBigInteger();
-  xx := x.ToBigInteger();
-  yx := y.ToBigInteger();
-  ab := ax.Multiply(bx);
-  xy := xx.Multiply(yx);
-  sum := ab.Add(xy);
-  if ((Fr.IsInitialized) and (Fr.SignValue < 0) and
-    (sum.BitLength > (Fq.BitLength shl 1))) then
-  begin
-    sum := sum.Subtract(Fq.ShiftLeft(Q.BitLength));
-  end;
-  result := TFpFieldElement.Create(Fq, Fr, ModReduce(sum));
-end;
-
-function TFpFieldElement.Negate: IECFieldElement;
-begin
-  if Fx.SignValue = 0 then
-  begin
-    result := Self as IECFieldElement
-  end
-  else
-  begin
-    result := TFpFieldElement.Create(Fq, Fr, Fq.Subtract(Fx));
-  end;
-end;
-
-function TFpFieldElement.Sqrt: IECFieldElement;
-var
-  u, v, K, e, t1, t2, t3, t4, y, legendreExponent, x, fourX, qMinusOne,
-    P: TBigInteger;
-  tempRes: TCryptoLibGenericArray<TBigInteger>;
-  CompareRes, ModReduceRes: Boolean;
-begin
-  if (IsZero or IsOne) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  if (not Fq.TestBit(0)) then
-  begin
-    raise ENotImplementedCryptoLibException.CreateRes(@SEvenValue);
-  end;
-
-  if (Fq.TestBit(1)) then // q == 4m + 3
-  begin
-    e := Fq.ShiftRight(2).Add(TBigInteger.One);
-    result := CheckSqrt(TFpFieldElement.Create(Fq, Fr, Fx.ModPow(e, Fq))
-      as IFpFieldElement);
-    Exit;
-  end;
-
-  if (Fq.TestBit(2)) then // q == 8m + 5
-  begin
-    t1 := Fx.ModPow(Fq.ShiftRight(3), Fq);
-    t2 := ModMult(t1, Fx);
-    t3 := ModMult(t2, t1);
-
-    if (t3.Equals(TBigInteger.One)) then
-    begin
-      result := CheckSqrt(TFpFieldElement.Create(Fq, Fr, t2)
-        as IFpFieldElement);
-      Exit;
-    end;
-
-    // TODO This is constant and could be precomputed
-    t4 := TBigInteger.Two.ModPow(Fq.ShiftRight(2), Fq);
-
-    y := ModMult(t2, t4);
-
-    result := CheckSqrt(TFpFieldElement.Create(Fq, Fr, y) as IFpFieldElement);
-    Exit;
-  end;
-
-  // q == 8m + 1
-
-  legendreExponent := Fq.ShiftRight(1);
-  if (not(Fx.ModPow(legendreExponent, Fq).Equals(TBigInteger.One))) then
-  begin
-    result := Nil;
-    Exit;
-  end;
-
-  x := Fx;
-  fourX := ModDouble(ModDouble(x));
-
-  K := legendreExponent.Add(TBigInteger.One);
-  qMinusOne := Fq.Subtract(TBigInteger.One);
-
-  repeat
-
-    repeat
-      P := TBigInteger.Arbitrary(Fq.BitLength);
-
-      CompareRes := P.CompareTo(Q) >= 0;
-      ModReduceRes := (not ModReduce(P.Multiply(P).Subtract(fourX))
-        .ModPow(legendreExponent, Q).Equals(qMinusOne));
-
-    until ((not CompareRes) and (not ModReduceRes));
-
-    tempRes := LucasSequence(P, x, K);
-    u := tempRes[0];
-    v := tempRes[1];
-
-    if (ModMult(v, v).Equals(fourX)) then
-    begin
-      result := TFpFieldElement.Create(Fq, Fr, ModHalfAbs(v));
-      Exit;
-    end;
-
-  until ((not u.Equals(TBigInteger.One)) or (not u.Equals(qMinusOne)));
-  result := Nil;
-end;
-
-function TFpFieldElement.Square: IECFieldElement;
-begin
-  result := TFpFieldElement.Create(Fq, Fr, ModMult(Fx, Fx));
-end;
-
-function TFpFieldElement.SquareMinusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, xx, yx, aa, xy: TBigInteger;
-begin
-  ax := Fx;
-  xx := x.ToBigInteger();
-  yx := y.ToBigInteger();
-  aa := ax.Multiply(ax);
-  xy := xx.Multiply(yx);
-  result := TFpFieldElement.Create(Fq, Fr, ModReduce(aa.Subtract(xy)));
-end;
-
-function TFpFieldElement.SquarePlusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, xx, yx, aa, xy, sum: TBigInteger;
-begin
-  ax := Fx;
-  xx := x.ToBigInteger();
-  yx := y.ToBigInteger();
-  aa := ax.Multiply(ax);
-  xy := xx.Multiply(yx);
-  sum := aa.Add(xy);
-  if ((Fr.IsInitialized) and (Fr.SignValue < 0) and
-    (sum.BitLength > (Fq.BitLength shl 1))) then
-  begin
-    sum := sum.Subtract(Fq.ShiftLeft(Fq.BitLength));
-  end;
-  result := TFpFieldElement.Create(Fq, Fr, ModReduce(sum));
-end;
-
-function TFpFieldElement.Subtract(const b: IECFieldElement): IECFieldElement;
-begin
-  result := TFpFieldElement.Create(Fq, Fr, ModSubtract(Fx, b.ToBigInteger()));
-end;
-
-function TFpFieldElement.ToBigInteger: TBigInteger;
-begin
-  result := Fx;
-end;
-
-{ TAbstract2mFieldElement }
-
-function TAbstractF2mFieldElement.HalfTrace: IECFieldElement;
-var
-  m, n, K, nk: Int32;
-  ht: IECFieldElement;
-begin
-  m := FieldSize;
-  if ((m and 1) = 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SHalfTraceUndefinedForM);
-  end;
-
-  n := TBitOperations.Asr32((m + 1), 1);
-  K := 31 - TBitOperations.NumberOfLeadingZeros32(n);
-  nk := 1;
-
-  ht := Self as IECFieldElement;
-  while (K > 0) do
-  begin
-    ht := ht.SquarePow(nk shl 1).Add(ht);
-    System.Dec(K);
-    nk := TBitOperations.Asr32(n, K);
-
-    if ((nk and 1) <> 0) then
-    begin
-      ht := ht.SquarePow(2).Add(Self as IECFieldElement);
-    end;
-  end;
-  result := ht;
-end;
-
-function TAbstractF2mFieldElement.HasFastTrace: Boolean;
-begin
-  result := false;
-
-end;
-
-function TAbstractF2mFieldElement.Trace: Int32;
-var
-  m, K, mk: Int32;
-  tr: IECFieldElement;
-begin
-  m := FieldSize;
-
-  K := 31 - TBitOperations.NumberOfLeadingZeros32(m);
-  mk := 1;
-
-  tr := Self as IECFieldElement;
-  while (K > 0) do
-  begin
-    tr := tr.SquarePow(mk).Add(tr);
-
-    System.Dec(K);
-    mk := TBitOperations.Asr32(m, K);
-
-    if ((mk and 1) <> 0) then
-    begin
-      tr := tr.Square().Add(Self as IECFieldElement);
-    end;
-  end;
-
-  if (tr.IsZero) then
-  begin
-    result := 0;
-    Exit;
-  end;
-  if (tr.IsOne) then
-  begin
-    result := 1;
-    Exit;
-  end;
-  raise EArgumentCryptoLibException.CreateRes(@STraceInternalErrorCalculation);
-end;
-
-{ TECCurve }
-
-procedure TECCurve.CheckPoint(const point: IECPoint);
-begin
-  if ((point = Nil) or ((Self as IECCurve) <> point.curve)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointOnCurve);
-  end;
-end;
-
-procedure TECCurve.CheckPoints(const points: TCryptoLibGenericArray<IECPoint>);
-begin
-  CheckPoints(points, 0, System.Length(points));
-end;
-
-procedure TECCurve.CheckPoints(const points: TCryptoLibGenericArray<IECPoint>;
-  off, len: Int32);
-var
-  i: Int32;
-  point: IECPoint;
-begin
-  if (points = Nil) then
-  begin
-    raise EArgumentNilCryptoLibException.CreateRes(@SPointsNil);
-  end;
-  if ((off < 0) or (len < 0) or (off > (System.Length(points) - len))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidRangeSpecified);
-  end;
-
-  for i := 0 to System.Pred(len) do
-
-  begin
-    point := points[off + i];
-    if ((point <> Nil) and ((Self as IECCurve) <> point.curve)) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SInvalidPointOnCurve2);
-    end;
-  end;
-end;
-
-function TECCurve.Configure: IConfig;
-begin
-  result := TConfig.Create(Self as IECCurve, Self.Fm_coord,
-    Self.Fm_endomorphism, Self.Fm_multiplier);
-end;
-
-function TECCurve.GetFieldElementEncodingLength: Int32;
-begin
-  Result := (FieldSize + 7) div 8;
-end;
-
-constructor TECCurve.Create(const field: IFiniteField);
-begin
-  inherited Create();
-  FLock := TCriticalSection.Create;
-  Fm_field := field;
-end;
-
-destructor TECCurve.Destroy;
-begin
-  FLock.Free;
-  inherited Destroy;
-end;
-
-function TECCurve.CreateCacheSafeLookupTable(const 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;
-var
-  glvEndomorphism: IGlvEndomorphism;
-begin
-  if (Supports(Fm_endomorphism, IGlvEndomorphism, glvEndomorphism)) then
-  begin
-    result := TGlvMultiplier.Create(Self as IECCurve, glvEndomorphism);
-    Exit;
-  end;
-
-  result := TWNafL2RMultiplier.Create();
-end;
-
-function TECCurve.CreatePoint(const x, y: TBigInteger): IECPoint;
-begin
-  result := CreatePoint(x, y, false);
-end;
-
-function TECCurve.CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
-  : IECPoint;
-begin
-  result := CreateRawPoint(FromBigInteger(x), FromBigInteger(y),
-    withCompression);
-end;
-
-function TECCurve.DecodePoint(const encoded: TCryptoLibByteArray): IECPoint;
-var
-  x, y: TBigInteger;
-  P: IECPoint;
-  expectedLength, yTilde: Int32;
-  ltype: Byte;
-begin
-  P := Nil;
-  expectedLength := (FieldSize + 7) div 8;
-
-  ltype := encoded[0];
-  case ltype of
-    $00: // infinity
-      begin
-        if (System.Length(encoded) <> 1) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes
-            (@SIncorrectLengthInfinityEncoding);
-        end;
-
-        P := Infinity;
-      end;
-
-    $02, // compressed
-    $03: // compressed
-      begin
-        if (System.Length(encoded) <> (expectedLength + 1)) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes
-            (@SIncorrectLengthCompressedEncoding);
-        end;
-
-        yTilde := ltype and 1;
-        x := TBigInteger.Create(1, encoded, 1, expectedLength);
-
-        P := DecompressPoint(yTilde, x);
-        // TODO Skip curve equation check?
-        if ((not P.ImplIsValid(true, true))) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes(@SInvalidPoint);
-        end;
-      end;
-
-    $04: // uncompressed
-      begin
-        if (System.Length(encoded) <> ((2 * expectedLength) + 1)) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes
-            (@SIncorrectLengthUnCompressedEncoding);
-        end;
-
-        x := TBigInteger.Create(1, encoded, 1, expectedLength);
-        y := TBigInteger.Create(1, encoded, 1 + expectedLength, expectedLength);
-
-        P := ValidatePoint(x, y);
-      end;
-
-    $06, // hybrid
-    $07: // hybrid
-      begin
-        if (System.Length(encoded) <> ((2 * expectedLength) + 1)) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes
-            (@SIncorrectLengthHybridEncoding);
-        end;
-
-        x := TBigInteger.Create(1, encoded, 1, expectedLength);
-        y := TBigInteger.Create(1, encoded, 1 + expectedLength, expectedLength);
-
-        if ((y.TestBit(0)) <> (ltype = $07)) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes(@SInConsistentYCoord);
-        end;
-
-        P := ValidatePoint(x, y);
-      end
-
-  else
-    begin
-      raise EFormatCryptoLibException.CreateResFmt
-        (@SInvalidPointEncoding, [ltype]);
-    end;
-
-  end;
-
-  if ((ltype <> $00) and (P.IsInfinity)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidInfinityEncoding);
-  end;
-
-  result := P;
-end;
-
-function TECCurve.Equals(const other: IECCurve): Boolean;
-begin
-  if ((Self as IECCurve) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := (field as TObject).Equals(other.field as TObject) and
-    (a.ToBigInteger().Equals(other.a.ToBigInteger())) and
-    (b.ToBigInteger().Equals(other.b.ToBigInteger()));
-end;
-
-function TECCurve.GetA: IECFieldElement;
-begin
-  result := Fm_a;
-end;
-
-class function TECCurve.GetAllCoordinateSystems: TCryptoLibInt32Array;
-begin
-  result := TCryptoLibInt32Array.Create(TECCurveConstants.COORD_AFFINE,
-    TECCurveConstants.COORD_HOMOGENEOUS, TECCurveConstants.COORD_JACOBIAN,
-    TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED,
-    TECCurveConstants.COORD_LAMBDA_AFFINE,
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE, TECCurveConstants.COORD_SKEWED);
-end;
-
-function TECCurve.GetB: IECFieldElement;
-begin
-  result := Fm_b;
-end;
-
-function TECCurve.GetCofactor: TBigInteger;
-begin
-  result := Fm_cofactor;
-end;
-
-function TECCurve.GetCoordinateSystem: Int32;
-begin
-  result := Fm_coord;
-end;
-
-function TECCurve.GetEndomorphism: IECEndomorphism;
-begin
-  result := Fm_endomorphism;
-end;
-
-function TECCurve.GetField: IFiniteField;
-begin
-  result := Fm_field;
-end;
-
-function TECCurve.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-begin
-  result := (field as TObject).GetHashCode()
-    xor Int32(TBitOperations.RotateLeft32(a.ToBigInteger().GetHashCode(), 8))
-    xor Int32(TBitOperations.RotateLeft32(b.ToBigInteger().GetHashCode(), 16));
-end;
-
-function TECCurve.GetMultiplier: IECMultiplier;
-begin
-
-  FLock.Acquire;
-  try
-    if (Fm_multiplier = Nil) then
-    begin
-      Fm_multiplier := CreateDefaultMultiplier();
-    end;
-    result := Fm_multiplier;
-  finally
-    FLock.Release;
-  end;
-
-end;
-
-function TECCurve.GetOrder: TBigInteger;
-begin
-  result := Fm_order;
-end;
-
-function TECCurve.GetPreCompInfo(const point: IECPoint; const name: String)
-  : IPreCompInfo;
-var
-  table: TDictionary<String, IPreCompInfo>;
-begin
-  CheckPoint(point);
-
-  FLock.Acquire;
-  try
-    table := point.preCompTable;
-    if table = Nil then
-    begin
-      result := Nil;
-    end
-    else
-    begin
-      table.TryGetValue(name, result);
-    end;
-  finally
-    FLock.Release;
-  end;
-end;
-
-function TECCurve.ImportPoint(const P: IECPoint): IECPoint;
-var
-  Lp: IECPoint;
-begin
-  if ((Self as IECCurve) = P.curve) then
-  begin
-    result := P;
-    Exit;
-  end;
-  if (P.IsInfinity) then
-  begin
-    result := Infinity;
-    Exit;
-  end;
-
-  // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
-  Lp := P.Normalize();
-
-  result := CreatePoint(Lp.XCoord.ToBigInteger(), Lp.YCoord.ToBigInteger(),
-    Lp.IsCompressed);
-end;
-
-procedure TECCurve.NormalizeAll(const points: TCryptoLibGenericArray<IECPoint>;
-  off, len: Int32; const iso: IECFieldElement);
-var
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-  indices: TCryptoLibInt32Array;
-  count, i, j, index: Int32;
-  P: IECPoint;
-begin
-  CheckPoints(points, off, len);
-  case CoordinateSystem of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        if (iso <> Nil) then
-        begin
-          raise EArgumentCryptoLibException.CreateRes
-            (@SInvalidAffineCoordinates);
-        end;
-
-        Exit;
-      end;
-  end;
-
-  // /*
-  // * Figure out which of the points actually need to be normalized
-  // */
-  System.SetLength(zs, len);
-  System.SetLength(indices, len);
-
-  count := 0;
-  for i := 0 to System.Pred(len) do
-
-  begin
-    P := points[off + i];
-    if ((P <> Nil) and ((iso <> Nil) or (not(P.IsNormalized())))) then
-    begin
-      zs[count] := P.GetZCoord(0);
-      indices[count] := off + i;
-      System.Inc(count);
-    end;
-  end;
-
-  if (count = 0) then
-  begin
-    Exit;
-  end;
-
-  TECAlgorithms.MontgomeryTrick(zs, 0, count, iso);
-
-  for j := 0 to System.Pred(count) do
-
-  begin
-    index := indices[j];
-    points[index] := points[index].Normalize(zs[j]);
-  end;
-
-end;
-
-procedure TECCurve.NormalizeAll(const points: TCryptoLibGenericArray<IECPoint>);
-begin
-  NormalizeAll(points, 0, System.Length(points), Nil);
-end;
-
-procedure TECCurve.SetCoord(const Value: Int32);
-begin
-  Fm_coord := Value;
-end;
-
-procedure TECCurve.SetEndomorphism(const Value: IECEndomorphism);
-begin
-  Fm_endomorphism := Value;
-end;
-
-procedure TECCurve.SetMultiplier(const Value: IECMultiplier);
-begin
-  Fm_multiplier := Value;
-end;
-
-function TECCurve.Precompute(const point: IECPoint; const name: String;
-  const callback: IPreCompCallback): IPreCompInfo;
-
-function IsHeavy(const info: IPreCompInfo): Boolean;
-var
-  wnaf: IWNafPreCompInfo;
-  wtnaf: IWTauNafPreCompInfo;
-  endo: IEndoPreCompInfo;
-  fixed: IFixedPointPreCompInfo;
-begin
-  Result :=
-    Supports(info, IWNafPreCompInfo, wnaf) or
-    Supports(info, IWTauNafPreCompInfo, wtnaf) or
-    Supports(info, IEndoPreCompInfo, endo) or
-    Supports(info, IFixedPointPreCompInfo, fixed);
-end;
-
-var
-  table: TDictionary<String, IPreCompInfo>;
-  existing: IPreCompInfo;
-begin
-  CheckPoint(point);
-
-  FLock.Acquire;
-  try
-    table := point.preCompTable;
-    if table = Nil then
-    begin
-      table := TDictionary<String, IPreCompInfo>.Create(4);
-      point.preCompTable := table;
-    end;
-
-    table.TryGetValue(name, existing);
-
-    result := callback.Precompute(existing);
-
-   if (result <> existing) and ((existing <> Nil) or (not IsHeavy(result))) then
-   begin
-     table.AddOrSetValue(name, result);
-   end;
-
-  finally
-    FLock.Release;
-  end;
-end;
-
-function TECCurve.SupportsCoordinateSystem(coord: Int32): Boolean;
-begin
-  result := coord = TECCurveConstants.COORD_AFFINE;
-end;
-
-function TECCurve.ValidatePoint(const x, y: TBigInteger;
-  withCompression: Boolean): IECPoint;
-var
-  P: IECPoint;
-begin
-  P := CreatePoint(x, y, withCompression);
-  if (not P.IsValid()) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointCoordinates);
-  end;
-  result := P;
-end;
-
-function TECCurve.ValidatePoint(const x, y: TBigInteger): IECPoint;
-var
-  P: IECPoint;
-begin
-  P := CreatePoint(x, y);
-  if (not P.IsValid()) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointCoordinates);
-  end;
-  result := P;
-end;
-
-{ TECCurve.TConfig }
-
-constructor TECCurve.TConfig.Create(const outer: IECCurve; coord: Int32;
-  const endomorphism: IECEndomorphism; const multiplier: IECMultiplier);
-begin
-  Inherited Create();
-  Fouter := outer;
-  Fcoord := coord;
-  Fendomorphism := endomorphism;
-  Fmultiplier := multiplier;
-end;
-
-function TECCurve.TConfig.CreateCurve: IECCurve;
-var
-  c: IECCurve;
-begin
-  if (not Fouter.SupportsCoordinateSystem(Fcoord)) then
-  begin
-    raise EInvalidOperationCryptoLibException.CreateRes
-      (@SUnSupportedCoordinateSystem);
-  end;
-
-  c := Fouter.CloneCurve();
-  if (c = Fouter) then
-  begin
-    raise EInvalidOperationCryptoLibException.CreateRes(@SCurrentCurve);
-  end;
-
-  c.coord := Fcoord;
-  c.endomorphism := Fendomorphism;
-  c.multiplier := Fmultiplier;
-
-  result := c;
-end;
-
-destructor TECCurve.TConfig.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TECCurve.TConfig.SetCoordinateSystem(coord: Int32): IConfig;
-begin
-  Fcoord := coord;
-  result := Self as IConfig;
-end;
-
-function TECCurve.TConfig.SetEndomorphism(const endomorphism
-  : IECEndomorphism): IConfig;
-begin
-  Fendomorphism := endomorphism;
-  result := Self as IConfig;
-end;
-
-function TECCurve.TConfig.SetMultiplier(const multiplier
-  : IECMultiplier): IConfig;
-begin
-  Fmultiplier := multiplier;
-  result := Self as IConfig;
-end;
-
-{ TAbstractFpCurve }
-
-constructor TAbstractFpCurve.Create(const Q: TBigInteger);
-begin
-  Inherited Create(TFiniteFields.GetPrimeField(Q));
-end;
-
-function TAbstractFpCurve.DecompressPoint(yTilde: Int32; const x1: TBigInteger)
-  : IECPoint;
-var
-  x, rhs, y: IECFieldElement;
-begin
-  x := FromBigInteger(x1);
-  rhs := x.Square().Add(a).Multiply(x).Add(b);
-  y := rhs.Sqrt();
-
-  // /*
-  // * If y is not a square, then we haven't got a point on the curve
-  // */
-  if (y = Nil) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointCompression);
-  end;
-
-  if (y.TestBitZero() <> (yTilde = 1)) then
-  begin
-    // Use the other root
-    y := y.Negate();
-  end;
-
-  result := CreateRawPoint(x, y, true);
-end;
-
-destructor TAbstractFpCurve.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TAbstractFpCurve.IsValidFieldElement(const x: TBigInteger): Boolean;
-begin
-  result := (x.IsInitialized) and (x.SignValue >= 0) and
-    (x.CompareTo(field.Characteristic) < 0);
-end;
-
-{ TFpCurve }
-
-function TFpCurve.CloneCurve: IECCurve;
-begin
-  result := TFpCurve.Create(Fm_q, Fm_r, Fm_a, Fm_b, Fm_order, Fm_cofactor);
-end;
-
-constructor TFpCurve.Create(const Q, r: TBigInteger;
-  const a, b: IECFieldElement; const Order, Cofactor: TBigInteger);
-begin
-  Inherited Create(Q);
-  Fm_q := Q;
-  Fm_r := r;
-  Fm_infinity := TFpPoint.Create(Self as IECCurve, Nil, Nil, false);
-
-  Fm_a := a;
-  Fm_b := b;
-  Fm_order := Order;
-  Fm_cofactor := Cofactor;
-  Fm_coord := FP_DEFAULT_COORDS;
-end;
-
-constructor TFpCurve.Create(const Q, r: TBigInteger;
-  const a, b: IECFieldElement);
-begin
-  Create(Q, r, a, b, TBigInteger.GetDefault, TBigInteger.GetDefault);
-end;
-
-constructor TFpCurve.Create(const Q, a, b, Order, Cofactor: TBigInteger);
-begin
-  Inherited Create(Q);
-  Fm_q := Q;
-  Fm_r := TFpFieldElement.CalculateResidue(Q);
-  Fm_infinity := TFpPoint.Create(Self as IECCurve, Nil, Nil, false);
-
-  Fm_a := FromBigInteger(a);
-  Fm_b := FromBigInteger(b);
-  Fm_order := Order;
-  Fm_cofactor := Cofactor;
-  Fm_coord := FP_DEFAULT_COORDS;
-end;
-
-constructor TFpCurve.Create(const Q, a, b: TBigInteger);
-begin
-  Create(Q, a, b, TBigInteger.GetDefault, TBigInteger.GetDefault);
-end;
-
-function TFpCurve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
-begin
-  result := TFpPoint.Create(Self as IECCurve, x, y, zs, withCompression);
-end;
-
-destructor TFpCurve.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TFpCurve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
-begin
-  result := TFpPoint.Create(Self as IECCurve, x, y, withCompression);
-end;
-
-function TFpCurve.FromBigInteger(const x: TBigInteger): IECFieldElement;
-begin
-  result := TFpFieldElement.Create(Fm_q, Fm_r, x);
-end;
-
-function TFpCurve.GetFieldSize: Int32;
-begin
-  result := Fm_q.BitLength;
-end;
-
-function TFpCurve.GetInfinity: IECPoint;
-begin
-  result := Fm_infinity;
-end;
-
-function TFpCurve.GetQ: TBigInteger;
-begin
-  result := Fm_q;
-end;
-
-function TFpCurve.ImportPoint(const P: IECPoint): IECPoint;
-begin
-  if ((Self as IECCurve <> P.curve) and
-    (CoordinateSystem = TECCurveConstants.COORD_JACOBIAN) and (not P.IsInfinity))
-  then
-  begin
-    case P.curve.CoordinateSystem of
-      TECCurveConstants.COORD_JACOBIAN,
-        TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
-        TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-        begin
-          result := TFpPoint.Create(Self as IECCurve,
-            FromBigInteger(P.RawXCoord.ToBigInteger()),
-            FromBigInteger(P.RawYCoord.ToBigInteger()),
-            TCryptoLibGenericArray<IECFieldElement>.Create
-            (FromBigInteger(P.GetZCoord(0).ToBigInteger())), P.IsCompressed);
-          Exit;
-        end;
-    end;
-  end;
-
-  result := (Inherited ImportPoint(P));
-end;
-
-function TFpCurve.SupportsCoordinateSystem(coord: Int32): Boolean;
-begin
-  case coord of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_HOMOGENEOUS,
-      TECCurveConstants.COORD_JACOBIAN,
-      TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        result := true;
-      end
-  else
-    begin
-      result := false;
-    end;
-  end;
-end;
-
-{ TAbstractF2mCurve }
-
-class function TAbstractF2mCurve.BuildField(m, k1, k2, k3: Int32): IFiniteField;
-begin
-  if (k1 = 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidK1);
-  end;
-
-  if (k2 = 0) then
-  begin
-    if (k3 <> 0) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SInvalidK3);
-    end;
-
-    result := TFiniteFields.GetBinaryExtensionField
-      (TCryptoLibInt32Array.Create(0, k1, m));
-    Exit;
-  end;
-
-  if (k2 <= k1) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SK2K1MisMatch);
-  end;
-
-  if (k3 <= k2) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SK3K2Mismatch);
-  end;
-
-  result := TFiniteFields.GetBinaryExtensionField(TCryptoLibInt32Array.Create(0,
-    k1, k2, k3, m));
-end;
-
-constructor TAbstractF2mCurve.Create(m, k1, k2, k3: Int32);
-begin
-  Inherited Create(BuildField(m, k1, k2, k3));
-end;
-
-function TAbstractF2mCurve.CreatePoint(const x, y: TBigInteger;
-  withCompression: Boolean): IECPoint;
-var
-  Lx, LY: IECFieldElement;
-begin
-  Lx := FromBigInteger(x);
-  LY := FromBigInteger(y);
-
-  case CoordinateSystem of
-    TECCurveConstants.COORD_LAMBDA_AFFINE,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        if (Lx.IsZero) then
-        begin
-          if (not LY.Square().Equals(b)) then
-          begin
-            raise EArgumentCryptoLibException.Create('');
-          end;
-        end
-        else
-        begin
-          // Y becomes Lambda (X + Y/X) here
-          LY := LY.Divide(Lx).Add(Lx);
-        end;
-      end;
-  end;
-
-  result := CreateRawPoint(Lx, LY, withCompression);
-end;
-
-function TAbstractF2mCurve.DecompressPoint(yTilde: Int32; const x1: TBigInteger)
-  : IECPoint;
-var
-  xp, yp, beta, z: IECFieldElement;
-begin
-  xp := FromBigInteger(x1);
-  yp := Nil;
-  if (xp.IsZero) then
-  begin
-    yp := b.Sqrt();
-  end
-  else
-  begin
-    beta := xp.Square().Invert().Multiply(b).Add(a).Add(xp);
-    z := SolveQuadraticEquation(beta);
-
-    if (z <> Nil) then
-    begin
-      if (z.TestBitZero() <> (yTilde = 1)) then
-      begin
-        z := z.AddOne();
-      end;
-
-      case CoordinateSystem of
-        TECCurveConstants.COORD_LAMBDA_AFFINE,
-          TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-          begin
-            yp := z.Add(xp);
-          end
-      else
-        begin
-          yp := z.Multiply(xp);
-        end;
-      end;
-
-    end;
-
-  end;
-
-  if (yp = Nil) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidPointCompression);
-  end;
-
-  result := CreateRawPoint(xp, yp, true);
-end;
-
-destructor TAbstractF2mCurve.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TAbstractF2mCurve.GetIsKoblitz: Boolean;
-begin
-  result := (Fm_order.IsInitialized) and (Fm_cofactor.IsInitialized) and
-    (Fm_b.IsOne) and (Fm_a.IsZero or Fm_a.IsOne);
-end;
-
-function TAbstractF2mCurve.GetSi: TCryptoLibGenericArray<TBigInteger>;
-begin
-  if (Fsi = Nil) then
-  begin
-
-    FLock.Acquire;
-    try
-      if (Fsi = Nil) then
-      begin
-        Fsi := TTnaf.GetSi(Self as IAbstractF2mCurve);
-      end;
-    finally
-      FLock.Release;
-    end;
-  end;
-  result := Fsi;
-end;
-
-class function TAbstractF2mCurve.Inverse(m: Int32;
-  const ks: TCryptoLibInt32Array; const x: TBigInteger): TBigInteger;
-var
-  LA: TLongArray;
-begin
-  LA := TLongArray.Create(x);
-  result := LA.ModInverse(m, ks).ToBigInteger();
-end;
-
-function TAbstractF2mCurve.IsValidFieldElement(const x: TBigInteger): Boolean;
-begin
-  result := (x.IsInitialized) and (x.SignValue >= 0) and
-    (x.BitLength <= FieldSize);
-end;
-
-function TAbstractF2mCurve.SolveQuadraticEquation(const beta: IECFieldElement)
-  : IECFieldElement;
-var
-  gamma, z, zeroElement, t, w, w2, r: IECFieldElement;
-  betaF2m: IAbstractF2mFieldElement;
-  m, i: Int32;
-  fastTrace: Boolean;
-begin
-
-  betaF2m := beta as IAbstractF2mFieldElement;
-
-  fastTrace := betaF2m.HasFastTrace();
-  if ((fastTrace) and (betaF2m.Trace() <> 0)) then
-  begin
-    result := Nil;
-    Exit;
-  end;
-
-  m := FieldSize;
-
-  // For odd m, use the half-trace
-  if ((m and 1) <> 0) then
-  begin
-    r := betaF2m.HalfTrace();
-    if ((fastTrace) or (r.Square().Add(r).Add(beta).IsZero)) then
-    begin
-      result := r;
-      Exit;
-    end;
-    result := Nil;
-    Exit;
-  end;
-
-  if (beta.IsZero) then
-  begin
-    result := beta;
-    Exit;
-  end;
-
-  zeroElement := FromBigInteger(TBigInteger.Zero);
-
-  m := FieldSize;
-
-  repeat
-    t := FromBigInteger(TBigInteger.Arbitrary(m));
-    z := zeroElement;
-    w := beta;
-    i := 1;
-    while i < m do
-    begin
-      w2 := w.Square();
-      z := z.Square().Add(w2.Multiply(t));
-      w := w2.Add(beta);
-      System.Inc(i);
-    end;
-
-    if (not w.IsZero) then
-    begin
-      result := Nil;
-      Exit;
-    end;
-    gamma := z.Square().Add(z);
-  until (not(gamma.IsZero));
-
-  result := z;
-end;
-
-{ TF2mCurve }
-
-function TF2mCurve.GetFieldSize: Int32;
-begin
-  result := Fm;
-end;
-
-function TF2mCurve.GetInfinity: IECPoint;
-begin
-  result := Fm_infinity;
-end;
-
-function TF2mCurve.GetK1: Int32;
-begin
-  result := Fk1;
-end;
-
-function TF2mCurve.GetK2: Int32;
-begin
-  result := Fk2;
-end;
-
-function TF2mCurve.GetK3: Int32;
-begin
-  result := Fk3;
-end;
-
-function TF2mCurve.GetM: Int32;
-begin
-  result := Fm;
-end;
-
-function TF2mCurve.IsTrinomial: Boolean;
-begin
-  result := (k2 = 0) and (k3 = 0);
-end;
-
-function TF2mCurve.CloneCurve: IECCurve;
-begin
-  result := TF2mCurve.Create(m, k1, k2, k3, Fm_a, Fm_b, Fm_order, Fm_cofactor);
-end;
-
-constructor TF2mCurve.Create(m, K: Int32; const a, b: TBigInteger);
-begin
-  Create(m, K, 0, 0, a, b, TBigInteger.GetDefault, TBigInteger.GetDefault);
-end;
-
-constructor TF2mCurve.Create(m, k1, k2, k3: Int32; const a, b: IECFieldElement;
-  const Order, Cofactor: TBigInteger);
-begin
-  Inherited Create(m, k1, k2, k3);
-  Fm := m;
-  Fk1 := k1;
-  Fk2 := k2;
-  Fk3 := k3;
-  Fm_order := Order;
-  Fm_cofactor := Cofactor;
-
-  Fm_infinity := TF2mPoint.Create(Self as IECCurve, Nil, Nil, false);
-  Fm_a := a;
-  Fm_b := b;
-  Fm_coord := F2M_DEFAULT_COORDS;
-end;
-
-constructor TF2mCurve.Create(m, K: Int32;
-  const a, b, Order, Cofactor: TBigInteger);
-begin
-  Create(m, K, 0, 0, a, b, Order, Cofactor);
-end;
-
-constructor TF2mCurve.Create(m, k1, k2, k3: Int32;
-  const a, b, Order, Cofactor: TBigInteger);
-begin
-  Inherited Create(m, k1, k2, k3);
-  Fm := m;
-  Fk1 := k1;
-  Fk2 := k2;
-  Fk3 := k3;
-  Fm_order := Order;
-  Fm_cofactor := Cofactor;
-  Fm_infinity := TF2mPoint.Create(Self as IECCurve, Nil, Nil, false);
-
-  if (k1 = 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidK1);
-  end;
-
-  if (k2 = 0) then
-  begin
-    if (k3 <> 0) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SInvalidK3);
-    end;
-  end
-  else
-  begin
-    if (k2 <= k1) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SK2K1MisMatch);
-    end;
-
-    if (k3 <= k2) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SK3K2Mismatch);
-    end;
-  end;
-
-  Fm_a := FromBigInteger(a);
-  Fm_b := FromBigInteger(b);
-  Fm_coord := F2M_DEFAULT_COORDS;
-
-end;
-
-function TF2mCurve.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  FE_LONGS, position, i: Int32;
-  table: TCryptoLibUInt64Array;
-  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);
-begin
-  Create(m, k1, k2, k3, a, b, TBigInteger.GetDefault, TBigInteger.GetDefault);
-end;
-
-function TF2mCurve.CreateDefaultMultiplier: IECMultiplier;
-begin
-  if (IsKoblitz) then
-  begin
-    result := TWTauNafMultiplier.Create();
-    Exit;
-  end;
-
-  result := (Inherited CreateDefaultMultiplier());
-end;
-
-function TF2mCurve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
-begin
-  result := TF2mPoint.Create(Self as IECCurve, x, y, withCompression);
-end;
-
-function TF2mCurve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
-begin
-  result := TF2mPoint.Create(Self as IECCurve, x, y, zs, withCompression);
-end;
-
-destructor TF2mCurve.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TF2mCurve.FromBigInteger(const x: TBigInteger): IECFieldElement;
-begin
-  result := TF2mFieldElement.Create(Fm, Fk1, Fk2, Fk3, x);
-end;
-
-function TF2mCurve.SupportsCoordinateSystem(coord: Int32): Boolean;
-begin
-  case coord of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_HOMOGENEOUS,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        result := true;
-      end
-  else
-    begin
-      result := false;
-    end;
-  end;
-end;
-
-{ TDefaultLookupTable }
-
-constructor TDefaultLookupTable.Create(const outer: IECCurve;
-  const table: TCryptoLibByteArray; Size: Int32);
-begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := Size;
-end;
-
-function TDefaultLookupTable.CreatePoint(const x, y: TCryptoLibByteArray)
-  : IECPoint;
-var
-  XFieldElement, YFieldElement: IECFieldElement;
-begin
-  XFieldElement := Fm_outer.FromBigInteger(TBigInteger.Create(1, x));
-  YFieldElement := Fm_outer.FromBigInteger(TBigInteger.Create(1, y));
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement, false);
-end;
-
-destructor TDefaultLookupTable.Destroy;
-begin
-  Fm_outer := nil;
-  Fm_table := nil;
-  inherited;
-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;
-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(TBitOperations.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;
-
-  result := CreatePoint(x, y);
-end;
-
-function TDefaultLookupTable.LookupVar(index: Int32): IECPoint;
-var
-  FE_BYTES, position, j: Int32;
-  x, y: TCryptoLibByteArray;
-begin
-  FE_BYTES := (Fm_outer.FieldSize + 7) div 8;
-  System.SetLength(x, FE_BYTES);
-  System.SetLength(y, FE_BYTES);
-
-  position := index * FE_BYTES * 2;
-
-  for j := 0 to System.Pred(FE_BYTES) do
-  begin
-    x[j] := Fm_table[position + j];
-    y[j] := Fm_table[position + FE_BYTES + j];
-  end;
-
-  result := CreatePoint(x, y);
-end;
-
-{ TDefaultF2mLookupTable }
-
-constructor TDefaultF2mLookupTable.Create(const outer: IF2mCurve;
-  const table: TCryptoLibUInt64Array; Size: Int32);
-begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := Size;
-end;
-
-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
-  begin
-    ks := TCryptoLibInt32Array.Create(Fm_outer.k1);
-  end
-  else
-  begin
-    ks := TCryptoLibInt32Array.Create(Fm_outer.k1, Fm_outer.k2, Fm_outer.k3);
-  end;
-
-  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;
-
-
-destructor TDefaultF2mLookupTable.Destroy;
-begin
-  Fm_outer := nil;
-  Fm_table := nil;
-  inherited;
-end;
-
-function TDefaultF2mLookupTable.GetSize: Int32;
-begin
-  result := Fm_size;
-end;
-
-function TDefaultF2mLookupTable.Lookup(index: Int32): IECPoint;
-var
-  FE_LONGS, position, i, j: Int32;
-  x, y: TCryptoLibUInt64Array;
-  MASK: UInt64;
-begin
-  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 := UInt64(TBitOperations.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;
-
-  result := CreatePoint(x, y);
-end;
-
-function TDefaultF2mLookupTable.LookupVar(index: Int32): IECPoint;
-var
-  FE_LONGS, position, j: Int32;
-  x, y: TCryptoLibUInt64Array;
-begin
-  FE_LONGS := (Fm_outer.m + 63) div 64;
-  System.SetLength(x, FE_LONGS);
-  System.SetLength(y, FE_LONGS);
-
-  position := index * FE_LONGS * 2;
-
-  for j := 0 to System.Pred(FE_LONGS) do
-  begin
-    x[j] := Fm_table[position + j];
-    y[j] := Fm_table[position + FE_LONGS + j];
-  end;
-
-  result := CreatePoint(x, y);
-end;
-
-{ TECPoint }
-
-function TECPoint.GetIsCompressed: Boolean;
-begin
-  result := Fm_withCompression;
-end;
-
-function TECPoint.GetIsInfinity: Boolean;
-begin
-  // result := (Fm_x = Nil) and (Fm_y = Nil);
-  result := (Fm_x = Nil) or (Fm_y = Nil) or
-    ((System.Length(Fm_zs) > 0) and (Fm_zs[0].IsZero));
-end;
-
-function TECPoint.RawXCoord: IECFieldElement;
-begin
-  result := Fm_x;
-end;
-
-function TECPoint.RawYCoord: IECFieldElement;
-begin
-  result := Fm_y;
-end;
-
-function TECPoint.RawZCoords: TCryptoLibGenericArray<IECFieldElement>;
-begin
-  result := Fm_zs;
-end;
-
-function TECPoint.Normalize: IECPoint;
-var
-  Z1: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  case CurveCoordinateSystem of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        result := Self;
-        Exit;
-      end
-  else
-    begin
-
-      Z1 := RawZCoords[0];
-      if (Z1.IsOne) then
-      begin
-        result := Self;
-        Exit;
-      end;
-
-      result := Normalize(Z1.Invert());
-    end;
-  end;
-end;
-
-function TECPoint.SatisfiesOrder: Boolean;
-var
-  n: TBigInteger;
-begin
-  if (TBigInteger.One.Equals(curve.GetCofactor())) then
-  begin
-    result := true;
-    Exit;
-  end;
-
-  n := curve.GetOrder();
-
-  // TODO Require order to be available for all curves
-
-  result := (not(n.IsInitialized)) or TECAlgorithms.ReferenceMultiply
-    (Self as IECPoint, n).IsInfinity;
-end;
-
-function TECPoint.ScaleX(const scale: IECFieldElement): IECPoint;
-begin
-  if IsInfinity then
-  begin
-    result := Self;
-  end
-  else
-  begin
-    result := curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord,
-      RawZCoords, IsCompressed);
-  end;
-end;
-
-function TECPoint.ScaleXNegateY(const scale: IECFieldElement): IECPoint;
-begin
-  if IsInfinity then
-  begin
-    result := Self;
-  end
-  else
-  begin
-    result := curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord.Negate,
-      RawZCoords, IsCompressed);
-  end;
-end;
-
-function TECPoint.ScaleY(const scale: IECFieldElement): IECPoint;
-begin
-  if IsInfinity then
-  begin
-    result := Self;
-  end
-  else
-  begin
-    result := curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale),
-      RawZCoords, IsCompressed);
-  end;
-end;
-
-function TECPoint.ScaleYNegateX(const scale: IECFieldElement): IECPoint;
-begin
-  if IsInfinity then
-  begin
-    result := Self;
-  end
-  else
-  begin
-    result := curve.CreateRawPoint(RawXCoord.Negate, RawYCoord.Multiply(scale),
-      RawZCoords, IsCompressed);
-  end;
-end;
-
-procedure TECPoint.SetpreCompTable(const Value
-  : TDictionary<String, IPreCompInfo>);
-begin
-  Fm_preCompTable := Value;
-end;
-
-function TECPoint.ThreeTimes: IECPoint;
-begin
-  result := TwicePlus(Self);
-end;
-
-function TECPoint.TimesPow2(e: Int32): IECPoint;
-var
-  P: IECPoint;
-begin
-  if (e < 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SCannotBeNegative);
-  end;
-
-  P := Self;
-  System.Dec(e);
-  while (e >= 0) do
-  begin
-    P := P.Twice();
-    System.Dec(e);
-  end;
-  result := P;
-end;
-
-function TECPoint.ToString: String;
-var
-  sl: TStringList;
-  i: Int32;
-begin
-  if (IsInfinity) then
-  begin
-    result := 'INF';
-    Exit;
-  end;
-
-  sl := TStringList.Create();
-  sl.LineBreak := '';
-  try
-    sl.Add('(');
-    sl.Add(RawXCoord.ToString);
-    sl.Add(',');
-    sl.Add(RawYCoord.ToString);
-    for i := 0 to System.Pred(System.Length(Fm_zs)) do
-    begin
-      sl.Add(',');
-      sl.Add(Fm_zs[i].ToString);
-    end;
-    sl.Add(')');
-    result := sl.Text;
-  finally
-    sl.Free;
-  end;
-end;
-
-function TECPoint.TwicePlus(const b: IECPoint): IECPoint;
-begin
-  result := Twice().Add(b);
-end;
-
-constructor TECPoint.Create(const curve: IECCurve; const x, y: IECFieldElement;
-  withCompression: Boolean);
-begin
-  Create(curve, x, y, GetInitialZCoords(curve), withCompression);
-end;
-
-procedure TECPoint.CheckNormalized;
-begin
-  if (not IsNormalized()) then
-  begin
-    raise EInvalidOperationCryptoLibException.CreateRes(@SPointNotInNormalForm);
-  end;
-end;
-
-constructor TECPoint.Create(const curve: IECCurve; const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create();
-  Fm_curve := curve;
-  Fm_x := x;
-  Fm_y := y;
-  Fm_zs := zs;
-  Fm_withCompression := withCompression;
-end;
-
-function TECPoint.CreateScaledPoint(const sx, sy: IECFieldElement): IECPoint;
-begin
-  result := curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy),
-    IsCompressed);
-end;
-
-destructor TECPoint.Destroy;
-var
-  Key: string;
-begin
-  Fm_curve.Clear;
-
-  if Assigned(Fm_preCompTable) then
-  begin
-    for Key in Fm_preCompTable.Keys do
-      Fm_preCompTable[Key] := nil;
-
-    Fm_preCompTable.Free;
-  end;
-
-  inherited Destroy;
-end;
-
-
-class constructor TECPoint.ECPoint;
-begin
-  System.SetLength(FEMPTY_ZS, 0);
-end;
-
-function TECPoint.Equals(const other: IECPoint): Boolean;
-var
-  c1, c2: IECCurve;
-  n1, n2, i1, i2: Boolean;
-  p1, p2: IECPoint;
-  points: TCryptoLibGenericArray<IECPoint>;
-begin
-  if ((Self as IECPoint) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  c1 := Self.curve;
-  c2 := other.curve;
-  n1 := (c1 = Nil);
-  n2 := (c2 = Nil);
-  i1 := IsInfinity;
-  i2 := other.IsInfinity;
-
-  if (i1 or i2) then
-  begin
-    result := (i1 and i2) and (n1 or n2 or c1.Equals(c2));
-    Exit;
-  end;
-
-  p1 := Self as IECPoint;
-  p2 := other;
-  if (n1 and n2) then
-  begin
-    // Points with null curve are in affine form, so already normalized
-  end
-  else if (n1) then
-  begin
-    p2 := p2.Normalize();
-  end
-  else if (n2) then
-  begin
-    p1 := p1.Normalize();
-  end
-  else if (not c1.Equals(c2)) then
-  begin
-    result := false;
-    Exit;
-  end
-  else
-  begin
-    // TODO Consider just requiring already normalized, to avoid silent performance degradation
-
-    points := TCryptoLibGenericArray<IECPoint>.Create(Self, c1.ImportPoint(p2));
-
-    // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
-    c1.NormalizeAll(points);
-
-    p1 := points[0];
-    p2 := points[1];
-  end;
-
-  result := p1.XCoord.Equals(p2.XCoord) and p1.YCoord.Equals(p2.YCoord);
-end;
-
-function TECPoint.GetEncoded: TCryptoLibByteArray;
-begin
-  result := GetEncoded(Fm_withCompression);
-end;
-
-function TECPoint.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-
-var
-  c: IECCurve;
-  P: IECPoint;
-  hc: Int32;
-begin
-  c := curve;
-  if c = Nil then
-  begin
-    hc := 0;
-  end
-  else
-  begin
-    hc := not c.GetHashCode();
-  end;
-
-  if (not IsInfinity) then
-  begin
-    // TODO Consider just requiring already normalized, to avoid silent performance degradation
-
-    P := Normalize();
-
-    hc := hc xor (P.XCoord.GetHashCode() * 17);
-    hc := hc xor (P.YCoord.GetHashCode() * 257);
-  end;
-
-  result := hc;
-end;
-
-class function TECPoint.GetInitialZCoords(const curve: IECCurve)
-  : TCryptoLibGenericArray<IECFieldElement>;
-var
-  coord: Int32;
-  One: IECFieldElement;
-begin
-  // Cope with null curve, most commonly used by implicitlyCa
-  if curve = Nil then
-  begin
-    coord := TECCurveConstants.COORD_AFFINE;
-  end
-  else
-  begin
-    coord := curve.CoordinateSystem;
-  end;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        result := FEMPTY_ZS;
-        Exit;
-      end;
-  end;
-
-  One := curve.FromBigInteger(TBigInteger.One);
-
-  case coord of
-
-    TECCurveConstants.COORD_HOMOGENEOUS, TECCurveConstants.COORD_JACOBIAN,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        result := TCryptoLibGenericArray<IECFieldElement>.Create(One);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY:
-      begin
-        result := TCryptoLibGenericArray<IECFieldElement>.Create(One, One, One);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        result := TCryptoLibGenericArray<IECFieldElement>.Create(One, curve.a);
-        Exit;
-      end
-
-  else
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SUnknownCoordSystem);
-    end;
-
-  end;
-
-end;
-
-function TECPoint.GetpreCompTable: TDictionary<String, IPreCompInfo>;
-begin
-  result := Fm_preCompTable;
-end;
-
-function TECPoint.GetXCoord: IECFieldElement;
-begin
-  result := Fm_x;
-end;
-
-function TECPoint.GetYCoord: IECFieldElement;
-begin
-  result := Fm_y;
-end;
-
-function TECPoint.GetZCoord(index: Int32): IECFieldElement;
-begin
-  if ((index < 0) or (index >= System.Length(Fm_zs))) then
-  begin
-    result := Nil;
-  end
-  else
-  begin
-    result := Fm_zs[index];
-  end;
-end;
-
-function TECPoint.GetZCoords: TCryptoLibGenericArray<IECFieldElement>;
-var
-  zsLen: Int32;
-begin
-  zsLen := System.Length(Fm_zs);
-  if (zsLen = 0) then
-  begin
-    result := Fm_zs;
-    Exit;
-  end;
-  System.SetLength(result, zsLen);
-  result := System.Copy(Fm_zs, 0, zsLen);
-end;
-
-function TECPoint.ImplIsValid(decompressed, checkOrder: Boolean): Boolean;
-var
-  Validity: IValidityPrecompInfo;
-  callback: IValidityCallback;
-begin
-
-  if (IsInfinity) then
-  begin
-    result := true;
-    Exit;
-  end;
-
-  callback := TValidityCallback.Create(Self as IECPoint, decompressed,
-    checkOrder);
-  Validity := curve.Precompute(Self as IECPoint,
-    TValidityPrecompInfo.PRECOMP_NAME, callback) as IValidityPrecompInfo;
-
-  result := not(Validity.hasFailed());
-end;
-
-function TECPoint.IsNormalized: Boolean;
-var
-  coord: Int32;
-begin
-  coord := CurveCoordinateSystem;
-
-  result := (coord = TECCurveConstants.COORD_AFFINE) or
-    (coord = TECCurveConstants.COORD_LAMBDA_AFFINE) or (IsInfinity) or
-    (RawZCoords[0].IsOne);
-end;
-
-function TECPoint.IsValid: Boolean;
-begin
-  result := ImplIsValid(false, true);
-end;
-
-function TECPoint.IsValidPartial: Boolean;
-begin
-  result := ImplIsValid(false, false);
-end;
-
-function TECPoint.Normalize(const zInv: IECFieldElement): IECPoint;
-var
-  zInv2, zInv3: IECFieldElement;
-begin
-  case CurveCoordinateSystem of
-    TECCurveConstants.COORD_HOMOGENEOUS,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        result := CreateScaledPoint(zInv, zInv);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN,
-      TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
-      TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        zInv2 := zInv.Square();
-        zInv3 := zInv2.Multiply(zInv);
-        result := CreateScaledPoint(zInv2, zInv3);
-        Exit;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SNotProjectiveCoordSystem);
-    end;
-
-  end;
-end;
-
-function TECPoint.GetAffineXCoord: IECFieldElement;
-begin
-  CheckNormalized();
-  result := XCoord;
-end;
-
-function TECPoint.GetAffineYCoord: IECFieldElement;
-begin
-  CheckNormalized();
-  result := YCoord;
-end;
-
-function TECPoint.GetCurve: IECCurve;
-begin
-  result := Fm_curve;
-end;
-
-function TECPoint.GetCurveCoordinateSystem: Int32;
-var
- curve: IECCurve;
-begin
-  // Cope with null curve, most commonly used by implicitlyCa
-  curve := Fm_curve;
-  if curve = Nil then
-  begin
-    result := TECCurveConstants.COORD_AFFINE;
-  end
-  else
-  begin
-    result := curve.CoordinateSystem;
-  end;
-end;
-
-function TECPoint.GetDetachedPoint: IECPoint;
-begin
-  result := Normalize().Detach();
-end;
-
-function TECPoint.Clone: IECPoint;
-var
- baseNorm: IECPoint;
- curve: IECCurve;
-begin
-  curve := Fm_curve;
-  baseNorm := Self.Normalize();
-  Result := curve.CreatePoint(
-          baseNorm.XCoord.ToBigInteger,
-          baseNorm.YCoord.ToBigInteger,
-          baseNorm.IsCompressed
-        );
-end;
-
-{ TF2mPoint }
-
-constructor TF2mPoint.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
-begin
-  Create(curve, x, y, false);
-end;
-
-constructor TF2mPoint.Create(const curve: IECCurve; const x, y: IECFieldElement;
-  withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SNilFieldElement);
-  end;
-
-  if (x <> Nil) then
-  begin
-    // Check if x and y are elements of the same field
-    TF2mFieldElement.CheckFieldElements(x, y);
-
-    // Check if x and a are elements of the same field
-    if (curve <> Nil) then
-    begin
-      TF2mFieldElement.CheckFieldElements(x, curve.a);
-    end;
-  end;
-end;
-
-function TF2mPoint.Add(const b: IECPoint): IECPoint;
-var
-  ecCurve: IECCurve;
-  coord: Int32;
-  x1, x2, Y1, Y2, dx, dy, L, x3, Y3, Z1, Z2, U1, V1, U2, V2, u, v, Vsq, Vcu, w,
-    a, VSqZ2, uv, Z3, L3, L1, L2, S2, S1, ABZ2, AU1, AU2, bigB: IECFieldElement;
-  Z1IsOne, Z2IsOne: Boolean;
-  P: IECPoint;
-begin
-  if (IsInfinity) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  x1 := RawXCoord;
-  x2 := b.RawXCoord;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        Y1 := RawYCoord;
-        Y2 := b.RawYCoord;
-
-        dx := x1.Add(x2);
-        dy := Y1.Add(Y2);
-        if (dx.IsZero) then
-        begin
-          if (dy.IsZero) then
-          begin
-            result := Twice();
-            Exit;
-          end;
-
-          result := ecCurve.Infinity;
-          Exit;
-        end;
-
-        L := dy.Divide(dx);
-
-        x3 := L.Square().Add(L).Add(dx).Add(ecCurve.a);
-        Y3 := L.Multiply(x1.Add(x3)).Add(x3).Add(Y1);
-
-        result := TF2mPoint.Create(ecCurve, x3, Y3, IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        Y1 := RawYCoord;
-        Z1 := RawZCoords[0];
-        Y2 := b.RawYCoord;
-        Z2 := b.RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-        U1 := Y2;
-        V1 := x2;
-        if (not Z1IsOne) then
-        begin
-          U1 := U1.Multiply(Z1);
-          V1 := V1.Multiply(Z1);
-        end;
-
-        Z2IsOne := Z2.IsOne;
-        U2 := Y1;
-        V2 := x1;
-        if (not Z2IsOne) then
-        begin
-          U2 := U2.Multiply(Z2);
-          V2 := V2.Multiply(Z2);
-        end;
-
-        u := U1.Add(U2);
-        v := V1.Add(V2);
-
-        if (v.IsZero) then
-        begin
-          if (u.IsZero) then
-          begin
-            result := Twice();
-            Exit;
-          end;
-
-          result := ecCurve.Infinity;
-          Exit;
-        end;
-
-        Vsq := v.Square();
-        Vcu := Vsq.Multiply(v);
-
-        if Z1IsOne then
-        begin
-          w := Z2;
-        end
-        else if Z2IsOne then
-        begin
-          w := Z1;
-        end
-        else
-        begin
-          w := Z1.Multiply(Z2);
-        end;
-
-        uv := u.Add(v);
-        a := uv.MultiplyPlusProduct(u, Vsq, ecCurve.a).Multiply(w).Add(Vcu);
-
-        x3 := v.Multiply(a);
-        if Z2IsOne then
-        begin
-          VSqZ2 := Vsq;
-        end
-        else
-        begin
-          VSqZ2 := Vsq.Multiply(Z2);
-        end;
-
-        Y3 := u.MultiplyPlusProduct(x1, v, Y1).MultiplyPlusProduct
-          (VSqZ2, uv, a);
-        Z3 := Vcu.Multiply(w);
-
-        result := TF2mPoint.Create(ecCurve, x3, Y3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        if (x1.IsZero) then
-        begin
-          if (x2.IsZero) then
-          begin
-            result := ecCurve.Infinity;
-            Exit;
-          end;
-
-          result := b.Add(Self);
-          Exit;
-        end;
-
-        L1 := RawYCoord;
-        Z1 := RawZCoords[0];
-        L2 := b.RawYCoord;
-        Z2 := b.RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-        U2 := x2;
-        S2 := L2;
-        if (not Z1IsOne) then
-        begin
-          U2 := U2.Multiply(Z1);
-          S2 := S2.Multiply(Z1);
-        end;
-
-        Z2IsOne := Z2.IsOne;
-        U1 := x1;
-        S1 := L1;
-        if (not Z2IsOne) then
-        begin
-          U1 := U1.Multiply(Z2);
-          S1 := S1.Multiply(Z2);
-        end;
-
-        a := S1.Add(S2);
-        bigB := U1.Add(U2);
-
-        if (bigB.IsZero) then
-        begin
-          if (a.IsZero) then
-          begin
-            result := Twice();
-            Exit;
-          end;
-
-          result := ecCurve.Infinity;
-          Exit;
-        end;
-
-        if (x2.IsZero) then
-        begin
-          // TODO This can probably be optimized quite a bit
-          P := Normalize();
-          x1 := P.RawXCoord;
-          Y1 := P.YCoord;
-
-          Y2 := L2;
-          L := Y1.Add(Y2).Divide(x1);
-
-          x3 := L.Square().Add(L).Add(x1).Add(ecCurve.a);
-          if (x3.IsZero) then
-          begin
-            result := TF2mPoint.Create(ecCurve, x3, ecCurve.b.Sqrt(),
-              IsCompressed);
-            Exit;
-          end;
-
-          Y3 := L.Multiply(x1.Add(x3)).Add(x3).Add(Y1);
-          L3 := Y3.Divide(x3).Add(x3);
-          Z3 := ecCurve.FromBigInteger(TBigInteger.One);
-        end
-        else
-        begin
-          bigB := bigB.Square();
-
-          AU1 := a.Multiply(U1);
-          AU2 := a.Multiply(U2);
-
-          x3 := AU1.Multiply(AU2);
-          if (x3.IsZero) then
-          begin
-            result := TF2mPoint.Create(ecCurve, x3, ecCurve.b.Sqrt(),
-              IsCompressed);
-            Exit;
-          end;
-
-          ABZ2 := a.Multiply(bigB);
-          if (not Z2IsOne) then
-          begin
-            ABZ2 := ABZ2.Multiply(Z2);
-          end;
-
-          L3 := AU2.Add(bigB).SquarePlusProduct(ABZ2, L1.Add(Z1));
-
-          Z3 := ABZ2;
-          if (not Z1IsOne) then
-          begin
-            Z3 := Z3.Multiply(Z1);
-          end;
-        end;
-
-        result := TF2mPoint.Create(ecCurve, x3, L3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-
-end;
-
-constructor TF2mPoint.Create(const curve: IECCurve; const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-destructor TF2mPoint.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TF2mPoint.Detach: IECPoint;
-begin
-  result := TF2mPoint.Create(Nil, AffineXCoord, AffineYCoord, false);
-end;
-
-function TF2mPoint.GetCompressionYTilde: Boolean;
-var
-  Lx, LY: IECFieldElement;
-begin
-  Lx := RawXCoord;
-  if (Lx.IsZero) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  LY := RawYCoord;
-
-  case CurveCoordinateSystem of
-    TECCurveConstants.COORD_LAMBDA_AFFINE,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        // Y is actually Lambda (X + Y/X) here
-        result := LY.TestBitZero() <> Lx.TestBitZero();
-        Exit;
-      end
-  else
-    begin
-      result := LY.Divide(Lx).TestBitZero();
-    end;
-  end;
-
-end;
-
-function TF2mPoint.GetYCoord: IECFieldElement;
-var
-  coord: Int32;
-  Lx, L, LY, z: IECFieldElement;
-begin
-  coord := CurveCoordinateSystem;
-
-  case coord of
-    TECCurveConstants.COORD_LAMBDA_AFFINE,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        Lx := RawXCoord;
-        L := RawYCoord;
-
-        if (IsInfinity or Lx.IsZero) then
-        begin
-          result := L;
-          Exit;
-        end;
-
-        // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
-        LY := L.Add(Lx).Multiply(Lx);
-        if (TECCurveConstants.COORD_LAMBDA_PROJECTIVE = coord) then
-        begin
-          z := RawZCoords[0];
-          if (not z.IsOne) then
-          begin
-            LY := LY.Divide(z);
-          end;
-        end;
-        result := LY;
-        Exit;
-      end
-  else
-    begin
-      result := RawYCoord;
-    end;
-  end;
-
-end;
-
-function TF2mPoint.Negate: IECPoint;
-var
-  Lx, LY, bigY, z, L: IECFieldElement;
-  ecCurve: IECCurve;
-  coord: Int32;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  Lx := RawXCoord;
-  if (Lx.IsZero) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        bigY := RawYCoord;
-        result := TF2mPoint.Create(ecCurve, Lx, bigY.Add(Lx), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        LY := RawYCoord;
-        z := RawZCoords[0];
-        result := TF2mPoint.Create(ecCurve, Lx, LY.Add(Lx),
-          TCryptoLibGenericArray<IECFieldElement>.Create(z), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        L := RawYCoord;
-        result := TF2mPoint.Create(ecCurve, Lx, L.AddOne(), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        // L is actually Lambda (X + Y/X) here
-        L := RawYCoord;
-        z := RawZCoords[0];
-        result := TF2mPoint.Create(ecCurve, Lx, L.Add(z),
-          TCryptoLibGenericArray<IECFieldElement>.Create(z), IsCompressed);
-        Exit;
-      end
-
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-
-end;
-
-function TF2mPoint.Twice: IECPoint;
-var
-  ecCurve: IECCurve;
-  x1, Y1, L1, x3, Y3, Z1, X1Z1, X1Sq, Y1Z1, s, v, vSquared, sv, h, Z3, L1Z1,
-    Z1Sq, a, aZ1Sq, L3, t, b, t1, t2: IECFieldElement;
-  coord: Int32;
-  Z1IsOne: Boolean;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-
-  x1 := RawXCoord;
-  if (x1.IsZero) then
-  begin
-    // A point with X == 0 is it's own additive inverse
-    result := ecCurve.Infinity;
-    Exit;
-  end;
-
-  coord := ecCurve.CoordinateSystem;
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        Y1 := RawYCoord;
-
-        L1 := Y1.Divide(x1).Add(x1);
-
-        x3 := L1.Square().Add(L1).Add(ecCurve.a);
-        Y3 := x1.SquarePlusProduct(x3, L1.AddOne());
-
-        result := TF2mPoint.Create(ecCurve, x3, Y3, IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        Y1 := RawYCoord;
-        Z1 := RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-
-        if Z1IsOne then
-        begin
-          X1Z1 := x1;
-        end
-        else
-        begin
-          X1Z1 := x1.Multiply(Z1);
-        end;
-
-        if Z1IsOne then
-        begin
-          Y1Z1 := Y1;
-        end
-        else
-        begin
-          Y1Z1 := Y1.Multiply(Z1);
-        end;
-
-        X1Sq := x1.Square();
-        s := X1Sq.Add(Y1Z1);
-        v := X1Z1;
-        vSquared := v.Square();
-        sv := s.Add(v);
-        h := sv.MultiplyPlusProduct(s, vSquared, ecCurve.a);
-
-        x3 := v.Multiply(h);
-        Y3 := X1Sq.Square().MultiplyPlusProduct(v, h, sv);
-        Z3 := v.Multiply(vSquared);
-
-        result := TF2mPoint.Create(ecCurve, x3, Y3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        L1 := RawYCoord;
-        Z1 := RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-        if Z1IsOne then
-        begin
-          L1Z1 := L1;
-        end
-        else
-        begin
-          L1Z1 := L1.Multiply(Z1);
-        end;
-
-        if Z1IsOne then
-        begin
-          Z1Sq := Z1;
-        end
-        else
-        begin
-          Z1Sq := Z1.Square();
-        end;
-
-        a := ecCurve.a;
-
-        if Z1IsOne then
-        begin
-          aZ1Sq := a;
-        end
-        else
-        begin
-          aZ1Sq := a.Multiply(Z1Sq);
-        end;
-
-        t := L1.Square().Add(L1Z1).Add(aZ1Sq);
-        if (t.IsZero) then
-        begin
-          result := TF2mPoint.Create(ecCurve, t, ecCurve.b.Sqrt(),
-            IsCompressed);
-          Exit;
-        end;
-
-        x3 := t.Square();
-
-        if Z1IsOne then
-        begin
-          Z3 := t;
-        end
-        else
-        begin
-          Z3 := t.Multiply(Z1Sq);
-        end;
-
-        b := ecCurve.b;
-
-        if (b.BitLength < (TBitOperations.Asr32(ecCurve.FieldSize, 1))) then
-        begin
-          t1 := L1.Add(x1).Square();
-
-          if (b.IsOne) then
-          begin
-            t2 := aZ1Sq.Add(Z1Sq).Square();
-          end
-          else
-          begin
-            // TODO Can be calculated with one square if we pre-compute sqrt(b)
-            t2 := aZ1Sq.SquarePlusProduct(b, Z1Sq.Square());
-          end;
-          L3 := t1.Add(t).Add(Z1Sq).Multiply(t1).Add(t2).Add(x3);
-          if (a.IsZero) then
-          begin
-            L3 := L3.Add(Z3);
-          end
-          else if (not a.IsOne) then
-          begin
-            L3 := L3.Add(a.AddOne().Multiply(Z3));
-          end
-        end
-        else
-        begin
-
-          if Z1IsOne then
-          begin
-            X1Z1 := x1;
-          end
-          else
-          begin
-            X1Z1 := x1.Multiply(Z1);
-          end;
-          L3 := X1Z1.SquarePlusProduct(t, L1Z1).Add(x3).Add(Z3);
-        end;
-
-        result := TF2mPoint.Create(ecCurve, x3, L3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-  end;
-end;
-
-function TF2mPoint.TwicePlus(const b: IECPoint): IECPoint;
-var
-  ecCurve: IECCurve;
-  x1, x2, Z2, L1, L2, Z1, X1Sq, L1Sq, Z1Sq, L1Z1, t, L2plus1, a, X2Z1Sq, bigB,
-    x3, L3, Z3: IECFieldElement;
-  coord: Int32;
-begin
-  if (IsInfinity) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  ecCurve := curve;
-
-  x1 := RawXCoord;
-  if (x1.IsZero) then
-  begin
-    // A point with X == 0 is it's own additive inverse
-    result := b;
-    Exit;
-  end;
-
-  coord := ecCurve.CoordinateSystem;
-
-  case coord of
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-
-        // NOTE: twicePlus() only optimized for lambda-affine argument
-        x2 := b.RawXCoord;
-        Z2 := b.RawZCoords[0];
-        if ((x2.IsZero) or (not Z2.IsOne)) then
-        begin
-          result := Twice().Add(b);
-          Exit;
-        end;
-
-        L1 := RawYCoord;
-        Z1 := RawZCoords[0];
-        L2 := b.RawYCoord;
-
-        X1Sq := x1.Square();
-        L1Sq := L1.Square();
-        Z1Sq := Z1.Square();
-        L1Z1 := L1.Multiply(Z1);
-
-        t := ecCurve.a.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
-        L2plus1 := L2.AddOne();
-        a := ecCurve.a.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq)
-          .MultiplyPlusProduct(t, X1Sq, Z1Sq);
-        X2Z1Sq := x2.Multiply(Z1Sq);
-        bigB := X2Z1Sq.Add(t).Square();
-
-        if (bigB.IsZero) then
-        begin
-          if (a.IsZero) then
-          begin
-            result := b.Twice();
-            Exit;
-          end;
-
-          result := ecCurve.Infinity;
-          Exit;
-        end;
-
-        if (a.IsZero) then
-        begin
-          result := TF2mPoint.Create(ecCurve, a, ecCurve.b.Sqrt(),
-            IsCompressed);
-          Exit;
-        end;
-
-        x3 := a.Square().Multiply(X2Z1Sq);
-        Z3 := a.Multiply(bigB).Multiply(Z1Sq);
-        L3 := a.Add(bigB).Square().MultiplyPlusProduct(t, L2plus1, Z3);
-
-        result := TF2mPoint.Create(ecCurve, x3, L3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      result := Twice().Add(b);
-      Exit;
-    end;
-  end;
-
-end;
-
-{ TECPointBase }
-
-constructor TECPointBase.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, withCompression);
-end;
-
-constructor TECPointBase.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-destructor TECPointBase.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TECPointBase.GetEncoded(compressed: Boolean): TCryptoLibByteArray;
-var
-  normed: IECPoint;
-  Lx, LY, PO: TCryptoLibByteArray;
-begin
-  if (IsInfinity) then
-  begin
-    System.SetLength(result, 1);
-    Exit;
-  end;
-
-  normed := Normalize();
-
-  Lx := normed.XCoord.GetEncoded();
-
-  if (compressed) then
-  begin
-    System.SetLength(PO, System.Length(Lx) + 1);
-    if normed.CompressionYTilde then
-    begin
-      PO[0] := Byte($03);
-    end
-    else
-    begin
-      PO[0] := Byte($02);
-    end;
-
-    System.Move(Lx[0], PO[1], System.Length(Lx) * System.SizeOf(Byte));
-
-    result := PO;
-    Exit;
-  end;
-
-  LY := normed.YCoord.GetEncoded();
-
-  System.SetLength(PO, System.Length(Lx) + System.Length(LY) + 1);
-
-  PO[0] := $04;
-
-  System.Move(Lx[0], PO[1], System.Length(Lx) * System.SizeOf(Byte));
-  System.Move(LY[0], PO[System.Length(Lx) + 1],
-    System.Length(LY) * System.SizeOf(Byte));
-
-  result := PO;
-
-end;
-
-function TECPointBase.Multiply(K: TBigInteger): IECPoint;
-begin
-  result := curve.GetMultiplier().Multiply(Self as IECPoint, K);
-end;
-
-{ TAbstractFpPoint }
-
-function TAbstractFpPoint.GetCompressionYTilde: Boolean;
-begin
-  result := AffineYCoord.TestBitZero();
-end;
-
-constructor TAbstractFpPoint.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, withCompression);
-end;
-
-constructor TAbstractFpPoint.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-destructor TAbstractFpPoint.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TAbstractFpPoint.SatisfiesCurveEquation: Boolean;
-var
-  Lx, LY, a, b, lhs, rhs, z, Z2, Z3, Z4, Z6: IECFieldElement;
-begin
-  Lx := RawXCoord;
-  LY := RawYCoord;
-  a := curve.a;
-  b := curve.b;
-  lhs := LY.Square();
-
-  case CurveCoordinateSystem of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        // do nothing
-      end;
-
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        z := RawZCoords[0];
-        if (not z.IsOne) then
-        begin
-          Z2 := z.Square();
-          Z3 := z.Multiply(Z2);
-          lhs := lhs.Multiply(z);
-          a := a.Multiply(Z2);
-          b := b.Multiply(Z3);
-        end;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN,
-      TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
-      TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        z := RawZCoords[0];
-        if (not z.IsOne) then
-        begin
-          Z2 := z.Square();
-          Z4 := Z2.Square();
-          Z6 := Z2.Multiply(Z4);
-          a := a.Multiply(Z4);
-          b := b.Multiply(Z6);
-        end;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-
-  rhs := Lx.Square().Add(a).Multiply(Lx).Add(b);
-  result := lhs.Equals(rhs);
-end;
-
-function TAbstractFpPoint.Subtract(const b: IECPoint): IECPoint;
-begin
-  if (b.IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  // Add -b
-  result := Add(b.Negate());
-end;
-
-{ TFpPoint }
-
-function TFpPoint.Add(const b: IECPoint): IECPoint;
-var
-  ecCurve: IECCurve;
-  coord: Int32;
-  gamma, x1, x2, Y1, Y2, dx, dy, x3, Y3, Z1, Z2, U1, V1, U2, V2, u, v, w, a, Z3,
-    S2, S1, vSquared, vCubed, vSquaredV2, Z1Squared, bigU2, Z3Squared, c, W1,
-    w2, A1, Z1Cubed, Z2Squared, bigU1, h, r, HSquared, G, W3,
-    Z2Cubed: IECFieldElement;
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-  Z1IsOne, Z2IsOne: Boolean;
-begin
-  if (IsInfinity) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  if (Self as IECPoint = b) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  x1 := RawXCoord;
-  Y1 := RawYCoord;
-  x2 := b.RawXCoord;
-  Y2 := b.RawYCoord;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-
-        dx := x2.Subtract(x1);
-        dy := Y2.Subtract(Y1);
-
-        if (dx.IsZero) then
-        begin
-          if (dy.IsZero) then
-          begin
-            // this == b, i.e. this must be doubled
-            result := Twice();
-            Exit;
-          end;
-
-          // this == -b, i.e. the result is the point at infinity
-          result := curve.Infinity;
-          Exit;
-        end;
-
-        gamma := dy.Divide(dx);
-        x3 := gamma.Square().Subtract(x1).Subtract(x2);
-        Y3 := gamma.Multiply(x1.Subtract(x3)).Subtract(Y1);
-
-        result := TFpPoint.Create(curve, x3, Y3, IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        Z1 := RawZCoords[0];
-        Z2 := b.RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-        Z2IsOne := Z2.IsOne;
-
-        if Z1IsOne then
-        begin
-          U1 := Y2;
-        end
-        else
-        begin
-          U1 := Y2.Multiply(Z1);
-        end;
-
-        if Z2IsOne then
-        begin
-          U2 := Y1;
-        end
-        else
-        begin
-          U2 := Y1.Multiply(Z2);
-        end;
-
-        u := U1.Subtract(U2);
-
-        if Z1IsOne then
-        begin
-          V1 := x2;
-        end
-        else
-        begin
-          V1 := x2.Multiply(Z1);
-        end;
-
-        if Z2IsOne then
-        begin
-          V2 := x1;
-        end
-        else
-        begin
-          V2 := x1.Multiply(Z2);
-        end;
-
-        v := V1.Subtract(V2);
-
-        // Check if b = this or b = -this
-        if (v.IsZero) then
-        begin
-          if (u.IsZero) then
-          begin
-            // this = b, i.e. this must be doubled
-            result := Twice();
-            Exit;
-          end;
-
-          // this = -b, i.e. the result is the point at infinity
-          result := ecCurve.Infinity;
-          Exit;
-        end;
-
-        // TODO Optimize for when w = 1
-        if Z1IsOne then
-        begin
-          w := Z2;
-        end
-        else if Z2IsOne then
-
-        begin
-          w := Z1;
-        end
-        else
-        begin
-          w := Z1.Multiply(Z2);
-        end;
-
-        vSquared := v.Square();
-        vCubed := vSquared.Multiply(v);
-        vSquaredV2 := vSquared.Multiply(V2);
-        a := u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));
-
-        x3 := v.Multiply(a);
-        Y3 := vSquaredV2.Subtract(a).MultiplyMinusProduct(u, U2, vCubed);
-        Z3 := vCubed.Multiply(w);
-
-        result := TFpPoint.Create(ecCurve, x3, Y3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        Z1 := RawZCoords[0];
-        Z2 := b.RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-
-        x3 := Nil;
-        Y3 := Nil;
-        Z3 := Nil;
-        Z3Squared := Nil;
-
-        if ((not Z1IsOne) and (Z1.Equals(Z2))) then
-        begin
-          // TODO Make this available as public method coZAdd?
-
-          dx := x1.Subtract(x2);
-          dy := Y1.Subtract(Y2);
-          if (dx.IsZero) then
-          begin
-            if (dy.IsZero) then
-            begin
-              result := Twice();
-              Exit;
-            end;
-            result := ecCurve.Infinity;
-            Exit;
-          end;
-
-          c := dx.Square();
-          W1 := x1.Multiply(c);
-          w2 := x2.Multiply(c);
-          A1 := W1.Subtract(w2).Multiply(Y1);
-
-          x3 := dy.Square().Subtract(W1).Subtract(w2);
-          Y3 := W1.Subtract(x3).Multiply(dy).Subtract(A1);
-          Z3 := dx;
-
-          if (Z1IsOne) then
-          begin
-            Z3Squared := c;
-          end
-          else
-          begin
-            Z3 := Z3.Multiply(Z1);
-          end
-        end
-        else
-        begin
-
-          if (Z1IsOne) then
-          begin
-            Z1Squared := Z1;
-            bigU2 := x2;
-            S2 := Y2;
-          end
-          else
-          begin
-            Z1Squared := Z1.Square();
-            bigU2 := Z1Squared.Multiply(x2);
-            Z1Cubed := Z1Squared.Multiply(Z1);
-            S2 := Z1Cubed.Multiply(Y2);
-          end;
-
-          Z2IsOne := Z2.IsOne;
-
-          if (Z2IsOne) then
-          begin
-            Z2Squared := Z2;
-            bigU1 := x1;
-            S1 := Y1;
-          end
-          else
-          begin
-            Z2Squared := Z2.Square();
-            bigU1 := Z2Squared.Multiply(x1);
-            Z2Cubed := Z2Squared.Multiply(Z2);
-            S1 := Z2Cubed.Multiply(Y1);
-          end;
-
-          h := bigU1.Subtract(bigU2);
-          r := S1.Subtract(S2);
-
-          // Check if b == this or b == -this
-          if (h.IsZero) then
-          begin
-            if (r.IsZero) then
-            begin
-              // this == b, i.e. this must be doubled
-              result := Twice();
-              Exit;
-            end;
-
-            // this == -b, i.e. the result is the point at infinity
-            result := ecCurve.Infinity;
-            Exit;
-          end;
-
-          HSquared := h.Square();
-          G := HSquared.Multiply(h);
-          v := HSquared.Multiply(bigU1);
-
-          x3 := r.Square().Add(G).Subtract(Two(v));
-          Y3 := v.Subtract(x3).MultiplyMinusProduct(r, G, S1);
-
-          Z3 := h;
-          if (not Z1IsOne) then
-          begin
-            Z3 := Z3.Multiply(Z1);
-          end;
-          if (not Z2IsOne) then
-          begin
-            Z3 := Z3.Multiply(Z2);
-          end;
-
-          // Alternative calculation of Z3 using fast square
-          // X3 := four(X3);
-          // Y3 := eight(Y3);
-          // Z3 := doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H);
-
-          if (Z3 = h) then
-          begin
-            Z3Squared := HSquared;
-          end;
-        end;
-
-        if (coord = TECCurveConstants.COORD_JACOBIAN_MODIFIED) then
-        begin
-          // TODO If the result will only be used in a subsequent addition, we don't need W3
-          W3 := CalculateJacobianModifiedW(Z3, Z3Squared);
-
-          zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3, W3);
-        end
-        else
-        begin
-          zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
-        end;
-
-        result := TFpPoint.Create(ecCurve, x3, Y3, zs, IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-
-end;
-
-function TFpPoint.CalculateJacobianModifiedW(const z: IECFieldElement;
-  const ZSquared: IECFieldElement): IECFieldElement;
-var
-  a4, w, a4Neg, LZSquared: IECFieldElement;
-begin
-  a4 := curve.a;
-  LZSquared := ZSquared;
-  if ((a4.IsZero) or (z.IsOne)) then
-  begin
-    result := a4;
-    Exit;
-  end;
-
-  if (LZSquared = Nil) then
-  begin
-    LZSquared := z.Square();
-  end;
-
-  w := LZSquared.Square();
-  a4Neg := a4.Negate();
-  if (a4Neg.BitLength < a4.BitLength) then
-  begin
-    w := w.Multiply(a4Neg).Negate();
-  end
-  else
-  begin
-    w := w.Multiply(a4);
-  end;
-  result := w;
-end;
-
-constructor TFpPoint.Create(const curve: IECCurve; const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-constructor TFpPoint.Create(const curve: IECCurve; const x, y: IECFieldElement;
-  withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SNilFieldElement);
-  end;
-end;
-
-constructor TFpPoint.Create(const curve: IECCurve; const x, y: IECFieldElement);
-begin
-  Create(curve, x, y, false);
-end;
-
-destructor TFpPoint.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TFpPoint.Detach: IECPoint;
-begin
-  result := TFpPoint.Create(Nil, AffineXCoord, AffineYCoord, false);
-end;
-
-function TFpPoint.DoubleProductFromSquares(const a, b, aSquared,
-  bSquared: IECFieldElement): IECFieldElement;
-begin
-  // /*
-  // * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
-  // * way to calculate 2.A.B, if A^2 and B^2 are already known.
-  // */
-  result := a.Add(b).Square().Subtract(aSquared).Subtract(bSquared);
-end;
-
-function TFpPoint.Eight(const x: IECFieldElement): IECFieldElement;
-begin
-  result := Four(Two(x));
-end;
-
-function TFpPoint.Four(const x: IECFieldElement): IECFieldElement;
-begin
-  result := Two(Two(x));
-end;
-
-function TFpPoint.GetJacobianModifiedW: IECFieldElement;
-var
-  ZZ: TCryptoLibGenericArray<IECFieldElement>;
-  w: IECFieldElement;
-begin
-  ZZ := RawZCoords;
-  w := ZZ[1];
-  if (w = Nil) then
-  begin
-    // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
-    w := CalculateJacobianModifiedW(ZZ[0], Nil);
-    ZZ[1] := w;
-  end;
-  result := w;
-end;
-
-function TFpPoint.GetZCoord(index: Int32): IECFieldElement;
-begin
-  if ((index = 1) and (TECCurveConstants.COORD_JACOBIAN_MODIFIED =
-    CurveCoordinateSystem)) then
-  begin
-    result := GetJacobianModifiedW();
-    Exit;
-  end;
-
-  result := (Inherited GetZCoord(index));
-end;
-
-function TFpPoint.Negate: IECPoint;
-var
-  Lcurve: IECCurve;
-  coord: Int32;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  Lcurve := curve;
-  coord := Lcurve.CoordinateSystem;
-
-  if (TECCurveConstants.COORD_AFFINE <> coord) then
-  begin
-    result := TFpPoint.Create(Lcurve, RawXCoord, RawYCoord.Negate(), RawZCoords,
-      IsCompressed);
-    Exit;
-  end;
-
-  result := TFpPoint.Create(Lcurve, RawXCoord, RawYCoord.Negate(),
-    IsCompressed);
-end;
-
-function TFpPoint.Three(const x: IECFieldElement): IECFieldElement;
-begin
-  result := Two(x).Add(x);
-end;
-
-function TFpPoint.ThreeTimes: IECPoint;
-var
-  Y1, x1, _2Y1, Lx, z, LY, d, bigD, i, L1, L2, X4, Y4: IECFieldElement;
-  ecCurve: IECCurve;
-  coord: Int32;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-
-        x1 := RawXCoord;
-
-        _2Y1 := Two(Y1);
-        Lx := _2Y1.Square();
-        z := Three(x1.Square()).Add(curve.a);
-        LY := z.Square();
-
-        d := Three(x1).Multiply(Lx).Subtract(LY);
-        if (d.IsZero) then
-        begin
-          result := curve.Infinity;
-          Exit;
-        end;
-
-        bigD := d.Multiply(_2Y1);
-        i := bigD.Invert();
-        L1 := d.Multiply(i).Multiply(z);
-        L2 := Lx.Square().Multiply(i).Subtract(L1);
-
-        X4 := (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(x1);
-        Y4 := (x1.Subtract(X4)).Multiply(L2).Subtract(Y1);
-        result := TFpPoint.Create(curve, X4, Y4, IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        result := TwiceJacobianModified(false).Add(Self);
-        Exit;
-      end
-  else
-    begin
-      // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
-      result := Twice().Add(Self);
-    end;
-
-  end;
-
-end;
-
-function TFpPoint.TimesPow2(e: Int32): IECPoint;
-var
-  ecCurve: IECCurve;
-  Y1, W1, x1, Z1, Z1Sq, X1Squared, m, _2Y1, _2Y1Squared, s, _4T, _8T, zInv,
-    zInv2, zInv3: IECFieldElement;
-  coord, i: Int32;
-begin
-  if (e < 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SCannotBeNegative);
-  end;
-  if ((e = 0) or (IsInfinity)) then
-  begin
-    result := Self;
-    Exit;
-  end;
-  if (e = 1) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  ecCurve := curve;
-
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
-  begin
-    result := ecCurve.Infinity;
-    Exit;
-  end;
-
-  coord := ecCurve.CoordinateSystem;
-
-  W1 := ecCurve.a;
-  x1 := RawXCoord;
-  if RawZCoords = Nil then
-  begin
-    Z1 := ecCurve.FromBigInteger(TBigInteger.One);
-  end
-  else
-  begin
-    Z1 := RawZCoords[0];
-  end;
-
-  if (not Z1.IsOne) then
-  begin
-    case coord of
-      TECCurveConstants.COORD_HOMOGENEOUS:
-        begin
-          Z1Sq := Z1.Square();
-          x1 := x1.Multiply(Z1);
-          Y1 := Y1.Multiply(Z1Sq);
-          W1 := CalculateJacobianModifiedW(Z1, Z1Sq);
-        end;
-      TECCurveConstants.COORD_JACOBIAN:
-        begin
-          W1 := CalculateJacobianModifiedW(Z1, Nil);
-        end;
-
-      TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-        begin
-          W1 := GetJacobianModifiedW();
-        end;
-    end;
-
-  end;
-
-  i := 0;
-  while i < e do
-  begin
-    if (Y1.IsZero) then
-    begin
-      result := ecCurve.Infinity;
-      Exit;
-    end;
-
-    X1Squared := x1.Square();
-    m := Three(X1Squared);
-    _2Y1 := Two(Y1);
-    _2Y1Squared := _2Y1.Multiply(Y1);
-    s := Two(x1.Multiply(_2Y1Squared));
-    _4T := _2Y1Squared.Square();
-    _8T := Two(_4T);
-
-    if (not W1.IsZero) then
-    begin
-      m := m.Add(W1);
-      W1 := Two(_8T.Multiply(W1));
-    end;
-
-    x1 := m.Square().Subtract(Two(s));
-    Y1 := m.Multiply(s.Subtract(x1)).Subtract(_8T);
-    if Z1.IsOne then
-    begin
-      Z1 := _2Y1;
-    end
-    else
-    begin
-      Z1 := _2Y1.Multiply(Z1);
-    end;
-
-    System.Inc(i);
-  end;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        zInv := Z1.Invert();
-        zInv2 := zInv.Square();
-        zInv3 := zInv2.Multiply(zInv);
-
-        result := TFpPoint.Create(ecCurve, x1.Multiply(zInv2),
-          Y1.Multiply(zInv3), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        x1 := x1.Multiply(Z1);
-        Z1 := Z1.Multiply(Z1.Square());
-        result := TFpPoint.Create(ecCurve, x1, Y1,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z1), IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_JACOBIAN:
-      begin
-        result := TFpPoint.Create(ecCurve, x1, Y1,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z1), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        result := TFpPoint.Create(ecCurve, x1, Y1,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z1, W1), IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-
-end;
-
-function TFpPoint.Twice: IECPoint;
-var
-  ecCurve: IECCurve;
-  Y1, x1, X1Squared, gamma, x3, Y3, Z1, w, s, t, b, _4B, h, _2s, _2t,
-    _4sSquared, Z3, m, Y1Squared, a4, a4Neg, Z1Squared, Z1Pow4: IECFieldElement;
-  coord: Int32;
-  Z1IsOne: Boolean;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-
-  Y1 := RawYCoord;
-
-  if (Y1.IsZero) then
-  begin
-    result := ecCurve.Infinity;
-    Exit;
-  end;
-
-  coord := ecCurve.CoordinateSystem;
-
-  x1 := RawXCoord;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        X1Squared := x1.Square();
-        gamma := Three(X1Squared).Add(curve.a).Divide(Two(Y1));
-        x3 := gamma.Square().Subtract(Two(x1));
-        Y3 := gamma.Multiply(x1.Subtract(x3)).Subtract(Y1);
-
-        result := TFpPoint.Create(curve, x3, Y3, IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_HOMOGENEOUS:
-      begin
-        Z1 := RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-
-        // TODO Optimize for small negative a4 and -3
-        w := ecCurve.a;
-        if ((not w.IsZero) and (not Z1IsOne)) then
-        begin
-          w := w.Multiply(Z1.Square());
-        end;
-        w := w.Add(Three(x1.Square()));
-
-        if Z1IsOne then
-        begin
-          s := Y1;
-        end
-        else
-        begin
-          s := Y1.Multiply(Z1);
-        end;
-
-        if Z1IsOne then
-        begin
-          t := Y1.Square();
-        end
-        else
-        begin
-          t := s.Multiply(Y1);
-        end;
-
-        b := x1.Multiply(t);
-        _4B := Four(b);
-        h := w.Square().Subtract(Two(_4B));
-
-        _2s := Two(s);
-        x3 := h.Multiply(_2s);
-        _2t := Two(t);
-        Y3 := _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square()));
-
-        if Z1IsOne then
-        begin
-          _4sSquared := Two(_2t);
-        end
-        else
-        begin
-          _4sSquared := _2s.Square();
-        end;
-
-        Z3 := Two(_4sSquared).Multiply(s);
-
-        result := TFpPoint.Create(ecCurve, x3, Y3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN:
-      begin
-        Z1 := RawZCoords[0];
-
-        Z1IsOne := Z1.IsOne;
-
-        Y1Squared := Y1.Square();
-        t := Y1Squared.Square();
-
-        a4 := ecCurve.a;
-        a4Neg := a4.Negate();
-
-        if (a4Neg.ToBigInteger().Equals(TBigInteger.ValueOf(3))) then
-        begin
-
-          if Z1IsOne then
-          begin
-            Z1Squared := Z1;
-          end
-          else
-          begin
-            Z1Squared := Z1.Square();
-          end;
-
-          m := Three(x1.Add(Z1Squared).Multiply(x1.Subtract(Z1Squared)));
-          s := Four(Y1Squared.Multiply(x1));
-        end
-        else
-        begin
-          X1Squared := x1.Square();
-          m := Three(X1Squared);
-          if (Z1IsOne) then
-          begin
-            m := m.Add(a4);
-          end
-          else if (not a4.IsZero) then
-          begin
-
-            if Z1IsOne then
-            begin
-              Z1Squared := Z1;
-            end
-            else
-            begin
-              Z1Squared := Z1.Square();
-            end;
-
-            Z1Pow4 := Z1Squared.Square();
-            if (a4Neg.BitLength < a4.BitLength) then
-            begin
-              m := m.Subtract(Z1Pow4.Multiply(a4Neg));
-            end
-            else
-            begin
-              m := m.Add(Z1Pow4.Multiply(a4));
-            end
-          end;
-          // S := two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
-          s := Four(x1.Multiply(Y1Squared));
-        end;
-
-        x3 := m.Square().Subtract(Two(s));
-        Y3 := s.Subtract(x3).Multiply(m).Subtract(Eight(t));
-
-        Z3 := Two(Y1);
-        if (not Z1IsOne) then
-        begin
-          Z3 := Z3.Multiply(Z1);
-        end;
-
-        // Alternative calculation of Z3 using fast square
-        // Z3 := doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
-        result := TFpPoint.Create(ecCurve, x3, Y3,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        result := TwiceJacobianModified(true);
-        Exit;
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-end;
-
-function TFpPoint.TwiceJacobianModified(calculateW: Boolean): IFpPoint;
-var
-  x1, Y1, Z1, W1, X1Squared, m, _2Y1, _2Y1Squared, s, x3, _4T, _8T, Y3, W3,
-    Z3: IECFieldElement;
-begin
-  x1 := RawXCoord;
-  Y1 := RawYCoord;
-  Z1 := RawZCoords[0];
-  W1 := GetJacobianModifiedW();
-
-  X1Squared := x1.Square();
-  m := Three(X1Squared).Add(W1);
-  _2Y1 := Two(Y1);
-  _2Y1Squared := _2Y1.Multiply(Y1);
-  s := Two(x1.Multiply(_2Y1Squared));
-  x3 := m.Square().Subtract(Two(s));
-  _4T := _2Y1Squared.Square();
-  _8T := Two(_4T);
-  Y3 := m.Multiply(s.Subtract(x3)).Subtract(_8T);
-
-  if calculateW then
-  begin
-    W3 := Two(_8T.Multiply(W1));
-  end
-  else
-  begin
-    W3 := Nil;
-  end;
-
-  if Z1.IsOne then
-  begin
-    Z3 := _2Y1;
-  end
-  else
-  begin
-    Z3 := _2Y1.Multiply(Z1);
-  end;
-
-  result := TFpPoint.Create(curve, x3, Y3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(Z3, W3), IsCompressed);
-end;
-
-function TFpPoint.TwicePlus(const b: IECPoint): IECPoint;
-var
-  Y1, x1, x2, Y2, dx, dy, Lx, LY, d, i, L1, L2, X4, Y4, bigD: IECFieldElement;
-  ecCurve: IECCurve;
-  coord: Int32;
-
-begin
-  if (Self as IECPoint = b) then
-  begin
-    result := ThreeTimes();
-    Exit;
-  end;
-  if (IsInfinity) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
-  begin
-    result := b;
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE:
-      begin
-        x1 := RawXCoord;
-        x2 := b.RawXCoord;
-        Y2 := b.RawYCoord;
-
-        dx := x2.Subtract(x1);
-        dy := Y2.Subtract(Y1);
-
-        if (dx.IsZero) then
-        begin
-          if (dy.IsZero) then
-          begin
-            // this == b i.e. the result is 3P
-            result := ThreeTimes();
-            Exit;
-          end;
-
-          // this == -b, i.e. the result is P
-          result := Self;
-          Exit;
-        end;
-
-        // / * * Optimized calculation of 2 p + Q, as described
-        // in " Trading Inversions for * Multiplications
-        // in Elliptic curve Cryptography ", by Ciet, Joye, Lauter,
-        // Montgomery. * /
-
-        Lx := dx.Square();
-        LY := dy.Square();
-        d := Lx.Multiply(Two(x1).Add(x2)).Subtract(LY);
-        if (d.IsZero) then
-        begin
-          result := curve.Infinity;
-          Exit;
-        end;
-
-        bigD := d.Multiply(dx);
-        i := bigD.Invert();
-        L1 := d.Multiply(i).Multiply(dy);
-        L2 := Two(Y1).Multiply(Lx).Multiply(dx).Multiply(i).Subtract(L1);
-        X4 := (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(x2);
-        Y4 := (x1.Subtract(X4)).Multiply(L2).Subtract(Y1);
-
-        result := TFpPoint.Create(curve, X4, Y4, IsCompressed);
-        Exit;
-      end;
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      begin
-        result := TwiceJacobianModified(false).Add(b);
-        Exit;
-      end
-  else
-    begin
-      result := Twice().Add(b);
-      Exit;
-    end;
-  end;
-
-end;
-
-function TFpPoint.Two(const x: IECFieldElement): IECFieldElement;
-begin
-  result := x.Add(x);
-end;
-
-{ TAbstractF2mPoint }
-
-constructor TAbstractF2mPoint.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, withCompression);
-end;
-
-constructor TAbstractF2mPoint.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-destructor TAbstractF2mPoint.Destroy;
-begin
-  inherited Destroy;
-end;
-
-function TAbstractF2mPoint.SatisfiesCurveEquation: Boolean;
-var
-  z, Z2, Z3, x, LY, a, b, lhs, rhs, L, x2, Z4: IECFieldElement;
-  ecCurve: IECCurve;
-  coord: Int32;
-  ZIsOne: Boolean;
-begin
-  ecCurve := curve;
-  x := RawXCoord;
-  LY := RawYCoord;
-  a := ecCurve.a;
-  b := ecCurve.b;
-
-  coord := ecCurve.CoordinateSystem;
-  if (coord = TECCurveConstants.COORD_LAMBDA_PROJECTIVE) then
-  begin
-    z := RawZCoords[0];
-    ZIsOne := z.IsOne;
-
-    if (x.IsZero) then
-    begin
-      // NOTE: For x == 0, we expect the affine-y instead of the lambda-y
-      lhs := LY.Square();
-      rhs := b;
-      if (not ZIsOne) then
-      begin
-        Z2 := z.Square();
-        rhs := rhs.Multiply(Z2);
-      end
-    end
-    else
-    begin
-      L := LY;
-      x2 := x.Square();
-      if (ZIsOne) then
-      begin
-        lhs := L.Square().Add(L).Add(a);
-        rhs := x2.Square().Add(b);
-      end
-      else
-      begin
-        Z2 := z.Square();
-        Z4 := Z2.Square();
-        lhs := L.Add(z).MultiplyPlusProduct(L, a, Z2);
-        // TODO If sqrt(b) is precomputed this can be simplified to a single square
-        rhs := x2.SquarePlusProduct(b, Z4);
-      end;
-      lhs := lhs.Multiply(x2);
-    end
-  end
-  else
-  begin
-    lhs := LY.Add(x).Multiply(LY);
-
-    case coord of
-      TECCurveConstants.COORD_AFFINE:
-        begin
-          // do nothing;
-        end;
-
-      TECCurveConstants.COORD_HOMOGENEOUS:
-        begin
-          z := RawZCoords[0];
-          if (not z.IsOne) then
-          begin
-            Z2 := z.Square();
-            Z3 := z.Multiply(Z2);
-            lhs := lhs.Multiply(z);
-            a := a.Multiply(z);
-            b := b.Multiply(Z3);
-          end;
-        end
-
-    else
-      begin
-        raise EInvalidOperationCryptoLibException.CreateRes
-          (@SUnSupportedCoordinateSystem);
-      end;
-
-    end;
-
-    rhs := x.Add(a).Multiply(x.Square()).Add(b);
-  end;
-
-  result := lhs.Equals(rhs);
-end;
-
-function TAbstractF2mPoint.SatisfiesOrder: Boolean;
-var
-  Cofactor: TBigInteger;
-  n: IECPoint;
-  x, rhs, L, t, y: IECFieldElement;
-  Lcurve: IECCurve;
-begin
-  Lcurve := curve;
-  Cofactor := Lcurve.GetCofactor();
-  if (TBigInteger.Two.Equals(Cofactor)) then
-  begin
-    (*
-      * Check that 0 == Tr(X + A); then there exists a solution to L^2 + L = X + A, and
-      * so a halving is possible, so this point is the double of another.
-      *
-      * Note: Tr(A) == 1 for cofactor 2 curves.
-    *)
-    n := Normalize();
-    x := n.AffineXCoord;
-    rhs := x.Add(Lcurve.a);
-    result := (x as IAbstractF2mFieldElement).Trace() <> 0;
-    Exit;
-  end;
-  if (TBigInteger.Four.Equals(Cofactor)) then
-  begin
-    // /*
-    // * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not).
-    // * Generate both possibilities for the square of the half-point's x-coordinate (w),
-    // * and check if Tr(w + A) == 0 for at least one; then a second halving is possible
-    // * (see comments for cofactor 2 above), so this point is four times another.
-    // *
-    // * Note: Tr(A) == 0 for cofactor 4 curves.
-    // */
-    n := Normalize();
-    x := n.AffineXCoord;
-    L := (Lcurve as IAbstractF2mCurve).SolveQuadraticEquation(x.Add(curve.a));
-    if (L = Nil) then
-    begin
-      result := false;
-      Exit;
-    end;
-
-    (*
-      * A solution exists, therefore 0 == Tr(X + A) == Tr(X).
-    *)
-    y := n.AffineYCoord;
-    t := x.Multiply(L).Add(y);
-
-    (*
-      * Either T or (T + X) is the square of a half-point's x coordinate (hx). In either
-      * case, the half-point can be halved again when 0 == Tr(hx + A).
-      *
-      * Note: Tr(hx + A) == Tr(hx) == Tr(hx^2) == Tr(T) == Tr(T + X)
-      *
-      * Check that 0 == Tr(T); then there exists a solution to L^2 + L = hx + A, and so a
-      * second halving is possible and this point is four times some other.
-    *)
-    result := (t as IAbstractF2mFieldElement).Trace() = 0;
-    Exit;
-  end;
-
-  result := Inherited SatisfiesOrder();
-end;
-
-function TAbstractF2mPoint.ScaleX(const scale: IECFieldElement): IECPoint;
-var
-  Lx, L, x2, L2, z, Z2: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  case CurveCoordinateSystem of
-    TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        // Y is actually Lambda (X + Y/X) here
-        Lx := RawXCoord;
-        L := RawYCoord;
-
-        x2 := Lx.Multiply(scale);
-        L2 := L.Add(Lx).Divide(scale).Add(x2);
-
-        result := curve.CreateRawPoint(Lx, L2, RawZCoords, IsCompressed);
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        // Y is actually Lambda (X + Y/X) here
-        Lx := RawXCoord;
-        L := RawYCoord;
-        z := RawZCoords[0];
-
-        // We scale the Z coordinate also, to avoid an inversion
-        x2 := Lx.Multiply(scale.Square());
-        L2 := L.Add(Lx).Add(x2);
-        Z2 := z.Multiply(scale);
-
-        result := curve.CreateRawPoint(Lx, L2,
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z2), IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      result := (Inherited ScaleX(scale));
-    end;
-
-  end;
-
-end;
-
-function TAbstractF2mPoint.ScaleXNegateY(const scale: IECFieldElement)
-  : IECPoint;
-begin
-  result := ScaleX(scale);
-end;
-
-function TAbstractF2mPoint.ScaleY(const scale: IECFieldElement): IECPoint;
-var
-  Lx, L, L2: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  case CurveCoordinateSystem of
-    TECCurveConstants.COORD_LAMBDA_AFFINE,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        Lx := RawXCoord;
-        L := RawYCoord;
-
-        // Y is actually Lambda (X + Y/X) here
-        L2 := L.Add(Lx).Multiply(scale).Add(Lx);
-
-        result := curve.CreateRawPoint(Lx, L2, RawZCoords, IsCompressed);
-        Exit;
-      end
-  else
-    begin
-      result := (Inherited ScaleY(scale));
-    end;
-  end;
-
-end;
-
-function TAbstractF2mPoint.ScaleYNegateX(const scale: IECFieldElement)
-  : IECPoint;
-begin
-  result := ScaleY(scale);
-end;
-
-function TAbstractF2mPoint.Subtract(const b: IECPoint): IECPoint;
-begin
-  if (b.IsInfinity) then
-  begin
-    result := Self;
-  end;
-
-  // Add -b
-  result := Add(b.Negate());
-end;
-
-function TAbstractF2mPoint.Tau: IAbstractF2mPoint;
-var
-  ecCurve: IECCurve;
-  coord: Int32;
-  x1, Y1, Z1: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  x1 := RawXCoord;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        Y1 := RawYCoord;
-        result := ecCurve.CreateRawPoint(x1.Square(), Y1.Square(), IsCompressed)
-          as IAbstractF2mPoint;
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_HOMOGENEOUS,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        Y1 := RawYCoord;
-        Z1 := RawZCoords[0];
-        result := ecCurve.CreateRawPoint(x1.Square(), Y1.Square(),
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z1.Square()),
-          IsCompressed) as IAbstractF2mPoint;
-        Exit;
-      end
-
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-end;
-
-function TAbstractF2mPoint.TauPow(pow: Int32): IAbstractF2mPoint;
-var
-  ecCurve: IECCurve;
-  coord: Int32;
-  x1, Y1, Z1: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  ecCurve := curve;
-  coord := ecCurve.CoordinateSystem;
-
-  x1 := RawXCoord;
-
-  case coord of
-    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
-      begin
-        Y1 := RawYCoord;
-        result := ecCurve.CreateRawPoint(x1.SquarePow(pow), Y1.SquarePow(pow),
-          IsCompressed) as IAbstractF2mPoint;
-        Exit;
-      end;
-
-    TECCurveConstants.COORD_HOMOGENEOUS,
-      TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      begin
-        Y1 := RawYCoord;
-        Z1 := RawZCoords[0];
-        result := ecCurve.CreateRawPoint(x1.SquarePow(pow), Y1.SquarePow(pow),
-          TCryptoLibGenericArray<IECFieldElement>.Create(Z1.SquarePow(pow)),
-          IsCompressed) as IAbstractF2mPoint;
-        Exit;
-      end
-
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnSupportedCoordinateSystem);
-    end;
-
-  end;
-end;
-
-{ TECPoint.TValidityCallback }
-
-constructor TECPoint.TValidityCallback.Create(const outer: IECPoint;
-  decompressed, checkOrder: Boolean);
-begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_decompressed := decompressed;
-  Fm_checkOrder := checkOrder;
-end;
-
-function TECPoint.TValidityCallback.Precompute(const existing: IPreCompInfo)
-  : IPreCompInfo;
-var
-  info: IValidityPrecompInfo;
-begin
-  if (not(Supports(existing, IValidityPrecompInfo, info))) then
-  begin
-    info := TValidityPrecompInfo.Create();
-  end;
-
-  if (info.hasFailed()) then
-  begin
-    result := info;
-    Exit;
-  end;
-  if (not(info.hasCurveEquationPassed())) then
-  begin
-    if (not(Fm_decompressed) and not(Fm_outer.SatisfiesCurveEquation())) then
-    begin
-      info.reportFailed();
-      result := info;
-      Exit;
-    end;
-    info.reportCurveEquationPassed();
-  end;
-
-  if ((Fm_checkOrder) and (not(info.HasOrderPassed()))) then
-  begin
-    if (not(Fm_outer.SatisfiesOrder())) then
-    begin
-      info.reportFailed();
-      result := info;
-      Exit;
-    end;
-    info.reportOrderPassed();
-  end;
-  result := info;
-end;
-
-{ TSimpleLookupTable }
-
-class function TSimpleLookupTable.Copy(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-  : TCryptoLibGenericArray<IECPoint>;
-var
-  i: Int32;
-begin
-  System.SetLength(result, len);
-  for i := 0 to System.Pred(len) do
-  begin
-    result[i] := points[off + i];
-  end;
-end;
-
-constructor TSimpleLookupTable.Create(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32);
-begin
-  inherited Create();
-  FPoints := Copy(points, off, len);
-end;
-
-destructor TSimpleLookupTable.Destroy;
-var
-  i: Integer;
-begin
-  if Assigned(FPoints) then
-  begin
-    for i := 0 to Length(FPoints) - 1 do
-      FPoints[i] := nil;
-    FPoints := nil;
-  end;
-  inherited;
-end;
-
-function TSimpleLookupTable.GetSize: Int32;
-begin
-  result := System.Length(FPoints);
-end;
-
-function TSimpleLookupTable.Lookup(index: Int32): IECPoint;
-begin
-  raise EInvalidOperationCryptoLibException.CreateRes(@SUnsupportedOperation);
-end;
-
-function TSimpleLookupTable.LookupVar(index: Int32): IECPoint;
-begin
-  result := FPoints[index];
-end;
-
-end.

+ 0 - 1537
CryptoLib/src/Math/EC/ClpECCompUtilities.pas

@@ -1,1537 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpECCompUtilities;
-
-{$I ..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  SysUtils,
-  Math,
-  ClpBitOperations,
-  ClpIECC,
-  ClpIPreCompInfo,
-  ClpIWNafPreCompInfo,
-  ClpWNafPreCompInfo,
-  ClpEndoPreCompInfo,
-  ClpIFixedPointPreCompInfo,
-  ClpIPreCompCallBack,
-  ClpBigInteger,
-  ClpIEndoPreCompInfo,
-  ClpIScalarSplitParameters,
-  ClpFixedPointPreCompInfo,
-  ClpCryptoLibTypes,
-  ClpECCurveConstants;
-
-resourcestring
-  SInvalidRange = 'Must be in the Range [2, 16], "width"';
-  SInvalidRange2 = 'Must be in the Range [2, 8], "width"';
-  SInvalidBitLength = 'Invalid BitLength';
-
-type
-  TWNafUtilities = class abstract(TObject)
-
-  strict private
-  const
-    DEFAULT_WINDOW_SIZE_CUTOFFS: array [0 .. 5] of Int32 = (13, 41, 121, 337,
-      897, 2305);
-
-    MAX_WIDTH = Int32(16);
-
-  class var
-    FEMPTY_BYTES: TCryptoLibByteArray;
-    FEMPTY_INTS: TCryptoLibInt32Array;
-
-  type
-    IMapPointCallback = interface(IPreCompCallback)
-      ['{730BF27F-D5C3-4DF4-AC77-B8653C457C10}']
-
-    end;
-
-    // type
-    // TMapPointCallback = class(TInterfacedObject, IPreCompCallback,
-    // IMapPointCallback)
-    //
-    // strict private
-    // var
-    // Fm_wnafPreCompP: IWNafPreCompInfo;
-    // Fm_includeNegated: Boolean;
-    // Fm_pointMap: IECPointMap;
-    //
-    // public
-    // constructor Create(const wnafPreCompP: IWNafPreCompInfo;
-    // includeNegated: Boolean; const pointMap: IECPointMap);
-    //
-    // function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-    //
-    // end;
-
-  type
-    IWNafCallback = interface(IPreCompCallback)
-      ['{A439A606-7899-4720-937E-C2F3D94D4811}']
-
-    end;
-
-  type
-    TWNafCallback = class(TInterfacedObject, IPreCompCallback, IWNafCallback)
-
-    strict private
-
-    var
-      Fm_p: IECPoint;
-      FminWidth: Int32;
-      Fm_includeNegated: Boolean;
-
-      class function CheckExisting(const existingWNaf: IWNafPreCompInfo;
-        width, reqPreCompLen: Int32; includeNegated: Boolean): Boolean;
-        static; inline;
-
-      class function CheckTable(const table: TCryptoLibGenericArray<IECPoint>;
-        reqLen: Int32): Boolean; static; inline;
-
-    public
-      constructor Create(const p: IECPoint; minWidth: Int32;
-        includeNegated: Boolean);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  type
-    IPointMapCallback = interface(IPreCompCallback)
-      ['{00A66D4E-7D61-4A47-AE36-E8D89DEE8D9F}']
-
-    end;
-
-  type
-    TPointMapCallback = class(TInterfacedObject, IPreCompCallback,
-      IPointMapCallback)
-
-    strict private
-
-    var
-      Fm_p: IECPoint;
-      FpointMap: IECPointMap;
-      FfromWNaf: IWNafPreCompInfo;
-      FIncludeNegated: Boolean;
-
-      class function CheckExisting(const existingWNaf: IWNafPreCompInfo;
-        width, reqPreCompLen: Int32; includeNegated: Boolean): Boolean;
-        static; inline;
-
-      class function CheckTable(const table: TCryptoLibGenericArray<IECPoint>;
-        reqLen: Int32): Boolean; static; inline;
-
-    public
-      constructor Create(const p: IECPoint; const pointMap: IECPointMap;
-        const fromWNaf: IWNafPreCompInfo; includeNegated: Boolean);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  type
-    IBasePointCallback = interface(IPreCompCallback)
-      ['{5A81CB00-3CB4-474D-A2A7-E949F7E71AEC}']
-
-    end;
-
-  type
-    TBasePointCallback = class(TInterfacedObject, IPreCompCallback,
-      IBasePointCallback)
-
-    strict private
-    var
-      FConfWidth: Int32;
-
-    public
-      constructor Create(ConfWidth: Int32);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  class function Trim(const a: TCryptoLibByteArray; length: Int32)
-    : TCryptoLibByteArray; overload; static; inline;
-
-  class function Trim(const a: TCryptoLibInt32Array; length: Int32)
-    : TCryptoLibInt32Array; overload; static; inline;
-
-  class function ResizeTable(const a: TCryptoLibGenericArray<IECPoint>;
-    length: Int32): TCryptoLibGenericArray<IECPoint>; static; inline;
-
-  class procedure Boot(); static;
-  class constructor CreateWNafUtilities();
-
-  public
-
-    const
-    PRECOMP_NAME: String = 'bc_wnaf';
-
-    class function GenerateCompactNaf(const k: TBigInteger)
-      : TCryptoLibInt32Array; static;
-    class function GenerateCompactWindowNaf(width: Int32; const k: TBigInteger)
-      : TCryptoLibInt32Array; static;
-
-    class function GenerateJsf(const g, h: TBigInteger)
-      : TCryptoLibByteArray; static;
-    class function GenerateNaf(const k: TBigInteger)
-      : TCryptoLibByteArray; static;
-    // /**
-    // * Computes the Window NAF (non-adjacent Form) of an integer.
-    // * @param width The width <code>w</code> of the Window NAF. The width is
-    // * defined as the minimal number <code>w</code>, such that for any
-    // * <code>w</code> consecutive digits in the resulting representation, at
-    // * most one is non-zero.
-    // * @param k The integer of which the Window NAF is computed.
-    // * @return The Window NAF of the given width, such that the following holds:
-    // * <code>k = &amp;sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
-    // * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
-    // * returned <code>byte[]</code>.
-    // */
-    class function GenerateWindowNaf(width: Int32; const k: TBigInteger)
-      : TCryptoLibByteArray; static;
-
-    class function GetNafWeight(const k: TBigInteger): Int32; static; inline;
-
-    class function GetWNafPreCompInfo(const p: IECPoint): IWNafPreCompInfo;
-      overload; static; inline;
-
-    class function GetWNafPreCompInfo(const preCompInfo: IPreCompInfo)
-      : IWNafPreCompInfo; overload; static; inline;
-
-    /// <summary>
-    /// Determine window width to use for a scalar multiplication of the
-    /// given size.
-    /// </summary>
-    /// <param name="bits">
-    /// the bit-length of the scalar to multiply by
-    /// </param>
-    /// <returns>
-    /// the window size to use
-    /// </returns>
-    class function GetWindowSize(bits: Int32): Int32; overload; static; inline;
-
-    /// <summary>
-    /// Determine window width to use for a scalar multiplication of the
-    /// given size.
-    /// </summary>
-    /// <param name="bits">
-    /// the bit-length of the scalar to multiply by
-    /// </param>
-    /// <param name="maxWidth">
-    /// the maximum window width to return
-    /// </param>
-    /// <returns>
-    /// the window size to use
-    /// </returns>
-    class function GetWindowSize(bits, maxWidth: Int32): Int32; overload;
-      static; inline;
-
-    /// <summary>
-    /// Determine window width to use for a scalar multiplication of the
-    /// given size.
-    /// </summary>
-    /// <param name="bits">
-    /// the bit-length of the scalar to multiply by
-    /// </param>
-    /// <param name="windowSizeCutoffs">
-    /// a monotonically increasing list of bit sizes at which to increment
-    /// the window width
-    /// </param>
-    /// <returns>
-    /// the window size to use
-    /// </returns>
-    class function GetWindowSize(bits: Int32;
-      const windowSizeCutoffs: array of Int32): Int32; overload; static;
-
-    /// <summary>
-    /// Determine window width to use for a scalar multiplication of the
-    /// given size.
-    /// </summary>
-    /// <param name="bits">
-    /// the bit-length of the scalar to multiply by
-    /// </param>
-    /// <param name="windowSizeCutoffs">
-    /// a monotonically increasing list of bit sizes at which to increment
-    /// the window width
-    /// </param>
-    /// /// <param name="maxWidth">
-    /// the maximum window width to return
-    /// </param>
-    /// <returns>
-    /// the window size to use
-    /// </returns>
-    class function GetWindowSize(bits: Int32;
-      const windowSizeCutoffs: array of Int32; maxWidth: Int32): Int32;
-      overload; static;
-
-    class function Precompute(const p: IECPoint; minWidth: Int32;
-      includeNegated: Boolean): IWNafPreCompInfo; static;
-
-    class procedure ConfigureBasepoint(const p: IECPoint); static;
-
-    class function PrecomputeWithPointMap(const p: IECPoint;
-      const pointMap: IECPointMap; const fromWNaf: IWNafPreCompInfo;
-      includeNegated: Boolean): IWNafPreCompInfo;
-
-  end;
-
-type
-  TEndoUtilities = class abstract(TObject)
-
-  strict private
-  type
-    IEndoCallback = interface(IPreCompCallback)
-      ['{80C0B850-A97A-4603-A42F-A476ABAF2026}']
-
-    end;
-
-  type
-    TEndoCallback = class(TInterfacedObject, IPreCompCallback, IEndoCallback)
-
-    strict private
-    var
-      Fendomorphism: IECEndomorphism;
-      Fp: IECPoint;
-
-      class function CheckExisting(const existingEndo: IEndoPreCompInfo;
-        const endomorphism: IECEndomorphism): Boolean; static; inline;
-
-    public
-      constructor Create(const endomorphism: IECEndomorphism;
-        const p: IECPoint);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  class function CalculateB(const k, g: TBigInteger; t: Int32)
-    : TBigInteger; static;
-
-  public
-
-    const
-    PRECOMP_NAME: String = 'bc_endo';
-
-  public
-    class function MapPoint(const endomorphism: IECEndomorphism;
-      const p: IECPoint): IECPoint; static;
-
-    class function DecomposeScalar(const p: IScalarSplitParameters;
-      const k: TBigInteger): TCryptoLibGenericArray<TBigInteger>; static;
-
-  end;
-
-type
-  TFixedPointUtilities = class sealed(TObject)
-  strict private
-
-  type
-    IFixedPointCallback = interface(IPreCompCallback)
-      ['{E6DFE8D3-A890-4568-AA4A-3D8BC6AF16E9}']
-
-    end;
-
-  type
-    TFixedPointCallback = class(TInterfacedObject, IPreCompCallback,
-      IFixedPointCallback)
-
-    strict private
-    var
-      Fm_p: IECPoint;
-
-      class function CheckExisting(const existingFP: IFixedPointPreCompInfo;
-        n: Int32): Boolean; static; inline;
-
-      class function CheckTable(const table: IECLookupTable; n: Int32): Boolean;
-        static; inline;
-
-    public
-      constructor Create(const p: IECPoint);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  const
-    PRECOMP_NAME: String = 'bc_fixed_point';
-
-  public
-
-    class function GetFixedPointPreCompInfo(const preCompInfo: IPreCompInfo)
-      : IFixedPointPreCompInfo; static; inline;
-
-    class function GetCombSize(const c: IECCurve): Int32; static; inline;
-
-    class function Precompute(const p: IECPoint)
-      : IFixedPointPreCompInfo; static;
-  end;
-
-implementation
-
-{ TWNafUtilities }
-
-uses
-  ClpECAlgorithms; // included here to avoid circular dependency :)
-
-class function TWNafUtilities.ResizeTable
-  (const a: TCryptoLibGenericArray<IECPoint>; length: Int32)
-  : TCryptoLibGenericArray<IECPoint>;
-begin
-  Result := a;
-  System.SetLength(Result, length);
-end;
-
-class function TWNafUtilities.Trim(const a: TCryptoLibInt32Array; length: Int32)
-  : TCryptoLibInt32Array;
-begin
-  Result := a;
-  System.SetLength(Result, length);
-end;
-
-class function TWNafUtilities.Trim(const a: TCryptoLibByteArray; length: Int32)
-  : TCryptoLibByteArray;
-begin
-  Result := a;
-  System.SetLength(Result, length);
-end;
-
-class procedure TWNafUtilities.Boot;
-begin
-  FEMPTY_BYTES := Nil;
-  FEMPTY_INTS := Nil;
-end;
-
-class constructor TWNafUtilities.CreateWNafUtilities;
-begin
-  TWNafUtilities.Boot;
-end;
-
-class function TWNafUtilities.GetWindowSize(bits: Int32;
-  const windowSizeCutoffs: array of Int32; maxWidth: Int32): Int32;
-var
-  w: Int32;
-begin
-  w := 0;
-  while (w < System.length(windowSizeCutoffs)) do
-  begin
-    if (bits < windowSizeCutoffs[w]) then
-    begin
-      break;
-    end;
-    System.Inc(w);
-  end;
-
-  Result := Max(2, Min(maxWidth, w + 2));
-end;
-
-class function TWNafUtilities.GetWindowSize(bits: Int32;
-  const windowSizeCutoffs: array of Int32): Int32;
-begin
-  Result := GetWindowSize(bits, windowSizeCutoffs, MAX_WIDTH);
-end;
-
-class function TWNafUtilities.GetWindowSize(bits, maxWidth: Int32): Int32;
-begin
-  Result := GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS, maxWidth);
-end;
-
-class function TWNafUtilities.GetWindowSize(bits: Int32): Int32;
-begin
-  Result := GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS, MAX_WIDTH);
-end;
-
-class procedure TWNafUtilities.ConfigureBasepoint(const p: IECPoint);
-var
-  c: IECCurve;
-  n: TBigInteger;
-  bits, ConfWidth: Int32;
-begin
-  c := p.Curve;
-  if (c = Nil) then
-  begin
-    Exit;
-  end;
-
-  n := c.Order;
-  if (not n.IsInitialized) then
-  begin
-    bits := c.FieldSize + 1;
-  end
-  else
-  begin
-    bits := n.BitLength;
-  end;
-
-  ConfWidth := Min(MAX_WIDTH, GetWindowSize(bits) + 3);
-
-  c.Precompute(p, PRECOMP_NAME, TBasePointCallback.Create(ConfWidth)
-    as IBasePointCallback);
-end;
-
-class function TWNafUtilities.GenerateCompactNaf(const k: TBigInteger)
-  : TCryptoLibInt32Array;
-var
-  _3k, diff: TBigInteger;
-  bits, highBit, &length, zeroes, i, digit: Int32;
-  naf: TCryptoLibInt32Array;
-begin
-  if ((TBitOperations.Asr32(k.BitLength, 16)) <> 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidBitLength);
-  end;
-  if (k.SignValue = 0) then
-  begin
-    Result := FEMPTY_INTS;
-    Exit;
-  end;
-
-  _3k := k.ShiftLeft(1).Add(k);
-
-  bits := _3k.BitLength;
-  System.SetLength(naf, TBitOperations.Asr32(bits, 1));
-
-  diff := _3k.&Xor(k);
-
-  highBit := bits - 1;
-  &length := 0;
-  zeroes := 0;
-
-  i := 1;
-
-  while (i < highBit) do
-  begin
-    if (not diff.TestBit(i)) then
-    begin
-      System.Inc(zeroes);
-      System.Inc(i);
-      continue;
-    end;
-
-    if k.TestBit(i) then
-    begin
-      digit := -1;
-    end
-    else
-    begin
-      digit := 1;
-    end;
-
-    naf[length] := (digit shl 16) or zeroes;
-    System.Inc(length);
-    zeroes := 1;
-
-    System.Inc(i, 2);
-
-  end;
-
-  naf[length] := (1 shl 16) or zeroes;
-  System.Inc(length);
-
-  if (System.length(naf) > length) then
-  begin
-    naf := Trim(naf, length);
-  end;
-
-  Result := naf;
-end;
-
-class function TWNafUtilities.GenerateCompactWindowNaf(width: Int32;
-  const k: TBigInteger): TCryptoLibInt32Array;
-var
-  wnaf: TCryptoLibInt32Array;
-  pow2, mask, sign, &length, &pos, digit, zeroes: Int32;
-  carry: Boolean;
-  LK: TBigInteger;
-begin
-  LK := k;
-  if (width = 2) then
-  begin
-    Result := GenerateCompactNaf(LK);
-    Exit;
-  end;
-
-  if ((width < 2) or (width > 16)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidRange);
-  end;
-  if ((TBitOperations.Asr32(LK.BitLength, 16)) <> 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidBitLength);
-  end;
-  if (LK.SignValue = 0) then
-  begin
-    Result := FEMPTY_INTS;
-    Exit;
-  end;
-
-  System.SetLength(wnaf, (LK.BitLength div width) + 1);
-
-  // 2^width and a mask and sign bit set accordingly
-  pow2 := 1 shl width;
-  mask := pow2 - 1;
-  sign := TBitOperations.Asr32(pow2, 1);
-
-  carry := false;
-  length := 0;
-  pos := 0;
-
-  while (pos <= LK.BitLength) do
-  begin
-    if (LK.TestBit(pos) = carry) then
-    begin
-      System.Inc(pos);
-      continue;
-    end;
-
-    LK := LK.ShiftRight(pos);
-
-    digit := LK.Int32Value and mask;
-    if (carry) then
-    begin
-      System.Inc(digit);
-    end;
-
-    carry := (digit and sign) <> 0;
-    if (carry) then
-    begin
-      digit := digit - pow2;
-    end;
-
-    if length > 0 then
-    begin
-      zeroes := pos - 1;
-    end
-    else
-    begin
-      zeroes := pos;
-    end;
-
-    wnaf[length] := (digit shl 16) or zeroes;
-    System.Inc(length);
-    pos := width;
-  end;
-
-  // Reduce the WNAF array to its actual length
-  if (System.length(wnaf) > length) then
-  begin
-    wnaf := Trim(wnaf, length);
-  end;
-
-  Result := wnaf;
-end;
-
-class function TWNafUtilities.GenerateJsf(const g, h: TBigInteger)
-  : TCryptoLibByteArray;
-var
-  digits, j, d0, d1, Offset, n0, n1, u0, u1: Int32;
-  jsf: TCryptoLibByteArray;
-  k0, k1: TBigInteger;
-begin
-  digits := Max(g.BitLength, h.BitLength) + 1;
-
-  System.SetLength(jsf, digits);
-
-  k0 := g;
-  k1 := h;
-  j := 0;
-  d0 := 0;
-  d1 := 0;
-
-  Offset := 0;
-
-  while (((d0 or d1) <> 0) or (k0.BitLength > Offset) or
-    (k1.BitLength > Offset)) do
-  begin
-    n0 := (Int32(UInt32(k0.Int32Value) shr Offset) + d0) and 7;
-    n1 := (Int32(UInt32(k1.Int32Value) shr Offset) + d1) and 7;
-
-    u0 := n0 and 1;
-    if (u0 <> 0) then
-    begin
-      u0 := u0 - (n0 and 2);
-      if (((n0 + u0) = 4) and ((n1 and 3) = 2)) then
-      begin
-        u0 := -u0;
-      end;
-    end;
-
-    u1 := n1 and 1;
-    if (u1 <> 0) then
-    begin
-      u1 := u1 - (n1 and 2);
-      if (((n1 + u1) = 4) and ((n0 and 3) = 2)) then
-      begin
-        u1 := -u1;
-      end;
-    end;
-
-    if ((d0 shl 1) = (1 + u0)) then
-    begin
-      d0 := d0 xor 1;
-    end;
-    if ((d1 shl 1) = (1 + u1)) then
-    begin
-      d1 := d1 xor 1;
-    end;
-
-    System.Inc(Offset);
-    if (Offset = 30) then
-    begin
-      Offset := 0;
-      k0 := k0.ShiftRight(30);
-      k1 := k1.ShiftRight(30);
-    end;
-
-    jsf[j] := Byte((u0 shl 4) or (u1 and $F));
-    System.Inc(j);
-  end;
-
-  // Reduce the JSF array to its actual length
-  if (System.length(jsf) > j) then
-  begin
-    jsf := Trim(jsf, j);
-  end;
-
-  Result := jsf;
-end;
-
-class function TWNafUtilities.GenerateNaf(const k: TBigInteger)
-  : TCryptoLibByteArray;
-var
-  _3k, diff: TBigInteger;
-  digits, i: Int32;
-  naf: TCryptoLibByteArray;
-begin
-  if (k.SignValue = 0) then
-  begin
-    Result := FEMPTY_BYTES;
-    Exit;
-  end;
-
-  _3k := k.ShiftLeft(1).Add(k);
-
-  digits := _3k.BitLength - 1;
-  System.SetLength(naf, digits);
-
-  diff := _3k.&Xor(k);
-
-  i := 1;
-
-  while i < digits do
-  begin
-    if (diff.TestBit(i)) then
-    begin
-      if k.TestBit(i) then
-      begin
-        naf[i - 1] := Byte(-1);
-      end
-      else
-      begin
-        naf[i - 1] := Byte(1);
-      end;
-
-      System.Inc(i);
-    end;
-    System.Inc(i);
-  end;
-
-  naf[digits - 1] := 1;
-
-  Result := naf;
-end;
-
-class function TWNafUtilities.GenerateWindowNaf(width: Int32;
-  const k: TBigInteger): TCryptoLibByteArray;
-var
-  wnaf: TCryptoLibByteArray;
-  pow2, mask, sign, &length, &pos, digit: Int32;
-  carry: Boolean;
-  LK: TBigInteger;
-begin
-  LK := k;
-  if (width = 2) then
-  begin
-    Result := GenerateNaf(LK);
-    Exit;
-  end;
-
-  if ((width < 2) or (width > 8)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidRange2);
-  end;
-  if (LK.SignValue = 0) then
-  begin
-    Result := FEMPTY_BYTES;
-    Exit;
-  end;
-
-  System.SetLength(wnaf, LK.BitLength + 1);
-
-  // 2^width and a mask and sign bit set accordingly
-  pow2 := 1 shl width;
-  mask := pow2 - 1;
-  sign := TBitOperations.Asr32(pow2, 1);
-
-  carry := false;
-  length := 0;
-  pos := 0;
-
-  while (pos <= LK.BitLength) do
-  begin
-    if (LK.TestBit(pos) = carry) then
-    begin
-      System.Inc(pos);
-      continue;
-    end;
-
-    LK := LK.ShiftRight(pos);
-
-    digit := LK.Int32Value and mask;
-    if (carry) then
-    begin
-      System.Inc(digit);
-    end;
-
-    carry := (digit and sign) <> 0;
-    if (carry) then
-    begin
-      digit := digit - pow2;
-    end;
-
-    if length > 0 then
-    begin
-      length := length + (pos - 1);
-    end
-    else
-    begin
-      length := length + (pos);
-    end;
-
-    wnaf[length] := Byte(digit);
-    System.Inc(length);
-    pos := width;
-  end;
-
-  // Reduce the WNAF array to its actual length
-  if (System.length(wnaf) > length) then
-  begin
-    wnaf := Trim(wnaf, length);
-  end;
-
-  Result := wnaf;
-end;
-
-class function TWNafUtilities.GetNafWeight(const k: TBigInteger): Int32;
-var
-  _3k, diff: TBigInteger;
-begin
-  if (k.SignValue = 0) then
-  begin
-    Result := 0;
-    Exit;
-  end;
-
-  _3k := k.ShiftLeft(1).Add(k);
-  diff := _3k.&Xor(k);
-
-  Result := diff.BitCount;
-end;
-
-class function TWNafUtilities.GetWNafPreCompInfo(const preCompInfo
-  : IPreCompInfo): IWNafPreCompInfo;
-begin
-  Result := preCompInfo as IWNafPreCompInfo;
-end;
-
-class function TWNafUtilities.GetWNafPreCompInfo(const p: IECPoint)
-  : IWNafPreCompInfo;
-var
-  preCompInfo: IPreCompInfo;
-begin
-  preCompInfo := p.Curve.GetPreCompInfo(p, PRECOMP_NAME);
-  Result := GetWNafPreCompInfo(preCompInfo);
-end;
-
-class function TWNafUtilities.Precompute(const p: IECPoint; minWidth: Int32;
-  includeNegated: Boolean): IWNafPreCompInfo;
-begin
-  Result := p.Curve.Precompute(p, PRECOMP_NAME,
-    TWNafCallback.Create(p, minWidth, includeNegated) as IWNafCallback)
-    as IWNafPreCompInfo;
-end;
-
-class function TWNafUtilities.PrecomputeWithPointMap(const p: IECPoint;
-  const pointMap: IECPointMap; const fromWNaf: IWNafPreCompInfo;
-  includeNegated: Boolean): IWNafPreCompInfo;
-var
-  c: IECCurve;
-begin
-  c := p.Curve;
-  Result := c.Precompute(p, PRECOMP_NAME, TPointMapCallback.Create(p, pointMap,
-    fromWNaf, includeNegated) as IPointMapCallback) as IWNafPreCompInfo;
-end;
-
-// { TWNafUtilities.TMapPointCallback }
-//
-// constructor TWNafUtilities.TMapPointCallback.Create(const wnafPreCompP
-// : IWNafPreCompInfo; includeNegated: Boolean; const pointMap: IECPointMap);
-// begin
-// Inherited Create();
-// Fm_wnafPreCompP := wnafPreCompP;
-// Fm_includeNegated := includeNegated;
-// Fm_pointMap := pointMap;
-// end;
-//
-// function TWNafUtilities.TMapPointCallback.Precompute(const existing
-// : IPreCompInfo): IPreCompInfo;
-// var
-// tempResult: IWNafPreCompInfo;
-// twiceP, twiceQ: IECPoint;
-// preCompP, preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
-// i: Int32;
-// begin
-// tempResult := TWNafPreCompInfo.Create();
-//
-// tempResult.ConfWidth := Fm_wnafPreCompP.ConfWidth;
-//
-// twiceP := Fm_wnafPreCompP.Twice;
-// if (twiceP <> Nil) then
-// begin
-// twiceQ := Fm_pointMap.Map(twiceP);
-// tempResult.Twice := twiceQ;
-// end;
-//
-// preCompP := Fm_wnafPreCompP.PreComp;
-//
-// System.SetLength(preCompQ, System.length(preCompP));
-// for i := 0 to System.Pred(System.length(preCompP)) do
-// begin
-// preCompQ[i] := Fm_pointMap.Map(preCompP[i]);
-// end;
-//
-// tempResult.PreComp := preCompQ;
-// tempResult.width := Fm_wnafPreCompP.width;
-//
-// if (Fm_includeNegated) then
-// begin
-//
-// System.SetLength(preCompNegQ, System.length(preCompQ));
-//
-// for i := 0 to System.Pred(System.length(preCompNegQ)) do
-// begin
-// preCompNegQ[i] := preCompQ[i].Negate();
-// end;
-//
-// tempResult.PreCompNeg := preCompNegQ;
-// end;
-//
-// result := tempResult;
-// end;
-
-{ TWNafUtilities.TWNafCallback }
-
-class function TWNafUtilities.TWNafCallback.CheckTable
-  (const table: TCryptoLibGenericArray<IECPoint>; reqLen: Int32): Boolean;
-begin
-  Result := (table <> Nil) and (System.length(table) >= reqLen);
-end;
-
-class function TWNafUtilities.TWNafCallback.CheckExisting(const existingWNaf
-  : IWNafPreCompInfo; width, reqPreCompLen: Int32;
-  includeNegated: Boolean): Boolean;
-begin
-  Result := (existingWNaf <> Nil) and
-    (existingWNaf.width >= Max(existingWNaf.ConfWidth, width))
-
-    and CheckTable(existingWNaf.PreComp, reqPreCompLen) and
-    ((not includeNegated) or CheckTable(existingWNaf.PreCompNeg,
-    reqPreCompLen));
-end;
-
-constructor TWNafUtilities.TWNafCallback.Create(const p: IECPoint;
-  minWidth: Int32; includeNegated: Boolean);
-begin
-  Inherited Create();
-  Fm_p := p;
-  FminWidth := minWidth;
-  Fm_includeNegated := includeNegated;
-end;
-
-function TWNafUtilities.TWNafCallback.Precompute(const existing: IPreCompInfo)
-  : IPreCompInfo;
-var
-  twiceP, isoTwiceP, last: IECPoint;
-  c: IECCurve;
-  PreComp, PreCompNeg, EMPTY_POINTS: TCryptoLibGenericArray<IECPoint>;
-  tempRes, existingWNaf: IWNafPreCompInfo;
-  reqPreCompLen, iniPreCompLen, curPreCompLen, pos, width, PromotionCountdown,
-    ConfWidth: Int32;
-  iso, iso2, iso3: IECFieldElement;
-begin
-  c := Fm_p.Curve;
-  EMPTY_POINTS := Nil;
-  existingWNaf := existing as IWNafPreCompInfo;
-
-  width := Max(2, Min(MAX_WIDTH, FminWidth));
-  reqPreCompLen := 1 shl (width - 2);
-
-  if (CheckExisting(existingWNaf, width, reqPreCompLen, Fm_includeNegated)) then
-  begin
-    existingWNaf.DecrementPromotionCountdown;
-    Result := existingWNaf;
-    Exit;
-  end;
-
-  tempRes := TWNafPreCompInfo.Create();
-
-  if (existingWNaf <> Nil) then
-  begin
-
-    PromotionCountdown := existingWNaf.DecrementPromotionCountdown;
-    tempRes.PromotionCountdown := PromotionCountdown;
-
-    ConfWidth := existingWNaf.ConfWidth;
-    tempRes.ConfWidth := ConfWidth;
-
-    PreComp := existingWNaf.PreComp;
-    PreCompNeg := existingWNaf.PreCompNeg;
-    twiceP := existingWNaf.Twice;
-  end;
-
-  width := Min(MAX_WIDTH, Max(tempRes.ConfWidth, width));
-  reqPreCompLen := 1 shl (width - 2);
-
-  iniPreCompLen := 0;
-  if (PreComp = Nil) then
-  begin
-    PreComp := EMPTY_POINTS;
-  end
-  else
-  begin
-    iniPreCompLen := System.length(PreComp);
-  end;
-
-  if (iniPreCompLen < reqPreCompLen) then
-  begin
-    PreComp := TWNafUtilities.ResizeTable(PreComp, reqPreCompLen);
-
-    if (reqPreCompLen = 1) then
-    begin
-      PreComp[0] := Fm_p.Normalize();
-    end
-    else
-    begin
-      curPreCompLen := iniPreCompLen;
-      if (curPreCompLen = 0) then
-      begin
-        PreComp[0] := Fm_p.Clone();
-        curPreCompLen := 1;
-      end;
-
-      if (reqPreCompLen = 2) then
-      begin
-        PreComp[1] := Fm_p.threeTimes();
-      end
-      else
-      begin
-        isoTwiceP := twiceP;
-        last := PreComp[curPreCompLen - 1];
-        if (isoTwiceP = Nil) then
-        begin
-          isoTwiceP := PreComp[0].Twice();
-          twiceP := isoTwiceP;
-          //
-          // /*
-          // * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
-          // * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
-          // * also requires scaling the initial point's X, Y coordinates, and reversing the
-          // * isomorphism as part of the subsequent normalization.
-          // *
-          // *  NOTE: The correctness of this optimization depends on:
-          // *      1) additions do not use the curve's A, B coefficients.
-          // *      2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
-          // */
-          if ((not(twiceP.IsInfinity)) and (TECAlgorithms.IsFpCurve(c)) and
-            (c.FieldSize >= 64)) then
-          begin
-            case (c.CoordinateSystem) of
-              TECCurveConstants.COORD_JACOBIAN,
-                TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
-                TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-
-                begin
-                  iso := twiceP.GetZCoord(0);
-                  isoTwiceP := c.CreatePoint(twiceP.XCoord.ToBigInteger,
-                    twiceP.YCoord.ToBigInteger());
-
-                  iso2 := iso.square();
-                  iso3 := iso2.Multiply(iso);
-                  last := last.scaleX(iso2).scaleY(iso3);
-
-                  if (iniPreCompLen = 0) then
-                  begin
-                    PreComp[0] := last;
-                  end;
-                end;
-
-            end;
-
-          end;
-        end;
-
-        while (curPreCompLen < reqPreCompLen) do
-        begin
-          // /*
-          // * Compute the new ECPoints for the precomputation array. The values 1, 3,
-          // * 5, ..., 2^(width-1)-1 times p are computed
-          // */
-          last := last.Add(isoTwiceP);
-          PreComp[curPreCompLen] := last;
-          System.Inc(curPreCompLen);
-        end;
-      end;
-      //
-      // /*
-      // * Having oft-used operands in affine form makes operations faster.
-      // */
-      c.NormalizeAll(PreComp, iniPreCompLen,
-        reqPreCompLen - iniPreCompLen, iso);
-    end;
-  end;
-
-  if (Fm_includeNegated) then
-  begin
-
-    if (PreCompNeg = Nil) then
-    begin
-      pos := 0;
-      System.SetLength(PreCompNeg, reqPreCompLen);
-
-    end
-    else
-    begin
-      pos := System.length(PreCompNeg);
-      if (pos < reqPreCompLen) then
-      begin
-        PreCompNeg := TWNafUtilities.ResizeTable(PreCompNeg, reqPreCompLen);
-      end;
-    end;
-
-    while (pos < reqPreCompLen) do
-    begin
-      PreCompNeg[pos] := PreComp[pos].Negate();
-      System.Inc(pos);
-    end;
-  end;
-
-  tempRes.PreComp := PreComp;
-  tempRes.PreCompNeg := PreCompNeg;
-  tempRes.Twice := twiceP;
-  tempRes.width := width;
-
-  Result := tempRes;
-end;
-
-{ TWNafUtilities.TBasePointCallback }
-
-constructor TWNafUtilities.TBasePointCallback.Create(ConfWidth: Int32);
-begin
-  Inherited Create();
-  FConfWidth := ConfWidth;
-end;
-
-function TWNafUtilities.TBasePointCallback.Precompute(const existing
-  : IPreCompInfo): IPreCompInfo;
-var
-  existingWNaf, tempResult: IWNafPreCompInfo;
-begin
-
-  if Supports(existing, IWNafPreCompInfo) then
-  begin
-    existingWNaf := existing as IWNafPreCompInfo;
-  end
-  else
-  begin
-    existingWNaf := Nil;
-  end;
-
-  if ((existingWNaf <> Nil) and (existingWNaf.ConfWidth = FConfWidth)) then
-  begin
-    existingWNaf.PromotionCountdown := 0;
-    Result := existingWNaf;
-    Exit;
-  end;
-
-  tempResult := TWNafPreCompInfo.Create();
-
-  tempResult.PromotionCountdown := 0;
-  tempResult.ConfWidth := FConfWidth;
-
-  if (existingWNaf <> Nil) then
-  begin
-    tempResult.PreComp := existingWNaf.PreComp;
-    tempResult.PreCompNeg := existingWNaf.PreCompNeg;
-    tempResult.Twice := existingWNaf.Twice;
-    tempResult.width := existingWNaf.width;
-  end;
-  Result := tempResult;
-end;
-
-{ TWNafUtilities.TPointMapCallback }
-
-class function TWNafUtilities.TPointMapCallback.CheckTable
-  (const table: TCryptoLibGenericArray<IECPoint>; reqLen: Int32): Boolean;
-begin
-  Result := ((table <> Nil) and (System.length(table) >= reqLen));
-end;
-
-class function TWNafUtilities.TPointMapCallback.CheckExisting(const existingWNaf
-  : IWNafPreCompInfo; width, reqPreCompLen: Int32;
-  includeNegated: Boolean): Boolean;
-begin
-  Result := ((existingWNaf <> Nil) and (existingWNaf.width >= width) and
-    (CheckTable(existingWNaf.PreComp, reqPreCompLen)) and
-    ((not includeNegated) or (CheckTable(existingWNaf.PreCompNeg,
-    reqPreCompLen))));
-end;
-
-constructor TWNafUtilities.TPointMapCallback.Create(const p: IECPoint;
-  const pointMap: IECPointMap; const fromWNaf: IWNafPreCompInfo;
-  includeNegated: Boolean);
-begin
-  Inherited Create();
-  Fm_p := p;
-  FpointMap := pointMap;
-  FfromWNaf := fromWNaf;
-  FIncludeNegated := includeNegated;
-end;
-
-function TWNafUtilities.TPointMapCallback.Precompute(const existing
-  : IPreCompInfo): IPreCompInfo;
-var
-  existingWNaf: IWNafPreCompInfo;
-  width, reqPreCompLen, i: Int32;
-  tempResult: IWNafPreCompInfo;
-  twiceFrom, Ltwice: IECPoint;
-  LpreCompFrom, LpreComp, LpreCompNeg: TCryptoLibGenericArray<IECPoint>;
-begin
-  if Supports(existing, IWNafPreCompInfo) then
-  begin
-    existingWNaf := existing as IWNafPreCompInfo;
-  end
-  else
-  begin
-    existingWNaf := Nil;
-  end;
-  width := FfromWNaf.width;
-  reqPreCompLen := System.length(FfromWNaf.PreComp);
-
-  if (CheckExisting(existingWNaf, width, reqPreCompLen, FIncludeNegated)) then
-  begin
-    existingWNaf.DecrementPromotionCountdown;
-    Result := existingWNaf;
-    Exit;
-  end;
-
-  (*
-    * TODO Ideally this method would support incremental calculation, but given the
-    * existing use-cases it would be of little-to-no benefit.
-  *)
-  tempResult := TWNafPreCompInfo.Create();
-
-  tempResult.PromotionCountdown := FfromWNaf.PromotionCountdown;
-
-  twiceFrom := FfromWNaf.Twice;
-  if (twiceFrom <> Nil) then
-  begin
-    Ltwice := FpointMap.Map(twiceFrom);
-    tempResult.Twice := Ltwice;
-  end;
-
-  LpreCompFrom := FfromWNaf.PreComp;
-  System.SetLength(LpreComp, System.length(LpreCompFrom));
-
-  for i := 0 to System.Pred(System.length(LpreCompFrom)) do
-  begin
-    LpreComp[i] := FpointMap.Map(LpreCompFrom[i]);
-  end;
-  tempResult.PreComp := LpreComp;
-  tempResult.width := width;
-
-  if (FIncludeNegated) then
-  begin
-    System.SetLength(LpreCompNeg, System.length(LpreComp));
-
-    for i := 0 to System.Pred(System.length(LpreCompNeg)) do
-    begin
-      LpreCompNeg[i] := LpreComp[i].Negate();
-    end;
-    tempResult.PreCompNeg := LpreCompNeg;
-  end;
-
-  Result := tempResult;
-end;
-
-{ TEndoUtilities }
-
-class function TEndoUtilities.CalculateB(const k, g: TBigInteger; t: Int32)
-  : TBigInteger;
-var
-  negative, extra: Boolean;
-  b: TBigInteger;
-begin
-  negative := (g.SignValue < 0);
-  b := k.Multiply(g.Abs());
-  extra := b.TestBit(t - 1);
-  b := b.ShiftRight(t);
-  if (extra) then
-  begin
-    b := b.Add(TBigInteger.One);
-  end;
-
-  if negative then
-  begin
-    Result := b.Negate();
-  end
-  else
-  begin
-    Result := b;
-  end;
-end;
-
-class function TEndoUtilities.DecomposeScalar(const p: IScalarSplitParameters;
-  const k: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
-var
-  bits: Int32;
-  b1, b2, a, b: TBigInteger;
-begin
-
-  bits := p.bits;
-  b1 := CalculateB(k, p.G1, bits);
-  b2 := CalculateB(k, p.G2, bits);
-
-  a := k.Subtract((b1.Multiply(p.V1A)).Add(b2.Multiply(p.V2A)));
-  b := (b1.Multiply(p.V1B)).Add(b2.Multiply(p.V2B)).Negate();
-
-  Result := TCryptoLibGenericArray<TBigInteger>.Create(a, b);
-end;
-
-class function TEndoUtilities.MapPoint(const endomorphism: IECEndomorphism;
-  const p: IECPoint): IECPoint;
-var
-  c: IECCurve;
-  PreComp: IEndoPreCompInfo;
-begin
-  c := p.Curve;
-  PreComp := c.Precompute(p, PRECOMP_NAME, TEndoCallback.Create(endomorphism, p)
-    as IEndoCallback) as IEndoPreCompInfo;
-
-  Result := PreComp.MappedPoint;
-end;
-
-{ TEndoUtilities.TEndoCallback }
-
-class function TEndoUtilities.TEndoCallback.CheckExisting(const existingEndo
-  : IEndoPreCompInfo; const endomorphism: IECEndomorphism): Boolean;
-begin
-  Result := ((existingEndo <> Nil) and
-    (existingEndo.endomorphism = endomorphism) and
-    (existingEndo.MappedPoint <> Nil));
-end;
-
-constructor TEndoUtilities.TEndoCallback.Create(const endomorphism
-  : IECEndomorphism; const p: IECPoint);
-begin
-  Inherited Create();
-  Fendomorphism := endomorphism;
-  Fp := p;
-end;
-
-function TEndoUtilities.TEndoCallback.Precompute(const existing: IPreCompInfo)
-  : IPreCompInfo;
-var
-  existingEndo: IEndoPreCompInfo;
-  MappedPoint: IECPoint;
-  tempResult: IEndoPreCompInfo;
-begin
-
-  if Supports(existing, IEndoPreCompInfo) then
-  begin
-    existingEndo := existing as IEndoPreCompInfo;
-  end
-  else
-  begin
-    existingEndo := Nil;
-  end;
-
-  if (CheckExisting(existingEndo, Fendomorphism)) then
-  begin
-    Result := existingEndo;
-    Exit;
-  end;
-
-  MappedPoint := Fendomorphism.pointMap.Map(Fp);
-
-  tempResult := TEndoPreCompInfo.Create() as IEndoPreCompInfo;
-  tempResult.endomorphism := Fendomorphism;
-  tempResult.MappedPoint := MappedPoint;
-  Result := tempResult as IPreCompInfo;
-end;
-
-{ TFixedPointUtilities }
-
-class function TFixedPointUtilities.TFixedPointCallback.CheckTable
-  (const table: IECLookupTable; n: Int32): Boolean;
-begin
-  Result := (table <> Nil) and (table.Size >= n);
-end;
-
-class function TFixedPointUtilities.TFixedPointCallback.CheckExisting
-  (const existingFP: IFixedPointPreCompInfo; n: Int32): Boolean;
-begin
-  Result := (existingFP <> Nil) and CheckTable(existingFP.LookupTable, n);
-end;
-
-class function TFixedPointUtilities.GetCombSize(const c: IECCurve): Int32;
-var
-  Order: TBigInteger;
-begin
-  Order := c.Order;
-  if (not(Order.IsInitialized)) then
-  begin
-    Result := c.FieldSize + 1;
-  end
-  else
-  begin
-    Result := Order.BitLength;
-  end;
-end;
-
-class function TFixedPointUtilities.GetFixedPointPreCompInfo(const preCompInfo
-  : IPreCompInfo): IFixedPointPreCompInfo;
-begin
-  Result := preCompInfo as IFixedPointPreCompInfo;
-end;
-
-class function TFixedPointUtilities.Precompute(const p: IECPoint)
-  : IFixedPointPreCompInfo;
-var
-  c: IECCurve;
-begin
-  c := p.Curve;
-
-  Result := c.Precompute(p, PRECOMP_NAME, TFixedPointCallback.Create(p)
-    as IFixedPointCallback) as IFixedPointPreCompInfo;
-end;
-
-{ TFixedPointUtilities.TFixedPointCallback }
-
-constructor TFixedPointUtilities.TFixedPointCallback.Create(const p: IECPoint);
-begin
-  Inherited Create();
-  Fm_p := p;
-end;
-
-function TFixedPointUtilities.TFixedPointCallback.Precompute(const existing
-  : IPreCompInfo): IPreCompInfo;
-var
-  bit, bits, minWidth, n, d, i, step: Int32;
-  existingFP: IFixedPointPreCompInfo;
-  pow2Table, LookupTable: TCryptoLibGenericArray<IECPoint>;
-  pow2: IECPoint;
-  c: IECCurve;
-  tempResult: IFixedPointPreCompInfo;
-begin
-  if Supports(existing, IFixedPointPreCompInfo) then
-  begin
-    existingFP := existing as IFixedPointPreCompInfo;
-  end
-  else
-  begin
-    existingFP := Nil;
-  end;
-
-  c := Fm_p.Curve;
-  bits := TFixedPointUtilities.GetCombSize(c);
-  if bits > 250 then
-  begin
-    minWidth := 6
-  end
-  else
-  begin
-    minWidth := 5
-  end;
-  n := 1 shl minWidth;
-
-  if (CheckExisting(existingFP, n)) then
-  begin
-    Result := existingFP;
-    Exit;
-  end;
-
-  d := (bits + minWidth - 1) div minWidth;
-
-  System.SetLength(pow2Table, minWidth + 1);
-
-  pow2Table[0] := Fm_p;
-  for i := 1 to System.Pred(minWidth) do
-  begin
-    pow2Table[i] := pow2Table[i - 1].TimesPow2(d);
-  end;
-
-  // This will be the 'offset' value
-  pow2Table[minWidth] := pow2Table[0].Subtract(pow2Table[1]);
-
-  c.NormalizeAll(pow2Table);
-
-  System.SetLength(LookupTable, n);
-  LookupTable[0] := pow2Table[0];
-
-  bit := minWidth - 1;
-  while bit >= 0 do
-  begin
-    pow2 := pow2Table[bit];
-
-    step := 1 shl bit;
-
-    i := step;
-
-    while i < n do
-    begin
-      LookupTable[i] := LookupTable[i - step].Add(pow2);
-
-      System.Inc(i, step shl 1);
-    end;
-
-    System.Dec(bit);
-  end;
-
-  c.NormalizeAll(LookupTable);
-
-  tempResult := TFixedPointPreCompInfo.Create();
-  tempResult.LookupTable := c.CreateCacheSafeLookupTable(LookupTable, 0,
-    System.length(LookupTable));
-  tempResult.Offset := pow2Table[minWidth];
-  tempResult.width := minWidth;
-  Result := tempResult;
-end;
-
-end.

+ 3 - 12
CryptoLib/src/Interfaces/Math/EC/ClpIScaleXNegateYPointMap.pas → CryptoLib/src/Math/EC/ClpECCore.pas

@@ -14,23 +14,14 @@
 { * ******************************************************************************* * }
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+(*  Base curve implementation is in ClpECCurve. Use ClpECCurve for TECCurve.       *)
 
-unit ClpIScaleXNegateYPointMap;
+unit ClpECCore;
 
-{$I ..\..\..\Include\CryptoLib.inc}
+{$I ..\..\Include\CryptoLib.inc}
 
 interface
 
-uses
-  ClpIECC;
-
-type
-  IScaleXNegateYPointMap = interface(IECPointMap)
-
-    ['{D4FF6900-B627-45AB-8066-00E763213CE5}']
-
-  end;
-
 implementation
 
 end.

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

@@ -0,0 +1,1423 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ * ******************************************************************************* * }
+
+unit ClpECCurve;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  SyncObjs,
+  Generics.Collections,
+  ClpBigInteger,
+  ClpIFiniteField,
+  ClpIECCore,
+  ClpLongArray,
+  ClpIECFieldElement,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpISecureRandom,
+  ClpArrayUtilities,
+  ClpBitOperations,
+  ClpBigIntegers,
+  ClpECCurveConstants,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SMustBeNonNilAndOnThisCurve = 'must be non-null and on this curve';
+  SInvalidRangeSpecified = 'invalid range specified';
+  SEntriesMustBeNullOrOnThisCurve = 'entries must be null or on this curve';
+  SNoDefaultMultiplier = 'No default multiplier set for curve';
+  SIncorrectLengthForInfinityEncoding = 'Incorrect length for infinity encoding';
+  SIncorrectLengthForCompressedEncoding = 'Incorrect length for compressed encoding';
+  SIncorrectLengthForUncompressedEncoding = 'Incorrect length for uncompressed encoding';
+  SIncorrectLengthForHybridEncoding = 'Incorrect length for hybrid encoding';
+  SInvalidPointEncoding = 'Invalid point encoding %d';
+  SInvalidInfinityEncoding = 'Invalid infinity encoding';
+  SPointCompressionNotSupported = 'Point compression not supported';
+  SInvalidPointCoordinates = 'Invalid point coordinates';
+  SInconsistentYCoordinateInHybridEncoding = 'Inconsistent Y coordinate in hybrid encoding';
+  SUnsupportedCoordinateSystem = 'unsupported coordinate system';
+  SImplementationReturnedCurrentCurve = 'implementation returned current curve';
+
+type
+  TECCurve = class abstract(TInterfacedObject, IECCurve)
+  strict protected
+    FField: IFiniteField;
+    FA, FB: IECFieldElement;
+    FOrder, FCofactor: TBigInteger;
+    FCoord: Int32;
+    FMultiplier: IECMultiplier;
+    FEndomorphism: IECEndomorphism;
+    FPreCompTable: TDictionary<String, IPreCompInfo>;
+    FLock: TCriticalSection;
+    FTableLock: TCriticalSection;
+
+    function CreateDefaultMultiplier(): IECMultiplier; virtual;
+    procedure CheckPoint(const APoint: IECPoint); virtual;
+    procedure CheckPoints(const APoints: TCryptoLibGenericArray<IECPoint>); overload; virtual;
+    procedure CheckPoints(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32); overload; virtual;
+    function DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint; virtual;
+    function CloneCurve: TECCurve; virtual; abstract;
+  public
+    constructor Create(const AField: IFiniteField);
+    destructor Destroy; override;
+
+    class function GetAllCoordinateSystems: TCryptoLibInt32Array; static;
+
+    function GetFieldSize: Int32; virtual; abstract;
+    function GetFieldElementEncodingLength: Int32; virtual;
+    function GetInfinity: IECPoint; virtual; abstract;
+    function GetOrder: TBigInteger; virtual;
+    function GetCofactor: TBigInteger; virtual;
+    function GetCoordinateSystem: Int32; virtual;
+    function GetA: IECFieldElement; virtual;
+    function GetB: IECFieldElement; virtual;
+    function GetMultiplier: IECMultiplier; virtual;
+    function GetEndomorphism: IECEndomorphism; virtual;
+
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; virtual; abstract;
+    function IsValidFieldElement(const AX: TBigInteger): Boolean; virtual; abstract;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; virtual; abstract;
+    function CreatePoint(const AX, AY: TBigInteger): IECPoint; virtual;
+    function CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement): IECPoint; overload; virtual; abstract;
+    function CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement; const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; overload; virtual; abstract;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; virtual; abstract;
+
+    function GetAffinePointEncodingLength(ACompressed: Boolean): Int32; virtual;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32): IECLookupTable; virtual;
+    function GetPreCompInfo(const APoint: IECPoint; const AName: String): IPreCompInfo; virtual;
+    function Precompute(const APoint: IECPoint; const AName: String;
+      const ACallback: IPreCompCallback): IPreCompInfo; overload; virtual;
+    function Precompute(const AName: String; const ACallback: IPreCompCallback): IPreCompInfo; overload; virtual;
+
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; virtual;
+    procedure NormalizeAll(const APoints: TCryptoLibGenericArray<IECPoint>); overload; virtual;
+    procedure NormalizeAll(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32; const AIso: IECFieldElement); overload; virtual;
+    function ImportPoint(const AP: IECPoint): IECPoint; virtual;
+    function GetField: IFiniteField; virtual;
+    function DecodePoint(const AEncoded: TCryptoLibByteArray): IECPoint; virtual;
+    function ValidatePoint(const AX, AY: TBigInteger): IECPoint; virtual;
+    function Configure: IECCurveConfig; virtual;
+    procedure ApplyConfig(ACoord: Int32; const AEndomorphism: IECEndomorphism;
+      const AMultiplier: IECMultiplier); virtual;
+    function Equals(const AOther: IECCurve): Boolean; virtual;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+  end;
+
+  TECCurveConfig = class sealed(TInterfacedObject, IECCurveConfig)
+  strict private
+    FOuter: TECCurve;
+    FCoord: Int32;
+    FEndomorphism: IECEndomorphism;
+    FMultiplier: IECMultiplier;
+  public
+    constructor Create(const AOuter: TECCurve; ACoord: Int32;
+      const AEndomorphism: IECEndomorphism; const AMultiplier: IECMultiplier);
+    function SetCoordinateSystem(ACoord: Int32): IECCurveConfig;
+    function SetEndomorphism(const AEndomorphism: IECEndomorphism): IECCurveConfig;
+    function SetMultiplier(const AMultiplier: IECMultiplier): IECCurveConfig;
+    function CreateCurve: IECCurve;
+  end;
+
+  TAbstractFpCurve = class abstract(TECCurve, IECCurve, IAbstractFpCurve)
+  strict private
+    class var
+      FKnownPrimes: TDictionary<TBigInteger, Boolean>;
+      FLockPrimes: TCriticalSection;
+      FMaxFieldSize: Int32;
+      FCertainty: Int32;
+    class procedure ImplCheckQ(const AQ: TBigInteger); static;
+    class function ImplIsPrime(const AQ: TBigInteger): Boolean; static;
+    class function ImplGetIterations(ABits, ACertainty: Int32): Int32; static;
+  strict protected
+    class function ImplRandomFieldElement(const ARandom: ISecureRandom;
+      const AP: TBigInteger): TBigInteger; static;
+    class function ImplRandomFieldElementMult(const ARandom: ISecureRandom;
+      const AP: TBigInteger): TBigInteger; static;
+  public
+    class constructor Create;
+    class destructor Destroy;
+    constructor Create(const AQ: TBigInteger); overload;
+    constructor Create(const AQ: TBigInteger; AIsInternal: Boolean); overload;
+    function IsValidFieldElement(const AX: TBigInteger): Boolean; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint; override;
+    class property MaxFieldSize: Int32 read FMaxFieldSize write FMaxFieldSize;
+    class property Certainty: Int32 read FCertainty write FCertainty;
+  end;
+
+  TFpCurve = class sealed(TAbstractFpCurve, IECCurve, IFpCurve)
+  strict protected
+    FQ, FR: TBigInteger;
+    FInfinity: IECPoint;
+  public
+    const FP_DEFAULT_COORDS = TECCurveConstants.COORD_JACOBIAN_MODIFIED;
+    constructor Create(const AQ, AA, AB, AOrder, ACofactor: TBigInteger); overload;
+    constructor Create(const AQ, AA, AB, AOrder, ACofactor: TBigInteger;
+      AIsInternal: Boolean); overload;
+    constructor Create(const AQ, AR: TBigInteger; const AA, AB: IECFieldElement;
+      const AOrder, ACofactor: TBigInteger); overload;
+    function CloneCurve: TECCurve; override;
+    function GetFieldSize: Int32; override;
+    function ImportPoint(const AP: IECPoint): IECPoint; override;
+    function GetInfinity: IECPoint; override;
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement; const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; override;
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; override;
+    function GetQ: TBigInteger;
+    property Q: TBigInteger read GetQ;
+  end;
+
+  TAbstractF2mCurve = class abstract(TECCurve, IECCurve, IAbstractF2mCurve)
+  strict private
+    class var FMaxFieldSize: Int32;
+  strict protected
+    class function ImplRandomFieldElementMult(const ARandom: ISecureRandom; AM: Int32): TBigInteger; static;
+    function GetIsKoblitz: Boolean; virtual;
+  public
+    class constructor Create;
+    constructor Create(AM, AK1, AK2, AK3: Int32);
+    class function Inverse(AM: Int32; const AKs: TCryptoLibInt32Array; const AX: TBigInteger): TBigInteger; static;
+    function CreatePoint(const AX, AY: TBigInteger): IECPoint; override;
+    function IsValidFieldElement(const AX: TBigInteger): Boolean; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint; override;
+    function SolveQuadraticEquation(const ABeta: IECFieldElement): IECFieldElement; virtual;
+    class property MaxFieldSize: Int32 read FMaxFieldSize write FMaxFieldSize;
+  end;
+
+  TF2mCurve = class sealed(TAbstractF2mCurve, IECCurve, IF2mCurve)
+  strict protected
+    FM, FK1, FK2, FK3: Int32;
+    FKs: TCryptoLibInt32Array;
+    FInfinity: IECPoint;
+    function CreateDefaultMultiplier: IECMultiplier; override;
+  public
+    const F2M_DEFAULT_COORDS = TECCurveConstants.COORD_LAMBDA_PROJECTIVE;
+    constructor Create(AM, AK: Int32; const AA, AB, AOrder, ACofactor: TBigInteger); overload;
+    constructor Create(AM, AK1, AK2, AK3: Int32; const AA, AB, AOrder, ACofactor: TBigInteger); overload;
+    constructor Create(AM, AK1, AK2, AK3: Int32; const AA, AB: IECFieldElement;
+      const AOrder, ACofactor: TBigInteger); overload;
+    function CloneCurve: TECCurve; override;
+    function GetFieldSize: Int32; override;
+    function GetInfinity: IECPoint; override;
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement; const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; override;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>; AOff, ALen: Int32): IECLookupTable; override;
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; override;
+    function IsTrinomial: Boolean;
+    function GetM: Int32;
+    function GetK1: Int32;
+    function GetK2: Int32;
+    function GetK3: Int32;
+    property M: Int32 read GetM;
+    property K1: Int32 read GetK1;
+    property K2: Int32 read GetK2;
+    property K3: Int32 read GetK3;
+  end;
+
+implementation
+
+uses
+  ClpECPoint,
+  ClpECFieldElement,
+  ClpECAlgorithms,
+  ClpAbstractECLookupTable,
+  ClpFiniteFields,
+  ClpPrimes,
+  ClpSecureRandom,
+  ClpMultipliers;
+
+type
+  TDefaultLookupTable = class sealed(TAbstractECLookupTable)
+  strict private
+    FOuter: IECCurve;
+    FTable: TBytes;
+    FSize: Int32;
+    function CreatePoint(const AX, AY: TCryptoLibByteArray): IECPoint;
+  public
+    constructor Create(const AOuter: IECCurve; const ATable: TCryptoLibByteArray; ASize: Int32);
+    function GetSize: Int32; override;
+    function Lookup(AIndex: Int32): IECPoint; override;
+    function LookupVar(AIndex: Int32): IECPoint; override;
+  end;
+
+{ TDefaultLookupTable }
+
+constructor TDefaultLookupTable.Create(const AOuter: IECCurve; const ATable: TCryptoLibByteArray; ASize: Int32);
+begin
+  Inherited Create();
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
+end;
+
+function TDefaultLookupTable.GetSize: Int32;
+begin
+  Result := FSize;
+end;
+
+function TDefaultLookupTable.Lookup(AIndex: Int32): IECPoint;
+var
+  LFeBytes, LPos, I, J: Int32;
+  LMask: Byte;
+  LX, LY: TBytes;
+begin
+  LFeBytes := FOuter.GetFieldElementEncodingLength();
+  SetLength(LX, LFeBytes);
+  SetLength(LY, LFeBytes);
+  LPos := 0;
+  for I := 0 to FSize - 1 do
+  begin
+    LMask := Byte(TBitOperations.Asr32((I xor AIndex) - 1, 31));
+    for J := 0 to LFeBytes - 1 do
+    begin
+      LX[J] := Byte(LX[J] xor (FTable[LPos + J] and LMask));
+      LY[J] := Byte(LY[J] xor (FTable[LPos + LFeBytes + J] and LMask));
+    end;
+    Inc(LPos, LFeBytes * 2);
+  end;
+  Result := CreatePoint(LX, LY);
+end;
+
+function TDefaultLookupTable.LookupVar(AIndex: Int32): IECPoint;
+var
+  LFeBytes, LPos, J: Int32;
+  LX, LY: TBytes;
+begin
+  LFeBytes := FOuter.GetFieldElementEncodingLength();
+  SetLength(LX, LFeBytes);
+  SetLength(LY, LFeBytes);
+  LPos := AIndex * LFeBytes * 2;
+  for J := 0 to LFeBytes - 1 do
+  begin
+    LX[J] := FTable[LPos + J];
+    LY[J] := FTable[LPos + LFeBytes + J];
+  end;
+  Result := CreatePoint(LX, LY);
+end;
+
+function TDefaultLookupTable.CreatePoint(const AX, AY: TBytes): IECPoint;
+var
+  LX, LY: IECFieldElement;
+begin
+  LX := FOuter.FromBigInteger(TBigInteger.Create(1, AX));
+  LY := FOuter.FromBigInteger(TBigInteger.Create(1, AY));
+  Result := FOuter.CreateRawPoint(LX, LY);
+end;
+
+  TDefaultF2mLookupTable = class sealed(TAbstractECLookupTable)
+  strict private
+    FOuter: TF2mCurve;
+    FTable: TCryptoLibUInt64Array;
+    FSize: Int32;
+    function CreatePoint(const AX, AY: TCryptoLibUInt64Array): IECPoint;
+  public
+    constructor Create(const AOuter: TF2mCurve; const ATable: TCryptoLibUInt64Array; ASize: Int32);
+    function GetSize: Int32; override;
+    function Lookup(AIndex: Int32): IECPoint; override;
+    function LookupVar(AIndex: Int32): IECPoint; override;
+  end;
+
+{ TDefaultF2mLookupTable }
+
+constructor TDefaultF2mLookupTable.Create(const AOuter: TF2mCurve; const ATable: TCryptoLibUInt64Array; ASize: Int32);
+begin
+  Inherited Create();
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
+end;
+
+function TDefaultF2mLookupTable.GetSize: Int32;
+begin
+  Result := FSize;
+end;
+
+function TDefaultF2mLookupTable.Lookup(AIndex: Int32): IECPoint;
+var
+  LFeLongs, LPos, I, J: Int32;
+  LMask: UInt64;
+  LX, LY: TCryptoLibUInt64Array;
+begin
+  LFeLongs := (FOuter.FM + 63) div 64;
+  System.SetLength(LX, LFeLongs);
+  System.SetLength(LY, LFeLongs);
+  LPos := 0;
+
+  for I := 0 to FSize - 1 do
+  begin
+    LMask := UInt64(Int64(TBitOperations.Asr32((I xor AIndex) - 1, 31)));
+
+    for J := 0 to LFeLongs - 1 do
+    begin
+      LX[J] := LX[J] xor (FTable[LPos + J] and LMask);
+      LY[J] := LY[J] xor (FTable[LPos + LFeLongs + J] and LMask);
+    end;
+
+    Inc(LPos, LFeLongs * 2);
+  end;
+
+  Result := CreatePoint(LX, LY);
+end;
+
+function TDefaultF2mLookupTable.LookupVar(AIndex: Int32): IECPoint;
+var
+  LFeLongs, LPos, J: Int32;
+  LX, LY: TCryptoLibUInt64Array;
+begin
+  LFeLongs := (FOuter.FM + 63) div 64;
+  System.SetLength(LX, LFeLongs);
+  System.SetLength(LY, LFeLongs);
+  LPos := AIndex * LFeLongs * 2;
+
+  for J := 0 to LFeLongs - 1 do
+  begin
+    LX[J] := FTable[LPos + J];
+    LY[J] := FTable[LPos + LFeLongs + J];
+  end;
+
+  Result := CreatePoint(LX, LY);
+end;
+
+function TDefaultF2mLookupTable.CreatePoint(const AX, AY: TCryptoLibUInt64Array): IECPoint;
+var
+  LKs: TCryptoLibInt32Array;
+  LXfe, LYfe: IECFieldElement;
+begin
+  if FOuter.IsTrinomial then
+    LKs := TCryptoLibInt32Array.Create(FOuter.FK1)
+  else
+    LKs := TCryptoLibInt32Array.Create(FOuter.FK1, FOuter.FK2, FOuter.FK3);
+  LXfe := TF2mFieldElement.Create(FOuter.FM, LKs, TLongArray.Create(AX));
+  LYfe := TF2mFieldElement.Create(FOuter.FM, LKs, TLongArray.Create(AY));
+  Result := FOuter.CreateRawPoint(LXfe, LYfe);
+end;
+
+{ TECCurve }
+
+constructor TECCurve.Create(const AField: IFiniteField);
+begin
+  Inherited Create();
+  FField := AField;
+  FA := nil;
+  FB := nil;
+  FOrder := TBigInteger.GetDefault();
+  FCofactor := TBigInteger.GetDefault();
+  FCoord := TECCurveConstants.COORD_AFFINE;
+  FMultiplier := nil;
+  FEndomorphism := nil;
+  FPreCompTable := nil;
+  FLock := TCriticalSection.Create;
+  FTableLock := TCriticalSection.Create;
+end;
+
+destructor TECCurve.Destroy;
+begin
+  FPreCompTable.Free;
+  FTableLock.Free;
+  FLock.Free;
+  inherited;
+end;
+
+class function TECCurve.GetAllCoordinateSystems: TCryptoLibInt32Array;
+begin
+  Result := TECCurveConstants.GetAllCoordinateSystems();
+end;
+
+function TECCurve.CreateDefaultMultiplier: IECMultiplier;
+var
+  LGlv: IGlvEndomorphism;
+begin
+  if Supports(FEndomorphism, IGlvEndomorphism, LGlv) then
+    Result := TGlvMultiplier.Create(Self as IECCurve, LGlv) as IECMultiplier
+  else
+    Result := TWNafL2RMultiplier.Create() as IECMultiplier;
+end;
+
+procedure TECCurve.CheckPoint(const APoint: IECPoint);
+begin
+  if (APoint = nil) or (Self as IECCurve <> APoint.Curve) then
+    raise EArgumentCryptoLibException.CreateRes(@SMustBeNonNilAndOnThisCurve);
+end;
+
+procedure TECCurve.CheckPoints(const APoints: TCryptoLibGenericArray<IECPoint>);
+begin
+  CheckPoints(APoints, 0, System.Length(APoints));
+end;
+
+procedure TECCurve.CheckPoints(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32);
+var
+  I: Int32;
+  LPoint: IECPoint;
+begin
+  if APoints = nil then
+    raise EArgumentNilCryptoLibException.Create('points');
+  if (AOff < 0) or (ALen < 0) or (AOff > (System.Length(APoints) - ALen)) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidRangeSpecified);
+  for I := 0 to ALen - 1 do
+  begin
+    LPoint := APoints[AOff + I];
+    if (LPoint <> nil) and (Self as IECCurve <> LPoint.Curve) then
+      raise EArgumentCryptoLibException.CreateRes(@SEntriesMustBeNullOrOnThisCurve);
+  end;
+end;
+
+function TECCurve.GetFieldElementEncodingLength: Int32;
+begin
+  Result := (GetFieldSize() + 7) div 8;
+end;
+
+function TECCurve.GetOrder: TBigInteger;
+begin
+  Result := FOrder;
+end;
+
+function TECCurve.GetCofactor: TBigInteger;
+begin
+  Result := FCofactor;
+end;
+
+function TECCurve.GetCoordinateSystem: Int32;
+begin
+  Result := FCoord;
+end;
+
+function TECCurve.GetA: IECFieldElement;
+begin
+  Result := FA;
+end;
+
+function TECCurve.GetB: IECFieldElement;
+begin
+  Result := FB;
+end;
+
+function TECCurve.GetMultiplier: IECMultiplier;
+begin
+  if FMultiplier = nil then
+    FMultiplier := CreateDefaultMultiplier();
+  Result := FMultiplier;
+end;
+
+function TECCurve.CreatePoint(const AX, AY: TBigInteger): IECPoint;
+begin
+  Result := CreateRawPoint(FromBigInteger(AX), FromBigInteger(AY));
+end;
+
+function TECCurve.GetAffinePointEncodingLength(ACompressed: Boolean): Int32;
+var
+  LFieldLen: Int32;
+begin
+  LFieldLen := GetFieldElementEncodingLength();
+  if ACompressed then
+    Result := 1 + LFieldLen
+  else
+    Result := 1 + (LFieldLen * 2);
+end;
+
+function TECCurve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
+var
+  LFeBytes, LPos, I: Int32;
+  LTable: TBytes;
+  LP: IECPoint;
+begin
+  LFeBytes := GetFieldElementEncodingLength();
+  System.SetLength(LTable, ALen * LFeBytes * 2);
+  LPos := 0;
+  for I := 0 to System.Pred(ALen) do
+  begin
+    LP := APoints[AOff + I];
+    LP.RawXCoord.EncodeTo(LTable, LPos);
+    LPos := LPos + LFeBytes;
+    LP.RawYCoord.EncodeTo(LTable, LPos);
+    LPos := LPos + LFeBytes;
+  end;
+  Result := TDefaultLookupTable.Create(Self, LTable, ALen);
+end;
+
+function TECCurve.GetPreCompInfo(const APoint: IECPoint; const AName: String): IPreCompInfo;
+begin
+  CheckPoint(APoint);
+  Result := APoint.GetPreCompInfo(AName);
+end;
+
+function TECCurve.Precompute(const AName: String; const ACallback: IPreCompCallback): IPreCompInfo;
+var
+  LTable: TDictionary<String, IPreCompInfo>;
+  LExisting: IPreCompInfo;
+begin
+  FLock.Enter;
+  try
+    LTable := FPreCompTable;
+    if LTable = nil then
+    begin
+      LTable := TDictionary<String, IPreCompInfo>.Create();
+      FPreCompTable := LTable;
+    end;
+  finally
+    FLock.Leave;
+  end;
+
+  FTableLock.Enter;
+  try
+    if LTable.TryGetValue(AName, LExisting) then
+      { use existing }
+    else
+      LExisting := nil;
+    Result := ACallback.Precompute(LExisting);
+    if Result <> LExisting then
+      LTable.AddOrSetValue(AName, Result);
+  finally
+    FTableLock.Leave;
+  end;
+end;
+
+function TECCurve.GetEndomorphism: IECEndomorphism;
+begin
+  Result := FEndomorphism;
+end;
+
+function TECCurve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
+begin
+  Result := ACoord = TECCurveConstants.COORD_AFFINE;
+end;
+
+procedure TECCurve.NormalizeAll(const APoints: TCryptoLibGenericArray<IECPoint>);
+begin
+  NormalizeAll(APoints, 0, System.Length(APoints), nil);
+end;
+
+procedure TECCurve.NormalizeAll(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32; const AIso: IECFieldElement);
+var
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+  LIndices: TCryptoLibInt32Array;
+  LCount, I, LCoord: Int32;
+  LP: IECPoint;
+begin
+  CheckPoints(APoints, AOff, ALen);
+
+  LCoord := GetCoordinateSystem();
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
+      begin
+        if AIso <> nil then
+          raise EArgumentCryptoLibException.Create('not valid for affine coordinates');
+        Exit;
+      end;
+  end;
+
+  System.SetLength(LZs, ALen);
+  System.SetLength(LIndices, ALen);
+  LCount := 0;
+  for I := 0 to ALen - 1 do
+  begin
+    LP := APoints[AOff + I];
+    if (LP <> nil) and ((AIso <> nil) or not LP.IsNormalized) then
+    begin
+      LZs[LCount] := LP.GetZCoord(0);
+      LIndices[LCount] := AOff + I;
+      Inc(LCount);
+    end;
+  end;
+
+  if LCount = 0 then
+    Exit;
+
+  TECAlgorithms.MontgomeryTrick(LZs, 0, LCount, AIso);
+
+  for I := 0 to LCount - 1 do
+    APoints[LIndices[I]] := APoints[LIndices[I]].Normalize(LZs[I]);
+end;
+
+function TECCurve.ImportPoint(const AP: IECPoint): IECPoint;
+var
+  LP: IECPoint;
+begin
+  if (Self as IECCurve) = AP.Curve then
+    Exit(AP);
+  if AP.IsInfinity then
+    Exit(GetInfinity());
+  LP := AP.Normalize();
+  Result := CreatePoint(LP.XCoord.ToBigInteger(), LP.YCoord.ToBigInteger());
+end;
+
+function TECCurve.Precompute(const APoint: IECPoint; const AName: String;
+  const ACallback: IPreCompCallback): IPreCompInfo;
+begin
+  CheckPoint(APoint);
+  Result := APoint.Precompute(AName, ACallback);
+end;
+
+function TECCurve.GetField: IFiniteField;
+begin
+  Result := FField;
+end;
+
+function TECCurve.DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint;
+begin
+  raise EArgumentCryptoLibException.Create(SPointCompressionNotSupported);
+end;
+
+function TECCurve.ValidatePoint(const AX, AY: TBigInteger): IECPoint;
+var
+  LP: IECPoint;
+begin
+  LP := CreatePoint(AX, AY);
+  if not LP.IsValid() then
+    raise EArgumentCryptoLibException.Create(SInvalidPointCoordinates);
+  Result := LP;
+end;
+
+function TECCurve.Configure: IECCurveConfig;
+begin
+  Result := TECCurveConfig.Create(Self, FCoord, FEndomorphism, FMultiplier);
+end;
+
+procedure TECCurve.ApplyConfig(ACoord: Int32; const AEndomorphism: IECEndomorphism;
+  const AMultiplier: IECMultiplier);
+begin
+  FCoord := ACoord;
+  FEndomorphism := AEndomorphism;
+  FMultiplier := AMultiplier;
+end;
+
+{ TECCurveConfig }
+
+constructor TECCurveConfig.Create(const AOuter: TECCurve; ACoord: Int32;
+  const AEndomorphism: IECEndomorphism; const AMultiplier: IECMultiplier);
+begin
+  inherited Create();
+  FOuter := AOuter;
+  FCoord := ACoord;
+  FEndomorphism := AEndomorphism;
+  FMultiplier := AMultiplier;
+end;
+
+function TECCurveConfig.SetCoordinateSystem(ACoord: Int32): IECCurveConfig;
+begin
+  FCoord := ACoord;
+  Result := Self;
+end;
+
+function TECCurveConfig.SetEndomorphism(const AEndomorphism: IECEndomorphism): IECCurveConfig;
+begin
+  FEndomorphism := AEndomorphism;
+  Result := Self;
+end;
+
+function TECCurveConfig.SetMultiplier(const AMultiplier: IECMultiplier): IECCurveConfig;
+begin
+  FMultiplier := AMultiplier;
+  Result := Self;
+end;
+
+function TECCurveConfig.CreateCurve: IECCurve;
+var
+  LClone: TECCurve;
+begin
+  if not FOuter.SupportsCoordinateSystem(FCoord) then
+    raise EInvalidOperationCryptoLibException.Create(SUnsupportedCoordinateSystem);
+  LClone := FOuter.CloneCurve();
+  if LClone = FOuter then
+    raise EInvalidOperationCryptoLibException.Create(SImplementationReturnedCurrentCurve);
+  LClone.ApplyConfig(FCoord, FEndomorphism, FMultiplier);
+  Result := LClone;
+end;
+
+function TECCurve.DecodePoint(const AEncoded: TCryptoLibByteArray): IECPoint;
+var
+  LExpectedLength: Int32;
+  LType: Byte;
+  LYTilde: Int32;
+  LX, LY: TBigInteger;
+  LP: IECPoint;
+begin
+  if (AEncoded = nil) or (System.Length(AEncoded) < 1) then
+    raise EArgumentCryptoLibException.CreateResFmt(@SInvalidPointEncoding, [0]);
+
+  LExpectedLength := GetFieldElementEncodingLength();
+  LType := AEncoded[0];
+
+  case LType of
+    $00: // infinity
+      begin
+        if System.Length(AEncoded) <> 1 then
+          raise EArgumentCryptoLibException.Create(SIncorrectLengthForInfinityEncoding);
+        LP := GetInfinity();
+      end;
+    $02, $03: // compressed
+      begin
+        if System.Length(AEncoded) <> (LExpectedLength + 1) then
+          raise EArgumentCryptoLibException.Create(SIncorrectLengthForCompressedEncoding);
+        LYTilde := LType and 1;
+        LX := TBigInteger.Create(1, AEncoded, 1, LExpectedLength);
+        LP := DecompressPoint(LYTilde, LX);
+        if not LP.ImplIsValid(True, True) then
+          raise EArgumentCryptoLibException.Create(SInvalidPointCoordinates);
+      end;
+    $04: // uncompressed
+      begin
+        if System.Length(AEncoded) <> (2 * LExpectedLength + 1) then
+          raise EArgumentCryptoLibException.Create(SIncorrectLengthForUncompressedEncoding);
+        LX := TBigInteger.Create(1, AEncoded, 1, LExpectedLength);
+        LY := TBigInteger.Create(1, AEncoded, 1 + LExpectedLength, LExpectedLength);
+        LP := ValidatePoint(LX, LY);
+      end;
+    $06, $07: // hybrid
+      begin
+        if System.Length(AEncoded) <> (2 * LExpectedLength + 1) then
+          raise EArgumentCryptoLibException.Create(SIncorrectLengthForHybridEncoding);
+        LX := TBigInteger.Create(1, AEncoded, 1, LExpectedLength);
+        LY := TBigInteger.Create(1, AEncoded, 1 + LExpectedLength, LExpectedLength);
+        if LY.TestBit(0) <> (LType = $07) then
+          raise EArgumentCryptoLibException.Create(SInconsistentYCoordinateInHybridEncoding);
+        LP := ValidatePoint(LX, LY);
+      end;
+  else
+    raise EFormatCryptoLibException.CreateResFmt(@SInvalidPointEncoding, [LType]);
+  end;
+
+  if (LType <> $00) and LP.IsInfinity then
+    raise EArgumentCryptoLibException.Create(SInvalidInfinityEncoding);
+
+  Result := LP;
+end;
+
+function TECCurve.Equals(const AOther: IECCurve): Boolean;
+var
+  LA, LB: TBigInteger;
+begin
+  if AOther = nil then
+    Exit(False);
+  if (Self as IECCurve) = AOther then
+    Exit(True);
+  if not FField.Equals(AOther.Field) then
+    Exit(False);
+  LA := FA.ToBigInteger();
+  LB := AOther.A.ToBigInteger();
+  if not LA.Equals(LB) then
+    Exit(False);
+  LA := FB.ToBigInteger();
+  LB := AOther.B.ToBigInteger();
+  Result := LA.Equals(LB);
+end;
+
+function TECCurve.GetHashCode: {$IFDEF DELPHI}Int32{$ELSE}PtrInt{$ENDIF};
+var
+  LHa, LHb: Int32;
+begin
+  Result := FField.GetHashCode();
+  LHa := FA.ToBigInteger().GetHashCode();
+  Result := Result xor Int32(TBitOperations.RotateLeft32(UInt32(LHa), 8));
+  LHb := FB.ToBigInteger().GetHashCode();
+  Result := Result xor Int32(TBitOperations.RotateLeft32(UInt32(LHb), 16));
+end;
+
+{ TAbstractFpCurve }
+
+class constructor TAbstractFpCurve.Create;
+begin
+  FKnownPrimes := TDictionary<TBigInteger, Boolean>.Create(TBigIntegers.BigIntegerEqualityComparer);
+  FLockPrimes := TCriticalSection.Create;
+  FMaxFieldSize := 1042; // 2 * 521
+  FCertainty := 100;
+end;
+
+class destructor TAbstractFpCurve.Destroy;
+begin
+  FLockPrimes.Free;
+  FKnownPrimes.Free;
+end;
+
+constructor TAbstractFpCurve.Create(const AQ: TBigInteger);
+begin
+  Create(AQ, False);
+end;
+
+constructor TAbstractFpCurve.Create(const AQ: TBigInteger; AIsInternal: Boolean);
+var
+  LFound: Boolean;
+begin
+  inherited Create(TFiniteFields.GetPrimeField(AQ));
+  FLockPrimes.Enter;
+  try
+    if AIsInternal then
+    begin
+      FKnownPrimes.AddOrSetValue(AQ, True);
+    end
+    else
+    begin
+      LFound := FKnownPrimes.ContainsKey(AQ);
+      if not LFound then
+      begin
+        ImplCheckQ(AQ);
+        FKnownPrimes.Add(AQ, False);
+      end;
+    end;
+  finally
+    FLockPrimes.Leave;
+  end;
+end;
+
+class procedure TAbstractFpCurve.ImplCheckQ(const AQ: TBigInteger);
+begin
+  if AQ.BitLength > FMaxFieldSize then
+    raise EArgumentCryptoLibException.Create('Fp q value out of range');
+  if not ImplIsPrime(AQ) then
+    raise EArgumentCryptoLibException.Create('Fp q value not prime');
+end;
+
+class function TAbstractFpCurve.ImplIsPrime(const AQ: TBigInteger): Boolean;
+var
+  LIterations: Int32;
+begin
+  if TPrimes.HasAnySmallFactors(AQ) then
+    Exit(False);
+  LIterations := ImplGetIterations(AQ.BitLength, FCertainty);
+  Result := TPrimes.IsMRProbablePrime(AQ, TSecureRandom.MasterRandom, LIterations);
+end;
+
+class function TAbstractFpCurve.ImplGetIterations(ABits, ACertainty: Int32): Int32;
+begin
+  if ABits >= 1536 then
+  begin
+    if ACertainty <= 100 then Exit(3)
+    else if ACertainty <= 128 then Exit(4)
+    else Exit(4 + (ACertainty - 128 + 1) div 2);
+  end
+  else if ABits >= 1024 then
+  begin
+    if ACertainty <= 100 then Exit(4)
+    else if ACertainty <= 112 then Exit(5)
+    else Exit(5 + (ACertainty - 112 + 1) div 2);
+  end
+  else if ABits >= 512 then
+  begin
+    if ACertainty <= 80 then Exit(5)
+    else if ACertainty <= 100 then Exit(7)
+    else Exit(7 + (ACertainty - 100 + 1) div 2);
+  end
+  else
+  begin
+    if ACertainty <= 80 then Exit(40)
+    else Exit(40 + (ACertainty - 80 + 1) div 2);
+  end;
+end;
+
+class function TAbstractFpCurve.ImplRandomFieldElement(const ARandom: ISecureRandom;
+  const AP: TBigInteger): TBigInteger;
+var
+  LX: TBigInteger;
+begin
+  repeat
+    LX := TBigIntegers.CreateRandomBigInteger(AP.BitLength, ARandom);
+  until LX.CompareTo(AP) < 0;
+  Result := LX;
+end;
+
+class function TAbstractFpCurve.ImplRandomFieldElementMult(const ARandom: ISecureRandom;
+  const AP: TBigInteger): TBigInteger;
+var
+  LX: TBigInteger;
+begin
+  repeat
+    LX := TBigIntegers.CreateRandomBigInteger(AP.BitLength, ARandom);
+  until (LX.SignValue > 0) and (LX.CompareTo(AP) < 0);
+  Result := LX;
+end;
+
+function TAbstractFpCurve.IsValidFieldElement(const AX: TBigInteger): Boolean;
+var
+  LP: TBigInteger;
+begin
+  if (AX = nil) or (AX.SignValue < 0) then
+    Exit(False);
+  LP := FField.Characteristic;
+  Result := AX.CompareTo(LP) < 0;
+end;
+
+function TAbstractFpCurve.RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LP: TBigInteger;
+  LFe1, LFe2: IECFieldElement;
+begin
+  LP := FField.Characteristic;
+  LFe1 := FromBigInteger(ImplRandomFieldElement(ARandom, LP));
+  LFe2 := FromBigInteger(ImplRandomFieldElement(ARandom, LP));
+  Result := LFe1.Multiply(LFe2);
+end;
+
+function TAbstractFpCurve.RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LP: TBigInteger;
+  LFe1, LFe2: IECFieldElement;
+begin
+  LP := FField.Characteristic;
+  LFe1 := FromBigInteger(ImplRandomFieldElementMult(ARandom, LP));
+  LFe2 := FromBigInteger(ImplRandomFieldElementMult(ARandom, LP));
+  Result := LFe1.Multiply(LFe2);
+end;
+
+function TAbstractFpCurve.DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint;
+var
+  LX, LRhs, LY: IECFieldElement;
+begin
+  LX := FromBigInteger(AX1);
+  LRhs := LX.Square().Add(FA).Multiply(LX).Add(FB);
+  LY := LRhs.Sqrt();
+  if LY = nil then
+    raise EArgumentCryptoLibException.Create(SInvalidPointCoordinates);
+  if LY.TestBitZero <> (AYTilde = 1) then
+    LY := LY.Negate();
+  Result := CreateRawPoint(LX, LY);
+end;
+
+{ TFpCurve }
+
+constructor TFpCurve.Create(const AQ, AA, AB, AOrder, ACofactor: TBigInteger);
+begin
+  Create(AQ, AA, AB, AOrder, ACofactor, False);
+end;
+
+constructor TFpCurve.Create(const AQ, AA, AB, AOrder, ACofactor: TBigInteger;
+  AIsInternal: Boolean);
+begin
+  inherited Create(AQ, AIsInternal);
+  FQ := AQ;
+  FR := TFpFieldElement.CalculateResidue(AQ);
+  FInfinity := TFpPoint.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(AA);
+  FB := FromBigInteger(AB);
+  FOrder := AOrder;
+  FCofactor := ACofactor;
+  FCoord := FP_DEFAULT_COORDS;
+end;
+
+constructor TFpCurve.Create(const AQ, AR: TBigInteger; const AA, AB: IECFieldElement;
+  const AOrder, ACofactor: TBigInteger);
+begin
+  inherited Create(AQ, True);
+  FQ := AQ;
+  FR := AR;
+  FInfinity := TFpPoint.Create(Self as IECCurve, nil, nil);
+  FA := AA;
+  FB := AB;
+  FOrder := AOrder;
+  FCofactor := ACofactor;
+  FCoord := FP_DEFAULT_COORDS;
+end;
+
+function TFpCurve.CloneCurve: TECCurve;
+begin
+  Result := TFpCurve.Create(FQ, FR, FA, FB, FOrder, FCofactor);
+end;
+
+function TFpCurve.ImportPoint(const AP: IECPoint): IECPoint;
+begin
+  if ((Self as IECCurve) <> AP.Curve) and (GetCoordinateSystem() = TECCurveConstants.COORD_JACOBIAN)
+    and (not AP.IsInfinity) then
+  begin
+    case AP.Curve.CoordinateSystem of
+      TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY, TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+        begin
+          Result := TFpPoint.Create(Self as IECCurve,
+            FromBigInteger(AP.RawXCoord.ToBigInteger()),
+            FromBigInteger(AP.RawYCoord.ToBigInteger()),
+            TCryptoLibGenericArray<IECFieldElement>.Create(
+              FromBigInteger(AP.GetZCoord(0).ToBigInteger())));
+          Exit;
+        end;
+    else
+      ;
+    end;
+  end;
+  Result := inherited ImportPoint(AP);
+end;
+
+function TFpCurve.GetFieldSize: Int32;
+begin
+  Result := FQ.BitLength;
+end;
+
+function TFpCurve.GetInfinity: IECPoint;
+begin
+  Result := FInfinity;
+end;
+
+function TFpCurve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
+begin
+  if (AX = nil) or (AX.SignValue < 0) or (AX.CompareTo(FQ) >= 0) then
+    raise EArgumentCryptoLibException.Create('value invalid for Fp field element');
+  Result := TFpFieldElement.Create(FQ, FR, AX);
+end;
+
+function TFpCurve.CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement): IECPoint;
+begin
+  Result := TFpPoint.Create(Self as IECCurve, AX, AY);
+end;
+
+function TFpCurve.CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement; const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
+begin
+  Result := TFpPoint.Create(Self as IECCurve, AX, AY, AZs);
+end;
+
+function TFpCurve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
+begin
+  case ACoord of
+    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_HOMOGENEOUS, TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+      Result := True;
+  else
+    Result := False;
+  end;
+end;
+
+function TFpCurve.GetQ: TBigInteger;
+begin
+  Result := FQ;
+end;
+
+{ TAbstractF2mCurve }
+
+class constructor TAbstractF2mCurve.Create;
+begin
+  FMaxFieldSize := 1142; // 2 * 571
+end;
+
+function BuildF2mField(AM, AK1, AK2, AK3: Int32): IFiniteField;
+var
+  LExponents: TCryptoLibInt32Array;
+begin
+  if AM > TAbstractF2mCurve.MaxFieldSize then
+    raise EArgumentCryptoLibException.Create('F2m m value out of range');
+  if (AK2 or AK3) = 0 then
+    LExponents := TCryptoLibInt32Array.Create(0, AK1, AM)
+  else
+    LExponents := TCryptoLibInt32Array.Create(0, AK1, AK2, AK3, AM);
+  Result := TFiniteFields.GetBinaryExtensionField(LExponents);
+end;
+
+constructor TAbstractF2mCurve.Create(AM, AK1, AK2, AK3: Int32);
+begin
+  inherited Create(BuildF2mField(AM, AK1, AK2, AK3));
+end;
+
+class function TAbstractF2mCurve.ImplRandomFieldElementMult(const ARandom: ISecureRandom; AM: Int32): TBigInteger;
+var
+  LX: TBigInteger;
+begin
+  repeat
+    LX := TBigIntegers.CreateRandomBigInteger(AM, ARandom);
+  until LX.SignValue > 0;
+  Result := LX;
+end;
+
+function TAbstractF2mCurve.CreatePoint(const AX, AY: TBigInteger): IECPoint;
+var
+  LX, LY: IECFieldElement;
+begin
+  LX := FromBigInteger(AX);
+  LY := FromBigInteger(AY);
+
+  case GetCoordinateSystem() of
+    TECCurveConstants.COORD_LAMBDA_AFFINE,
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      if LX.GetIsZero then
+      begin
+        if not LY.Square().Equals(FB) then
+          raise EArgumentCryptoLibException.Create('');
+      end
+      else
+      begin
+        // Y becomes Lambda (X + Y/X) here
+        LY := LY.Divide(LX).Add(LX);
+      end;
+    end;
+  end;
+
+  Result := CreateRawPoint(LX, LY);
+end;
+
+function TAbstractF2mCurve.IsValidFieldElement(const AX: TBigInteger): Boolean;
+begin
+  Result := (AX <> nil) and (AX.SignValue >= 0) and (AX.BitLength <= GetFieldSize());
+end;
+
+function TAbstractF2mCurve.RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+begin
+  Result := FromBigInteger(TBigIntegers.CreateRandomBigInteger(GetFieldSize(), ARandom));
+end;
+
+function TAbstractF2mCurve.RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LFe1, LFe2: IECFieldElement;
+begin
+  LFe1 := FromBigInteger(ImplRandomFieldElementMult(ARandom, GetFieldSize()));
+  LFe2 := FromBigInteger(ImplRandomFieldElementMult(ARandom, GetFieldSize()));
+  Result := LFe1.Multiply(LFe2);
+end;
+
+function TAbstractF2mCurve.DecompressPoint(AYTilde: Int32; const AX1: TBigInteger): IECPoint;
+var
+  LXp, LYp, LBeta, LZ: IECFieldElement;
+begin
+  LXp := FromBigInteger(AX1);
+  LYp := nil;
+  if LXp.GetIsZero then
+  begin
+    LYp := FB.Sqrt();
+  end
+  else
+  begin
+    LBeta := LXp.Square().Invert().Multiply(FB).Add(FA).Add(LXp);
+    LZ := SolveQuadraticEquation(LBeta);
+
+    if LZ <> nil then
+    begin
+      if LZ.TestBitZero <> (AYTilde = 1) then
+        LZ := LZ.AddOne();
+
+      case GetCoordinateSystem() of
+        TECCurveConstants.COORD_LAMBDA_AFFINE,
+        TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+          LYp := LZ.Add(LXp);
+      else
+        LYp := LZ.Multiply(LXp);
+      end;
+    end;
+  end;
+
+  if LYp = nil then
+    raise EArgumentCryptoLibException.Create(SInvalidPointCoordinates);
+
+  Result := CreateRawPoint(LXp, LYp);
+end;
+
+function TAbstractF2mCurve.SolveQuadraticEquation(const ABeta: IECFieldElement): IECFieldElement;
+var
+  LBetaF2m: IAbstractF2mFieldElement;
+  LFastTrace: Boolean;
+  LM, LI: Int32;
+  LR, LZeroElement, LT, LZ, LW, LW2, LGamma: IECFieldElement;
+begin
+  if not Supports(ABeta, IAbstractF2mFieldElement, LBetaF2m) then
+    raise EInvalidCastCryptoLibException.Create('Expected AbstractF2mFieldElement');
+
+  LFastTrace := LBetaF2m.HasFastTrace;
+  if LFastTrace and (0 <> LBetaF2m.Trace) then
+    Exit(nil);
+
+  LM := GetFieldSize();
+
+  // For odd m, use the half-trace
+  if (LM and 1) <> 0 then
+  begin
+    LR := LBetaF2m.HalfTrace();
+    if LFastTrace or LR.Square().Add(LR).Add(ABeta).GetIsZero then
+      Exit(LR);
+
+    Exit(nil);
+  end;
+
+  if ABeta.GetIsZero then
+    Exit(ABeta);
+
+  LZeroElement := FromBigInteger(TBigInteger.Zero);
+
+  repeat
+    LT := FromBigInteger(TBigInteger.Arbitrary(LM));
+    LZ := LZeroElement;
+    LW := ABeta;
+    for LI := 1 to LM - 1 do
+    begin
+      LW2 := LW.Square();
+      LZ := LZ.Square().Add(LW2.Multiply(LT));
+      LW := LW2.Add(ABeta);
+    end;
+    if not LW.GetIsZero then
+      Exit(nil);
+    LGamma := LZ.Square().Add(LZ);
+  until not LGamma.GetIsZero;
+
+  Result := LZ;
+end;
+
+class function TAbstractF2mCurve.Inverse(AM: Int32; const AKs: TCryptoLibInt32Array; const AX: TBigInteger): TBigInteger;
+begin
+  Result := TLongArray.Create(AX).ModInverse(AM, AKs).ToBigInteger();
+end;
+
+function TAbstractF2mCurve.GetIsKoblitz: Boolean;
+begin
+  Result := (FOrder <> nil) and (FCofactor <> nil) and FB.IsOne
+    and (FA.GetIsZero or FA.IsOne);
+end;
+
+{ TF2mCurve }
+
+constructor TF2mCurve.Create(AM, AK: Int32; const AA, AB, AOrder, ACofactor: TBigInteger);
+begin
+  Create(AM, AK, 0, 0, AA, AB, AOrder, ACofactor);
+end;
+
+constructor TF2mCurve.Create(AM, AK1, AK2, AK3: Int32; const AA, AB, AOrder, ACofactor: TBigInteger);
+begin
+  inherited Create(AM, AK1, AK2, AK3);
+  FM := AM;
+  FK1 := AK1;
+  FK2 := AK2;
+  FK3 := AK3;
+  if (AK2 or AK3) = 0 then
+    FKs := TCryptoLibInt32Array.Create(AK1)
+  else
+    FKs := TCryptoLibInt32Array.Create(AK1, AK2, AK3);
+  FOrder := AOrder;
+  FCofactor := ACofactor;
+  FInfinity := TF2mPoint.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(AA);
+  FB := FromBigInteger(AB);
+  FCoord := F2M_DEFAULT_COORDS;
+end;
+
+constructor TF2mCurve.Create(AM, AK1, AK2, AK3: Int32; const AA, AB: IECFieldElement;
+  const AOrder, ACofactor: TBigInteger);
+begin
+  inherited Create(AM, AK1, AK2, AK3);
+  FM := AM;
+  FK1 := AK1;
+  FK2 := AK2;
+  FK3 := AK3;
+  if (AK2 or AK3) = 0 then
+    FKs := TCryptoLibInt32Array.Create(AK1)
+  else
+    FKs := TCryptoLibInt32Array.Create(AK1, AK2, AK3);
+  FOrder := AOrder;
+  FCofactor := ACofactor;
+  FInfinity := TF2mPoint.Create(Self as IECCurve, nil, nil);
+  FA := AA;
+  FB := AB;
+  FCoord := F2M_DEFAULT_COORDS;
+end;
+
+function TF2mCurve.CloneCurve: TECCurve;
+begin
+  Result := TF2mCurve.Create(FM, FK1, FK2, FK3, FA, FB, FOrder, FCofactor);
+end;
+
+function TF2mCurve.GetFieldSize: Int32;
+begin
+  Result := FM;
+end;
+
+function TF2mCurve.GetInfinity: IECPoint;
+begin
+  Result := FInfinity;
+end;
+
+function TF2mCurve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
+var
+  LX: TLongArray;
+begin
+  if (AX = nil) or (AX.SignValue < 0) or (AX.BitLength > FM) then
+    raise EArgumentCryptoLibException.Create('value invalid for F2m field element');
+
+  LX := TLongArray.Create(AX);
+  Result := TF2mFieldElement.Create(FM, FKs, LX);
+end;
+
+function TF2mCurve.CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement): IECPoint;
+begin
+  Result := TF2mPoint.Create(Self as IECCurve, AX, AY);
+end;
+
+function TF2mCurve.CreateRawPoint(const AX: IECFieldElement; const AY: IECFieldElement; const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
+begin
+  Result := TF2mPoint.Create(Self as IECCurve, AX, AY, AZs);
+end;
+
+function TF2mCurve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
+begin
+  case ACoord of
+    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_HOMOGENEOUS, TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+      Result := True;
+  else
+    Result := False;
+  end;
+end;
+
+function TF2mCurve.CreateDefaultMultiplier: IECMultiplier;
+begin
+  if GetIsKoblitz then
+    Result := TWTauNafMultiplier.Create()
+  else
+    Result := inherited CreateDefaultMultiplier();
+end;
+
+function TF2mCurve.IsTrinomial: Boolean;
+begin
+  Result := (FK2 = 0) and (FK3 = 0);
+end;
+
+function TF2mCurve.GetM: Int32;
+begin
+  Result := FM;
+end;
+
+function TF2mCurve.GetK1: Int32;
+begin
+  Result := FK1;
+end;
+
+function TF2mCurve.GetK2: Int32;
+begin
+  Result := FK2;
+end;
+
+function TF2mCurve.GetK3: Int32;
+begin
+  Result := FK3;
+end;
+
+function TF2mCurve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
+var
+  LFeLongs, LPos, I: Int32;
+  LTable: TCryptoLibUInt64Array;
+  LP: IECPoint;
+begin
+  LFeLongs := (FM + 63) div 64;
+  System.SetLength(LTable, ALen * LFeLongs * 2);
+  LPos := 0;
+  for I := 0 to ALen - 1 do
+  begin
+    LP := APoints[AOff + I];
+    (LP.GetRawXCoord as IF2mFieldElement).X.CopyTo(LTable, LPos);
+    Inc(LPos, LFeLongs);
+    (LP.GetRawYCoord as IF2mFieldElement).X.CopyTo(LTable, LPos);
+    Inc(LPos, LFeLongs);
+  end;
+  Result := TDefaultF2mLookupTable.Create(Self, LTable, ALen);
+end;
+
+end.

+ 20 - 19
CryptoLib/src/Math/EC/ClpECCurveConstants.pas

@@ -6,38 +6,39 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpECCurveConstants;
 
 {$I ..\..\Include\CryptoLib.inc}
 
 interface
 
+uses
+  ClpCryptoLibTypes;
+
 type
   TECCurveConstants = class sealed(TObject)
-
   public
-
-    const
-    COORD_AFFINE = Int32(0);
-    COORD_HOMOGENEOUS = Int32(1);
-    COORD_JACOBIAN = Int32(2);
-    COORD_JACOBIAN_CHUDNOVSKY = Int32(3);
-    COORD_JACOBIAN_MODIFIED = Int32(4);
-    COORD_LAMBDA_AFFINE = Int32(5);
-    COORD_LAMBDA_PROJECTIVE = Int32(6);
-    COORD_SKEWED = Int32(7);
-
+    const COORD_AFFINE = 0;
+    const COORD_HOMOGENEOUS = 1;
+    const COORD_JACOBIAN = 2;
+    const COORD_JACOBIAN_CHUDNOVSKY = 3;
+    const COORD_JACOBIAN_MODIFIED = 4;
+    const COORD_LAMBDA_AFFINE = 5;
+    const COORD_LAMBDA_PROJECTIVE = 6;
+    const COORD_SKEWED = 7;
+
+    class function GetAllCoordinateSystems: TCryptoLibInt32Array; static;
   end;
 
 implementation
 
+class function TECCurveConstants.GetAllCoordinateSystems: TCryptoLibInt32Array;
+begin
+  Result := TCryptoLibInt32Array.Create(COORD_AFFINE, COORD_HOMOGENEOUS,
+    COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY, COORD_JACOBIAN_MODIFIED,
+    COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED);
+end;
+
 end.

+ 971 - 0
CryptoLib/src/Math/EC/ClpECFieldElement.pas

@@ -0,0 +1,971 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+unit ClpECFieldElement;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpIECFieldElement,
+  ClpLongArray,
+  ClpBitOperations,
+  ClpArrayUtilities,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SF2mFieldElementsNotBothInstances = 'Field elements are not both instances of F2mFieldElement';
+  SF2mFieldElementIncorrectRepresentation = 'One of the F2m field elements has incorrect representation';
+  SF2mFieldElementsNotSameField = 'Field elements are not elements of the same field F2m';
+  SHalfTraceOnlyDefinedForOddM = 'Half-trace only defined for odd m';
+  SInternalErrorInTraceCalculation = 'Internal error in trace calculation';
+
+type
+  TECFieldElement = class abstract(TInterfacedObject, IECFieldElement)
+  public
+    function GetBitLength: Int32; virtual;
+    function GetIsOne: Boolean; virtual;
+    function GetIsZero: Boolean; virtual;
+
+    function GetFieldName: String; virtual; abstract;
+    function GetFieldSize: Int32; virtual; abstract;
+    function ToBigInteger: TBigInteger; virtual; abstract;
+    function Add(const AB: IECFieldElement): IECFieldElement; virtual; abstract;
+    function AddOne: IECFieldElement; virtual; abstract;
+    function Subtract(const AB: IECFieldElement): IECFieldElement; virtual; abstract;
+    function Multiply(const AB: IECFieldElement): IECFieldElement; virtual; abstract;
+    function Divide(const AB: IECFieldElement): IECFieldElement; virtual; abstract;
+    function Negate: IECFieldElement; virtual; abstract;
+    function Square: IECFieldElement; virtual; abstract;
+    function Invert: IECFieldElement; virtual; abstract;
+    function Sqrt: IECFieldElement; virtual; abstract;
+
+    function MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement; virtual;
+    function MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement; virtual;
+    function SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement; virtual;
+    function SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement; virtual;
+    function SquarePow(APow: Int32): IECFieldElement; virtual;
+    function TestBitZero: Boolean; virtual;
+
+    function Equals(const AOther: IECFieldElement): Boolean; virtual;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+    function ToString: String; override;
+    function GetEncoded: TCryptoLibByteArray; virtual;
+    function GetEncodedLength: Int32; virtual;
+    procedure EncodeTo(var ABuf: TCryptoLibByteArray; AOff: Int32); virtual;
+
+    property BitLength: Int32 read GetBitLength;
+    property IsOne: Boolean read GetIsOne;
+    property IsZero: Boolean read GetIsZero;
+  end;
+
+  TAbstractFpFieldElement = class abstract(TECFieldElement)
+  end;
+
+  TFpFieldElement = class sealed(TAbstractFpFieldElement, IECFieldElement, IFpFieldElement)
+  strict private
+    FQ, FR, FX: TBigInteger;
+    function CheckSqrt(const AZ: IECFieldElement): IECFieldElement;
+    function LucasSequence(const AP, AQ, AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
+  strict protected
+    function ModAdd(const AX1, AX2: TBigInteger): TBigInteger; virtual;
+    function ModDouble(const AX: TBigInteger): TBigInteger; virtual;
+    function ModHalf(const AX: TBigInteger): TBigInteger; virtual;
+    function ModHalfAbs(const AX: TBigInteger): TBigInteger; virtual;
+    function ModInverse(const AX: TBigInteger): TBigInteger; virtual;
+    function ModMult(const AX1, AX2: TBigInteger): TBigInteger; virtual;
+    function ModReduce(const AX: TBigInteger): TBigInteger; virtual;
+    function ModSubtract(const AX1, AX2: TBigInteger): TBigInteger; virtual;
+  public
+    class function CalculateResidue(const AP: TBigInteger): TBigInteger; static;
+    constructor Create(const AQ, AR, AX: TBigInteger);
+
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function ToBigInteger: TBigInteger; override;
+    function Add(const AB: IECFieldElement): IECFieldElement; override;
+    function AddOne: IECFieldElement; override;
+    function Subtract(const AB: IECFieldElement): IECFieldElement; override;
+    function Multiply(const AB: IECFieldElement): IECFieldElement; override;
+    function MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement; override;
+    function MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement; override;
+    function Divide(const AB: IECFieldElement): IECFieldElement; override;
+    function Negate: IECFieldElement; override;
+    function Square: IECFieldElement; override;
+    function SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement; override;
+    function SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: IECFieldElement; override;
+
+    function Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+
+    function GetQ: TBigInteger;
+
+    property Q: TBigInteger read GetQ;
+  end;
+
+  TAbstractF2mFieldElement = class abstract(TECFieldElement, IECFieldElement, IAbstractF2mFieldElement)
+  public
+    function HalfTrace: IECFieldElement; virtual;
+    function GetHasFastTrace: Boolean; virtual;
+    function Trace: Int32; virtual;
+
+    property HasFastTrace: Boolean read GetHasFastTrace;
+  end;
+
+  TF2mFieldElement = class sealed(TAbstractF2mFieldElement, IECFieldElement, IAbstractF2mFieldElement, IF2mFieldElement)
+  public
+    const
+      Gnb = 1;
+      Tpb = 2;
+      Ppb = 3;
+  strict private
+    FRepresentation: Int32;
+    FM: Int32;
+    FKs: TCryptoLibInt32Array;
+    FX: TLongArray;
+  public
+    class procedure CheckFieldElements(const AA, AB: IECFieldElement); static;
+
+    constructor Create(AM: Int32; const AKs: TCryptoLibInt32Array; const AX: TLongArray);
+
+    function GetBitLength: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+    function TestBitZero: Boolean; override;
+
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function ToBigInteger: TBigInteger; override;
+    function Add(const AB: IECFieldElement): IECFieldElement; override;
+    function AddOne: IECFieldElement; override;
+    function Subtract(const AB: IECFieldElement): IECFieldElement; override;
+    function Multiply(const AB: IECFieldElement): IECFieldElement; override;
+    function MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement; override;
+    function MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement; override;
+    function Divide(const AB: IECFieldElement): IECFieldElement; override;
+    function Negate: IECFieldElement; override;
+    function Square: IECFieldElement; override;
+    function SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement; override;
+    function SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement; override;
+    function SquarePow(APow: Int32): IECFieldElement; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: IECFieldElement; override;
+
+    function Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+
+    function GetRepresentation: Int32;
+    function GetM: Int32;
+    function GetK1: Int32;
+    function GetK2: Int32;
+    function GetK3: Int32;
+    function GetX: TLongArray;
+
+    property Representation: Int32 read GetRepresentation;
+    property M: Int32 read GetM;
+    property K1: Int32 read GetK1;
+    property K2: Int32 read GetK2;
+    property K3: Int32 read GetK3;
+    property X: TLongArray read GetX;
+  end;
+
+implementation
+
+function TECFieldElement.GetBitLength: Int32;
+begin
+  Result := ToBigInteger.BitLength;
+end;
+
+function TECFieldElement.GetIsOne: Boolean;
+begin
+  Result := BitLength = 1;
+end;
+
+function TECFieldElement.GetIsZero: Boolean;
+begin
+  Result := ToBigInteger.SignValue = 0;
+end;
+
+function TECFieldElement.MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := Multiply(AB).Subtract(AX.Multiply(AY));
+end;
+
+function TECFieldElement.MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := Multiply(AB).Add(AX.Multiply(AY));
+end;
+
+function TECFieldElement.SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := Square().Subtract(AX.Multiply(AY));
+end;
+
+function TECFieldElement.SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := Square().Add(AX.Multiply(AY));
+end;
+
+function TECFieldElement.SquarePow(APow: Int32): IECFieldElement;
+var
+  LR: IECFieldElement;
+  I: Int32;
+begin
+  LR := Self as IECFieldElement;
+  I := 0;
+  while I < APow do
+  begin
+    LR := LR.Square();
+    System.Inc(I);
+  end;
+  Result := LR;
+end;
+
+function TECFieldElement.TestBitZero: Boolean;
+begin
+  Result := ToBigInteger.TestBit(0);
+end;
+
+function TECFieldElement.GetHashCode: {$IFDEF DELPHI}Int32{$ELSE}PtrInt{$ENDIF};
+begin
+  Result := ToBigInteger.GetHashCode();
+end;
+
+function TECFieldElement.ToString: String;
+begin
+  Result := ToBigInteger.ToString(16);
+end;
+
+function TECFieldElement.Equals(const AOther: IECFieldElement): Boolean;
+begin
+  if AOther = nil then
+    Exit(False);
+  if (Self as IECFieldElement) = AOther then
+    Exit(True);
+  Result := ToBigInteger.Equals(AOther.ToBigInteger);
+end;
+
+function TECFieldElement.GetEncoded: TCryptoLibByteArray;
+begin
+  Result := TBigIntegers.AsUnsignedByteArray(GetEncodedLength(), ToBigInteger);
+end;
+
+function TECFieldElement.GetEncodedLength: Int32;
+begin
+  Result := (GetFieldSize + 7) div 8;
+end;
+
+procedure TECFieldElement.EncodeTo(var ABuf: TCryptoLibByteArray; AOff: Int32);
+begin
+  TBigIntegers.AsUnsignedByteArray(ToBigInteger, ABuf, AOff, GetEncodedLength());
+end;
+
+{ TFpFieldElement }
+
+class function TFpFieldElement.CalculateResidue(const AP: TBigInteger): TBigInteger;
+var
+  LBitLength: Int32;
+  LFirstWord: TBigInteger;
+begin
+  LBitLength := AP.BitLength;
+  if LBitLength >= 96 then
+  begin
+    LFirstWord := AP.ShiftRight(LBitLength - 64);
+    if LFirstWord.Int64Value = -1 then
+    begin
+      Result := TBigInteger.One.ShiftLeft(LBitLength).Subtract(AP);
+      Exit;
+    end;
+    if (LBitLength and 7) = 0 then
+    begin
+      Result := TBigInteger.One.ShiftLeft(LBitLength shl 1).Divide(AP).Negate();
+      Exit;
+    end;
+  end;
+  Result := TBigInteger.GetDefault();
+end;
+
+constructor TFpFieldElement.Create(const AQ, AR, AX: TBigInteger);
+begin
+  Inherited Create;
+  FQ := AQ;
+  FR := AR;
+  FX := AX;
+end;
+
+function TFpFieldElement.ModAdd(const AX1, AX2: TBigInteger): TBigInteger;
+var
+  LX3: TBigInteger;
+begin
+  LX3 := AX1.Add(AX2);
+  if LX3.CompareTo(FQ) >= 0 then
+    LX3 := LX3.Subtract(FQ);
+  Result := LX3;
+end;
+
+function TFpFieldElement.ModDouble(const AX: TBigInteger): TBigInteger;
+var
+  L2x: TBigInteger;
+begin
+  L2x := AX.ShiftLeft(1);
+  if L2x.CompareTo(FQ) >= 0 then
+    L2x := L2x.Subtract(FQ);
+  Result := L2x;
+end;
+
+function TFpFieldElement.ModHalf(const AX: TBigInteger): TBigInteger;
+var
+  LX: TBigInteger;
+begin
+  LX := AX;
+  if LX.TestBit(0) then
+    LX := FQ.Add(LX);
+  Result := LX.ShiftRight(1);
+end;
+
+function TFpFieldElement.ModHalfAbs(const AX: TBigInteger): TBigInteger;
+var
+  LX: TBigInteger;
+begin
+  LX := AX;
+  if LX.TestBit(0) then
+    LX := FQ.Subtract(LX);
+  Result := LX.ShiftRight(1);
+end;
+
+function TFpFieldElement.ModInverse(const AX: TBigInteger): TBigInteger;
+begin
+  Result := TBigIntegers.ModOddInverse(FQ, AX);
+end;
+
+function TFpFieldElement.ModMult(const AX1, AX2: TBigInteger): TBigInteger;
+begin
+  Result := ModReduce(AX1.Multiply(AX2));
+end;
+
+function TFpFieldElement.ModReduce(const AX: TBigInteger): TBigInteger;
+var
+  LNegative: Boolean;
+  LQLen, LD, LQLenD: Int32;
+  LX, LQMod, LU, LV, LMu, LQuot, LBk1: TBigInteger;
+  LRIsOne: Boolean;
+begin
+  if not FR.IsInitialized then
+    Result := AX.&Mod(FQ)
+  else
+  begin
+    LNegative := AX.SignValue < 0;
+    LX := AX;
+    if LNegative then
+      LX := LX.Abs();
+    LQLen := FQ.BitLength;
+    if FR.SignValue > 0 then
+    begin
+      LQMod := TBigInteger.One.ShiftLeft(LQLen);
+      LRIsOne := FR.Equals(TBigInteger.One);
+      while LX.BitLength > (LQLen + 1) do
+      begin
+        LU := LX.ShiftRight(LQLen);
+        LV := LX.Remainder(LQMod);
+        if not LRIsOne then
+          LU := LU.Multiply(FR);
+        LX := LU.Add(LV);
+      end;
+    end
+    else
+    begin
+      LD := ((LQLen - 1) and 31) + 1;
+      LQLenD := LQLen + LD;
+      LMu := FR.Negate();
+      LU := LMu.Multiply(LX.ShiftRight(LQLen - LD));
+      LQuot := LU.ShiftRight(LQLenD);
+      LV := LQuot.Multiply(FQ);
+      LBk1 := TBigInteger.One.ShiftLeft(LQLenD);
+      LV := LV.Remainder(LBk1);
+      LX := LX.Remainder(LBk1);
+      LX := LX.Subtract(LV);
+      if LX.SignValue < 0 then
+        LX := LX.Add(LBk1);
+    end;
+    while LX.CompareTo(FQ) >= 0 do
+      LX := LX.Subtract(FQ);
+    if LNegative and (LX.SignValue <> 0) then
+      LX := FQ.Subtract(LX);
+    Result := LX;
+  end;
+end;
+
+function TFpFieldElement.ModSubtract(const AX1, AX2: TBigInteger): TBigInteger;
+var
+  LX3: TBigInteger;
+begin
+  LX3 := AX1.Subtract(AX2);
+  if LX3.SignValue < 0 then
+    LX3 := LX3.Add(FQ);
+  Result := LX3;
+end;
+
+function TFpFieldElement.GetFieldName: String;
+begin
+  Result := 'Fp';
+end;
+
+function TFpFieldElement.GetFieldSize: Int32;
+begin
+  Result := FQ.BitLength;
+end;
+
+function TFpFieldElement.ToBigInteger: TBigInteger;
+begin
+  Result := FX;
+end;
+
+function TFpFieldElement.Add(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := TFpFieldElement.Create(FQ, FR, ModAdd(FX, AB.ToBigInteger()));
+end;
+
+function TFpFieldElement.AddOne: IECFieldElement;
+var
+  LX2: TBigInteger;
+begin
+  LX2 := FX.Add(TBigInteger.One);
+  if LX2.CompareTo(FQ) = 0 then
+    LX2 := TBigInteger.Zero;
+  Result := TFpFieldElement.Create(FQ, FR, LX2);
+end;
+
+function TFpFieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := TFpFieldElement.Create(FQ, FR, ModSubtract(FX, AB.ToBigInteger()));
+end;
+
+function TFpFieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := TFpFieldElement.Create(FQ, FR, ModMult(FX, AB.ToBigInteger()));
+end;
+
+function TFpFieldElement.MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAx, LBx, LXx, LYx, LAb, LXy: TBigInteger;
+begin
+  LAx := FX;
+  LBx := AB.ToBigInteger();
+  LXx := AX.ToBigInteger();
+  LYx := AY.ToBigInteger();
+  LAb := LAx.Multiply(LBx);
+  LXy := LXx.Multiply(LYx);
+  Result := TFpFieldElement.Create(FQ, FR, ModReduce(LAb.Subtract(LXy)));
+end;
+
+function TFpFieldElement.MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAx, LBx, LXx, LYx, LAb, LXy, LSum: TBigInteger;
+begin
+  LAx := FX;
+  LBx := AB.ToBigInteger();
+  LXx := AX.ToBigInteger();
+  LYx := AY.ToBigInteger();
+  LAb := LAx.Multiply(LBx);
+  LXy := LXx.Multiply(LYx);
+  LSum := LAb.Add(LXy);
+  if FR.IsInitialized and (FR.SignValue < 0) and (LSum.BitLength > (FQ.BitLength shl 1)) then
+    LSum := LSum.Subtract(FQ.ShiftLeft(FQ.BitLength));
+  Result := TFpFieldElement.Create(FQ, FR, ModReduce(LSum));
+end;
+
+function TFpFieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := TFpFieldElement.Create(FQ, FR, ModMult(FX, ModInverse(AB.ToBigInteger())));
+end;
+
+function TFpFieldElement.Negate: IECFieldElement;
+begin
+  if FX.SignValue = 0 then
+    Result := Self as IECFieldElement
+  else
+    Result := TFpFieldElement.Create(FQ, FR, FQ.Subtract(FX));
+end;
+
+function TFpFieldElement.Square: IECFieldElement;
+begin
+  Result := TFpFieldElement.Create(FQ, FR, ModMult(FX, FX));
+end;
+
+function TFpFieldElement.SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAx, LXx, LYx, LAa, LXy: TBigInteger;
+begin
+  LAx := FX;
+  LXx := AX.ToBigInteger();
+  LYx := AY.ToBigInteger();
+  LAa := LAx.Multiply(LAx);
+  LXy := LXx.Multiply(LYx);
+  Result := TFpFieldElement.Create(FQ, FR, ModReduce(LAa.Subtract(LXy)));
+end;
+
+function TFpFieldElement.SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAx, LXx, LYx, LAa, LXy, LSum: TBigInteger;
+begin
+  LAx := FX;
+  LXx := AX.ToBigInteger();
+  LYx := AY.ToBigInteger();
+  LAa := LAx.Multiply(LAx);
+  LXy := LXx.Multiply(LYx);
+  LSum := LAa.Add(LXy);
+  if FR.IsInitialized and (FR.SignValue < 0) and (LSum.BitLength > (FQ.BitLength shl 1)) then
+    LSum := LSum.Subtract(FQ.ShiftLeft(FQ.BitLength));
+  Result := TFpFieldElement.Create(FQ, FR, ModReduce(LSum));
+end;
+
+function TFpFieldElement.Invert: IECFieldElement;
+begin
+  Result := TFpFieldElement.Create(FQ, FR, ModInverse(FX));
+end;
+
+function TFpFieldElement.CheckSqrt(const AZ: IECFieldElement): IECFieldElement;
+begin
+  if AZ.Square().Equals(Self as IECFieldElement) then
+    Result := AZ
+  else
+    Result := nil;
+end;
+
+function TFpFieldElement.LucasSequence(const AP, AQ, AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
+var
+  LN, LS, LJ: Int32;
+  LUh, LVl, LVh, LQl, LQh: TBigInteger;
+  LResult: TCryptoLibGenericArray<TBigInteger>;
+begin
+  LN := AK.BitLength;
+  LS := AK.GetLowestSetBit();
+  {$IFDEF DEBUG}
+  System.Assert(AK.TestBit(LS));
+  {$ENDIF}
+  LUh := TBigInteger.One;
+  LVl := TBigInteger.Two;
+  LVh := AP;
+  LQl := TBigInteger.One;
+  LQh := TBigInteger.One;
+  LJ := LN - 1;
+  while LJ >= LS + 1 do
+  begin
+    LQl := ModMult(LQl, LQh);
+    if AK.TestBit(LJ) then
+    begin
+      LQh := ModMult(LQl, AQ);
+      LUh := ModMult(LUh, LVh);
+      LVl := ModReduce(LVh.Multiply(LVl).Subtract(AP.Multiply(LQl)));
+      LVh := ModReduce(LVh.Multiply(LVh).Subtract(LQh.ShiftLeft(1)));
+    end
+    else
+    begin
+      LQh := LQl;
+      LUh := ModReduce(LUh.Multiply(LVl).Subtract(LQl));
+      LVh := ModReduce(LVh.Multiply(LVl).Subtract(AP.Multiply(LQl)));
+      LVl := ModReduce(LVl.Multiply(LVl).Subtract(LQl.ShiftLeft(1)));
+    end;
+    System.Dec(LJ);
+  end;
+  LQl := ModMult(LQl, LQh);
+  LQh := ModMult(LQl, AQ);
+  LUh := ModReduce(LUh.Multiply(LVl).Subtract(LQl));
+  LVl := ModReduce(LVh.Multiply(LVl).Subtract(AP.Multiply(LQl)));
+  LQl := ModMult(LQl, LQh);
+  for LJ := 1 to LS do
+  begin
+    LUh := ModMult(LUh, LVl);
+    LVl := ModReduce(LVl.Multiply(LVl).Subtract(LQl.ShiftLeft(1)));
+    LQl := ModMult(LQl, LQl);
+  end;
+  SetLength(LResult, 2);
+  LResult[0] := LUh;
+  LResult[1] := LVl;
+  Result := LResult;
+end;
+
+function TFpFieldElement.Sqrt: IECFieldElement;
+var
+  LE, LT1, LT2, LT3, LT4, LY, LLegendreExponent, LFourX, LK, LQMinusOne: TBigInteger;
+  LP: TBigInteger;
+  LLucasResult: TCryptoLibGenericArray<TBigInteger>;
+  LU, LV: TBigInteger;
+  LZ: IECFieldElement;
+begin
+  if IsZero or IsOne then
+    Exit(Self as IECFieldElement);
+  if not FQ.TestBit(0) then
+    raise ENotImplementedCryptoLibException.Create('even value of q');
+  if FQ.TestBit(1) then
+  begin
+    LE := FQ.ShiftRight(2).Add(TBigInteger.One);
+    LZ := TFpFieldElement.Create(FQ, FR, FX.ModPow(LE, FQ));
+    Exit(CheckSqrt(LZ));
+  end;
+  if FQ.TestBit(2) then
+  begin
+    LT1 := FX.ModPow(FQ.ShiftRight(3), FQ);
+    LT2 := ModMult(LT1, FX);
+    LT3 := ModMult(LT2, LT1);
+    if LT3.Equals(TBigInteger.One) then
+      Exit(CheckSqrt(TFpFieldElement.Create(FQ, FR, LT2)));
+    LT4 := TBigInteger.Two.ModPow(FQ.ShiftRight(2), FQ);
+    LY := ModMult(LT2, LT4);
+    Exit(CheckSqrt(TFpFieldElement.Create(FQ, FR, LY)));
+  end;
+  LLegendreExponent := FQ.ShiftRight(1);
+  if not FX.ModPow(LLegendreExponent, FQ).Equals(TBigInteger.One) then
+    Exit(nil);
+  LFourX := ModDouble(ModDouble(FX));
+  LK := LLegendreExponent.Add(TBigInteger.One);
+  LQMinusOne := FQ.Subtract(TBigInteger.One);
+  repeat
+    repeat
+      LP := TBigInteger.Arbitrary(FQ.BitLength);
+    until (LP.CompareTo(FQ) < 0) and
+      ModReduce(LP.Multiply(LP).Subtract(LFourX)).ModPow(LLegendreExponent, FQ).Equals(LQMinusOne);
+    LLucasResult := LucasSequence(LP, FX, LK);
+    LU := LLucasResult[0];
+    LV := LLucasResult[1];
+    if ModMult(LV, LV).Equals(LFourX) then
+      Exit(TFpFieldElement.Create(FQ, FR, ModHalfAbs(LV)));
+  until (not LU.Equals(TBigInteger.One)) and (not LU.Equals(LQMinusOne));
+  Result := nil;
+end;
+
+function TFpFieldElement.GetQ: TBigInteger;
+begin
+  Result := FQ;
+end;
+
+function TFpFieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LOtherFp: IFpFieldElement;
+begin
+  if AOther = nil then
+    Exit(False);
+  if (Self as IECFieldElement) = AOther then
+    Exit(True);
+  if not Supports(AOther, IFpFieldElement, LOtherFp) then
+    Exit(False);
+  Result := FQ.Equals(LOtherFp.Q) and FX.Equals(AOther.ToBigInteger());
+end;
+
+function TFpFieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
+begin
+  Result := FQ.GetHashCode() xor FX.GetHashCode();
+end;
+
+{ TAbstractF2mFieldElement }
+
+function TAbstractF2mFieldElement.HalfTrace: IECFieldElement;
+var
+  LM, LN, LK, LNk: Int32;
+  LHt: IECFieldElement;
+begin
+  LM := GetFieldSize;
+  if (LM and 1) = 0 then
+    raise EInvalidOperationCryptoLibException.Create(SHalfTraceOnlyDefinedForOddM);
+  LN := TBitOperations.Asr32(LM + 1, 1);
+  LK := 31 - TBitOperations.NumberOfLeadingZeros32(UInt32(LN));
+  LNk := 1;
+  LHt := Self as IECFieldElement;
+  while LK > 0 do
+  begin
+    LHt := LHt.SquarePow(LNk shl 1).Add(LHt);
+    System.Dec(LK);
+    LNk := TBitOperations.Asr32(LN, LK);
+    if (LNk and 1) <> 0 then
+      LHt := LHt.SquarePow(2).Add(Self as IECFieldElement);
+  end;
+  Result := LHt;
+end;
+
+function TAbstractF2mFieldElement.GetHasFastTrace: Boolean;
+begin
+  Result := False;
+end;
+
+function TAbstractF2mFieldElement.Trace: Int32;
+var
+  LM, LK, LMk: Int32;
+  LTr: IECFieldElement;
+begin
+  LM := GetFieldSize;
+  LK := 31 - TBitOperations.NumberOfLeadingZeros32(UInt32(LM));
+  LMk := 1;
+  LTr := Self as IECFieldElement;
+  while LK > 0 do
+  begin
+    LTr := LTr.SquarePow(LMk).Add(LTr);
+    System.Dec(LK);
+    LMk := TBitOperations.Asr32(LM, LK);
+    if (LMk and 1) <> 0 then
+      LTr := LTr.Square().Add(Self as IECFieldElement);
+  end;
+  if LTr.IsZero then
+    Result := 0
+  else if LTr.IsOne then
+    Result := 1
+  else
+    raise EInvalidOperationCryptoLibException.Create(SInternalErrorInTraceCalculation);
+end;
+
+{ TF2mFieldElement }
+
+class procedure TF2mFieldElement.CheckFieldElements(const AA, AB: IECFieldElement);
+var
+  LAIntf, LBIntf: IF2mFieldElement;
+begin
+  if not Supports(AA, IF2mFieldElement, LAIntf) or not Supports(AB, IF2mFieldElement, LBIntf) then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementsNotBothInstances);
+  if LAIntf.Representation <> LBIntf.Representation then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementIncorrectRepresentation);
+  if (LAIntf.M <> LBIntf.M) or (LAIntf.K1 <> LBIntf.K1) or (LAIntf.K2 <> LBIntf.K2) or (LAIntf.K3 <> LBIntf.K3) then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementsNotSameField);
+end;
+
+constructor TF2mFieldElement.Create(AM: Int32; const AKs: TCryptoLibInt32Array; const AX: TLongArray);
+begin
+  Inherited Create;
+  FM := AM;
+  if System.Length(AKs) = 1 then
+    FRepresentation := Tpb
+  else
+    FRepresentation := Ppb;
+  FKs := AKs;
+  FX := AX;
+end;
+
+function TF2mFieldElement.GetX: TLongArray;
+begin
+  Result := FX;
+end;
+
+function TF2mFieldElement.GetBitLength: Int32;
+begin
+  Result := FX.Degree();
+end;
+
+function TF2mFieldElement.GetIsOne: Boolean;
+begin
+  Result := FX.IsOne();
+end;
+
+function TF2mFieldElement.GetIsZero: Boolean;
+begin
+  Result := FX.IsZero();
+end;
+
+function TF2mFieldElement.TestBitZero: Boolean;
+begin
+  Result := FX.TestBitZero();
+end;
+
+function TF2mFieldElement.GetFieldName: String;
+begin
+  Result := 'F2m';
+end;
+
+function TF2mFieldElement.GetFieldSize: Int32;
+begin
+  Result := FM;
+end;
+
+function TF2mFieldElement.ToBigInteger: TBigInteger;
+begin
+  Result := FX.ToBigInteger();
+end;
+
+function TF2mFieldElement.Add(const AB: IECFieldElement): IECFieldElement;
+var
+  LIarrClone: TLongArray;
+  LBIntf: IF2mFieldElement;
+begin
+  if not Supports(AB, IF2mFieldElement, LBIntf) then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementsNotBothInstances);
+  LIarrClone := FX.Copy();
+  LIarrClone.AddShiftedByWords(LBIntf.X, 0);
+  Result := TF2mFieldElement.Create(FM, FKs, LIarrClone);
+end;
+
+function TF2mFieldElement.AddOne: IECFieldElement;
+begin
+  Result := TF2mFieldElement.Create(FM, FKs, FX.AddOne());
+end;
+
+function TF2mFieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := Add(AB);
+end;
+
+function TF2mFieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
+var
+  LBIntf: IF2mFieldElement;
+begin
+  if not Supports(AB, IF2mFieldElement, LBIntf) then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementsNotBothInstances);
+  Result := TF2mFieldElement.Create(FM, FKs, FX.ModMultiply(LBIntf.X, FM, FKs));
+end;
+
+function TF2mFieldElement.MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := MultiplyPlusProduct(AB, AX, AY);
+end;
+
+function TF2mFieldElement.MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAx, LBx, LXx, LYx: TLongArray;
+  LAb, LXy: TLongArray;
+  LBIntf, LXIntf, LYIntf: IF2mFieldElement;
+begin
+  if not Supports(AB, IF2mFieldElement, LBIntf) or not Supports(AX, IF2mFieldElement, LXIntf) or not Supports(AY, IF2mFieldElement, LYIntf) then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementsNotBothInstances);
+  LAx := FX;
+  LBx := LBIntf.X;
+  LXx := LXIntf.X;
+  LYx := LYIntf.X;
+  LAb := LAx.Multiply(LBx, FM, FKs);
+  LXy := LXx.Multiply(LYx, FM, FKs);
+  if TLongArray.AreAliased(LAb, LAx) or TLongArray.AreAliased(LAb, LBx) then
+    LAb := LAb.Copy();
+  LAb.AddShiftedByWords(LXy, 0);
+  LAb.Reduce(FM, FKs);
+  Result := TF2mFieldElement.Create(FM, FKs, LAb);
+end;
+
+function TF2mFieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
+var
+  LBInv: IECFieldElement;
+begin
+  LBInv := AB.Invert();
+  Result := Multiply(LBInv);
+end;
+
+function TF2mFieldElement.Negate: IECFieldElement;
+begin
+  Result := Self as IECFieldElement;
+end;
+
+function TF2mFieldElement.Square: IECFieldElement;
+begin
+  Result := TF2mFieldElement.Create(FM, FKs, FX.ModSquare(FM, FKs));
+end;
+
+function TF2mFieldElement.SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := SquarePlusProduct(AX, AY);
+end;
+
+function TF2mFieldElement.SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAx, LXx, LYx: TLongArray;
+  LAA, LXy: TLongArray;
+  LXIntf, LYIntf: IF2mFieldElement;
+begin
+  if not Supports(AX, IF2mFieldElement, LXIntf) or not Supports(AY, IF2mFieldElement, LYIntf) then
+    raise EArgumentCryptoLibException.Create(SF2mFieldElementsNotBothInstances);
+  LAx := FX;
+  LXx := LXIntf.X;
+  LYx := LYIntf.X;
+  LAA := LAx.Square(FM, FKs);
+  LXy := LXx.Multiply(LYx, FM, FKs);
+  if TLongArray.AreAliased(LAA, LAx) then
+    LAA := LAA.Copy();
+  LAA.AddShiftedByWords(LXy, 0);
+  LAA.Reduce(FM, FKs);
+  Result := TF2mFieldElement.Create(FM, FKs, LAA);
+end;
+
+function TF2mFieldElement.SquarePow(APow: Int32): IECFieldElement;
+begin
+  if APow < 1 then
+    Result := Self as IECFieldElement
+  else
+    Result := TF2mFieldElement.Create(FM, FKs, FX.ModSquareN(APow, FM, FKs));
+end;
+
+function TF2mFieldElement.Invert: IECFieldElement;
+begin
+  Result := TF2mFieldElement.Create(FM, FKs, FX.ModInverse(FM, FKs));
+end;
+
+function TF2mFieldElement.Sqrt: IECFieldElement;
+begin
+  if FX.IsZero() or FX.IsOne() then
+    Result := Self as IECFieldElement
+  else
+    Result := SquarePow(FM - 1);
+end;
+
+function TF2mFieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LOtherF2m: IF2mFieldElement;
+begin
+  if AOther = nil then
+    Exit(False);
+  if (Self as IECFieldElement) = AOther then
+    Exit(True);
+  if not Supports(AOther, IF2mFieldElement, LOtherF2m) then
+    Exit(False);
+  Result := (FM = LOtherF2m.M) and (FRepresentation = LOtherF2m.Representation)
+    and (GetK1 = LOtherF2m.K1) and (GetK2 = LOtherF2m.K2) and (GetK3 = LOtherF2m.K3)
+    and FX.Equals(LOtherF2m.X);
+end;
+
+function TF2mFieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
+begin
+  Result := FX.GetHashCode() xor FM xor TArrayUtilities.GetArrayHashCode(FKs);
+end;
+
+function TF2mFieldElement.GetRepresentation: Int32;
+begin
+  Result := FRepresentation;
+end;
+
+function TF2mFieldElement.GetM: Int32;
+begin
+  Result := FM;
+end;
+
+function TF2mFieldElement.GetK1: Int32;
+begin
+  Result := FKs[0];
+end;
+
+function TF2mFieldElement.GetK2: Int32;
+begin
+  if System.Length(FKs) >= 2 then
+    Result := FKs[1]
+  else
+    Result := 0;
+end;
+
+function TF2mFieldElement.GetK3: Int32;
+begin
+  if System.Length(FKs) >= 3 then
+    Result := FKs[2]
+  else
+    Result := 0;
+end;
+
+end.

+ 2263 - 0
CryptoLib/src/Math/EC/ClpECPoint.pas

@@ -0,0 +1,2263 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ * ******************************************************************************* * }
+
+unit ClpECPoint;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  SyncObjs,
+  Generics.Collections,
+  ClpBigInteger,
+  ClpIECCore,
+  ClpIECFieldElement,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpISecureRandom,
+  ClpSecureRandom,
+  ClpCryptoLibTypes;
+
+type
+  TECPoint = class abstract(TInterfacedObject, IECPoint)
+  strict private
+    FPreCompTable: TDictionary<String, IPreCompInfo>;
+    FPointLock: TCriticalSection;
+    FTableLock: TCriticalSection;
+    class function GetInitialZCoords(const ACurve: IECCurve): TCryptoLibGenericArray<IECFieldElement>; static;
+  strict protected
+    FCurve: IECCurve;
+    FX, FY: IECFieldElement;
+    FZs: TCryptoLibGenericArray<IECFieldElement>;
+
+    function GetCurveCoordinateSystem: Int32; virtual;
+    function CreateScaledPoint(const ASx, ASy: IECFieldElement): IECPoint; virtual;
+
+    function RawXCoord: IECFieldElement; inline;
+    function RawYCoord: IECFieldElement; inline;
+    function RawZCoords: TCryptoLibGenericArray<IECFieldElement>; inline;
+    procedure CheckNormalized; virtual;
+  public
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement); overload;
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>); overload;
+    destructor Destroy; override;
+
+    function GetCurve: IECCurve; virtual;
+    function GetIsInfinity: Boolean; virtual;
+    function GetXCoord: IECFieldElement; virtual;
+    function GetYCoord: IECFieldElement; virtual;
+    function GetRawXCoord: IECFieldElement; virtual;
+    function GetRawYCoord: IECFieldElement; virtual;
+    function GetZCoord(AIndex: Int32): IECFieldElement; virtual;
+    function GetZCoords: TCryptoLibGenericArray<IECFieldElement>; virtual;
+
+    function IsNormalized: Boolean; virtual;
+    function Normalize: IECPoint; overload; virtual;
+    function Normalize(const AZInv: IECFieldElement): IECPoint; overload; virtual;
+    function GetDetachedPoint: IECPoint; virtual;
+
+    function ScaleX(const AScale: IECFieldElement): IECPoint; virtual;
+    function ScaleXNegateY(const AScale: IECFieldElement): IECPoint; virtual;
+    function ScaleY(const AScale: IECFieldElement): IECPoint; virtual;
+    function ScaleYNegateX(const AScale: IECFieldElement): IECPoint; virtual;
+
+    function GetPreCompInfo(const AName: String): IPreCompInfo; virtual;
+    function Precompute(const AName: String; const ACallback: IPreCompCallback): IPreCompInfo; virtual;
+
+    function GetEncoded: TCryptoLibByteArray; overload; virtual;
+    function GetEncoded(ACompressed: Boolean): TCryptoLibByteArray; overload; virtual; abstract;
+    function GetEncodedLength(ACompressed: Boolean): Int32; virtual; abstract;
+    procedure EncodeTo(ACompressed: Boolean; var ABuf: TCryptoLibByteArray; AOff: Int32); virtual; abstract;
+
+    function GetAffineXCoord: IECFieldElement; virtual;
+    function GetAffineYCoord: IECFieldElement; virtual;
+    function Add(const AB: IECPoint): IECPoint; virtual; abstract;
+    function Subtract(const AB: IECPoint): IECPoint; virtual; abstract;
+    function Negate: IECPoint; virtual; abstract;
+    function Twice: IECPoint; virtual; abstract;
+    function Multiply(const AK: TBigInteger): IECPoint; virtual; abstract;
+    function TimesPow2(AE: Int32): IECPoint; virtual;
+    function TwicePlus(const AB: IECPoint): IECPoint; virtual;
+    function ThreeTimes: IECPoint; virtual;
+
+    function Equals(const AOther: IECPoint): Boolean;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+    function ToString: String; override;
+
+  strict protected
+    function Detach: IECPoint; virtual; abstract;  // called from GetDetachedPoint on normalized point
+    function GetCompressionYTilde: Boolean; virtual; abstract;
+  public
+    function ImplIsValid(ADecompressed, ACheckOrder: Boolean): Boolean; virtual;
+    function SatisfiesCurveEquation: Boolean; virtual; abstract;
+    function SatisfiesOrder: Boolean; virtual;
+    function IsValid: Boolean; virtual;
+    function IsValidPartial: Boolean; virtual;
+  end;
+
+  TECPointBase = class abstract(TECPoint, IECPointBase)
+  public
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement); overload;
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>); overload;
+    function GetEncoded(ACompressed: Boolean): TCryptoLibByteArray; overload; override;
+    function GetEncodedLength(ACompressed: Boolean): Int32; override;
+    procedure EncodeTo(ACompressed: Boolean; var ABuf: TCryptoLibByteArray; AOff: Int32); override;
+    function Multiply(const AK: TBigInteger): IECPoint; override;
+  end;
+
+  TAbstractFpPoint = class abstract(TECPointBase, IAbstractFpPoint)
+  strict protected
+    function GetCompressionYTilde: Boolean; override;
+  public
+    function SatisfiesCurveEquation: Boolean; override;
+    function Subtract(const AB: IECPoint): IECPoint; override;
+  end;
+
+  TFpPoint = class sealed(TAbstractFpPoint, IFpPoint)
+  strict protected
+    function Detach: IECPoint; override;
+    function Two(const AX: IECFieldElement): IECFieldElement; virtual;
+    function Three(const AX: IECFieldElement): IECFieldElement; virtual;
+    function Four(const AX: IECFieldElement): IECFieldElement; virtual;
+    function Eight(const AX: IECFieldElement): IECFieldElement; virtual;
+    function DoubleProductFromSquares(const AA, AB, AASquared, ABSquared: IECFieldElement): IECFieldElement; virtual;
+    function CalculateJacobianModifiedW(const AZ, AZSquared: IECFieldElement): IECFieldElement; virtual;
+    function GetJacobianModifiedW: IECFieldElement; virtual;
+    function TwiceJacobianModified(ACalculateW: Boolean): IECPoint; virtual;
+  public
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement); overload;
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>); overload;
+    function GetZCoord(AIndex: Int32): IECFieldElement; override;
+    function Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function ThreeTimes: IECPoint; override;
+    function TimesPow2(AE: Int32): IECPoint; override;
+    function Negate: IECPoint; override;
+  end;
+
+  TAbstractF2mPoint = class abstract(TECPointBase, IAbstractF2mPoint)
+  strict protected
+    function SatisfiesOrder: Boolean; override;
+  public
+    function SatisfiesCurveEquation: Boolean; override;
+    function ScaleX(const AScale: IECFieldElement): IECPoint; override;
+    function ScaleXNegateY(const AScale: IECFieldElement): IECPoint; override;
+    function ScaleY(const AScale: IECFieldElement): IECPoint; override;
+    function ScaleYNegateX(const AScale: IECFieldElement): IECPoint; override;
+    function Subtract(const AB: IECPoint): IECPoint; override;
+    function Tau: IAbstractF2mPoint; virtual;
+    function TauPow(APow: Int32): IAbstractF2mPoint; virtual;
+  end;
+
+  TF2mPoint = class sealed(TAbstractF2mPoint, IF2mPoint)
+  strict protected
+    function Detach: IECPoint; override;
+    function GetCompressionYTilde: Boolean; override;
+  public
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement); overload;
+    constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>); overload;
+    function GetYCoord: IECFieldElement; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function Negate: IECPoint; override;
+  end;
+
+implementation
+
+uses
+  ClpECAlgorithms,
+  ClpECFieldElement,
+  ClpECCurveConstants,
+  ClpIValidityPreCompInfo,
+  ClpValidityPreCompInfo,
+  ClpECCurve;
+
+resourcestring
+  SPointNotInNormalForm = 'point not in normal form';
+  SUnknownCoordinateSystem = 'unknown coordinate system';
+  SDetachedPointsMustBeInAffine = 'Detached points must be in affine coordinates';
+  SNotAProjectiveCoordinateSystem = 'not a projective coordinate system';
+  SInvalidTimesPow2Exponent = 'exponent cannot be negative';
+
+{ TValidityCallback }
+
+type
+  TValidityCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FOuter: IECPoint;
+    FDecompressed: Boolean;
+    FCheckOrder: Boolean;
+  public
+    constructor Create(const AOuter: IECPoint; ADecompressed, ACheckOrder: Boolean);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TValidityCallback.Create(const AOuter: IECPoint; ADecompressed,
+  ACheckOrder: Boolean);
+begin
+  inherited Create;
+  FOuter := AOuter;
+  FDecompressed := ADecompressed;
+  FCheckOrder := ACheckOrder;
+end;
+
+function TValidityCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+var
+  LValidity: IValidityPreCompInfo;
+begin
+  if not Supports(AExisting, IValidityPreCompInfo, LValidity) then
+    LValidity := TValidityPreCompInfo.Create;
+  if LValidity.HasFailed then
+    Exit(LValidity);
+  if not LValidity.HasCurveEquationPassed then
+  begin
+    if (not FDecompressed) and (not FOuter.SatisfiesCurveEquation) then
+    begin
+      LValidity.ReportFailed;
+      Exit(LValidity);
+    end;
+    LValidity.ReportCurveEquationPassed;
+  end;
+  if FCheckOrder and (not LValidity.HasOrderPassed) then
+  begin
+    if not FOuter.SatisfiesOrder then
+    begin
+      LValidity.ReportFailed;
+      Exit(LValidity);
+    end;
+    LValidity.ReportOrderPassed;
+  end;
+  Result := LValidity;
+end;
+
+{ TECPoint }
+
+class function TECPoint.GetInitialZCoords(const ACurve: IECCurve): TCryptoLibGenericArray<IECFieldElement>;
+var
+  LCoord: Int32;
+  LOne: IECFieldElement;
+begin
+  if ACurve = nil then
+    LCoord := TECCurveConstants.COORD_AFFINE
+  else
+    LCoord := ACurve.CoordinateSystem;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
+      SetLength(Result, 0);
+  else
+    begin
+      LOne := ACurve.FromBigInteger(TBigInteger.One);
+      case LCoord of
+        TECCurveConstants.COORD_HOMOGENEOUS, TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+          Result := TCryptoLibGenericArray<IECFieldElement>.Create(LOne);
+        TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY:
+          Result := TCryptoLibGenericArray<IECFieldElement>.Create(LOne, LOne, LOne);
+        TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+          Result := TCryptoLibGenericArray<IECFieldElement>.Create(LOne, ACurve.A);
+      else
+        raise EArgumentCryptoLibException.Create(SUnknownCoordinateSystem);
+      end;
+    end;
+  end;
+end;
+
+constructor TECPoint.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
+begin
+  Create(ACurve, AX, AY, GetInitialZCoords(ACurve));
+end;
+
+constructor TECPoint.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
+begin
+  Inherited Create;
+  FPreCompTable := nil;
+  FPointLock := TCriticalSection.Create;
+  FTableLock := TCriticalSection.Create;
+  FCurve := ACurve;
+  FX := AX;
+  FY := AY;
+  FZs := AZs;
+end;
+
+destructor TECPoint.Destroy;
+begin
+  FPreCompTable.Free;
+  FTableLock.Free;
+  FPointLock.Free;
+  inherited;
+end;
+
+function TECPoint.GetCurveCoordinateSystem: Int32;
+begin
+  if FCurve = nil then
+    Result := TECCurveConstants.COORD_AFFINE
+  else
+    Result := FCurve.CoordinateSystem;
+end;
+
+function TECPoint.RawXCoord: IECFieldElement;
+begin
+  Result := FX;
+end;
+
+function TECPoint.RawYCoord: IECFieldElement;
+begin
+  Result := FY;
+end;
+
+function TECPoint.GetRawXCoord: IECFieldElement;
+begin
+  Result := RawXCoord;
+end;
+
+function TECPoint.GetRawYCoord: IECFieldElement;
+begin
+  Result := RawYCoord;
+end;
+
+function TECPoint.RawZCoords: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  Result := FZs;
+end;
+
+function TECPoint.GetCurve: IECCurve;
+begin
+  Result := FCurve;
+end;
+
+function TECPoint.GetIsInfinity: Boolean;
+begin
+  Result := (FX = nil) and (FY = nil);
+end;
+
+function TECPoint.GetXCoord: IECFieldElement;
+begin
+  Result := FX;
+end;
+
+function TECPoint.GetYCoord: IECFieldElement;
+begin
+  Result := FY;
+end;
+
+function TECPoint.GetZCoord(AIndex: Int32): IECFieldElement;
+begin
+  if (AIndex < 0) or (AIndex >= System.Length(FZs)) then
+    Result := nil
+  else
+    Result := FZs[AIndex];
+end;
+
+function TECPoint.GetZCoords: TCryptoLibGenericArray<IECFieldElement>;
+var
+  LZsLen, I: Int32;
+begin
+  LZsLen := System.Length(FZs);
+  if LZsLen = 0 then
+    Result := FZs
+  else
+  begin
+    SetLength(Result, LZsLen);
+    for I := 0 to System.Pred(LZsLen) do
+      Result[I] := FZs[I];
+  end;
+end;
+
+procedure TECPoint.CheckNormalized;
+begin
+  if not IsNormalized then
+    raise EInvalidOperationCryptoLibException.Create(SPointNotInNormalForm);
+end;
+
+function TECPoint.IsNormalized: Boolean;
+var
+  LCoord: Int32;
+begin
+  LCoord := GetCurveCoordinateSystem();
+  Result := (LCoord = TECCurveConstants.COORD_AFFINE) or (LCoord = TECCurveConstants.COORD_LAMBDA_AFFINE) or
+    GetIsInfinity or RawZCoords[0].GetIsOne;
+end;
+
+function TECPoint.SatisfiesOrder: Boolean;
+var
+  LOrder: TBigInteger;
+  LMult: IECPoint;
+begin
+  if TBigInteger.One.Equals(FCurve.Cofactor) then
+    Exit(True);
+  LOrder := FCurve.Order;
+  if LOrder.Equals(TBigInteger.GetDefault()) then
+    Exit(True);
+  LMult := TECAlgorithms.ReferenceMultiply(Self as IECPoint, LOrder);
+  Result := LMult.GetIsInfinity;
+end;
+
+function TECPoint.CreateScaledPoint(const ASx, ASy: IECFieldElement): IECPoint;
+begin
+  Result := FCurve.CreateRawPoint(RawXCoord.Multiply(ASx), RawYCoord.Multiply(ASy));
+end;
+
+function TECPoint.Normalize(const AZInv: IECFieldElement): IECPoint;
+var
+  LCoord: Int32;
+  LZInv2, LZInv3: IECFieldElement;
+begin
+  LCoord := GetCurveCoordinateSystem();
+  case LCoord of
+    TECCurveConstants.COORD_HOMOGENEOUS, TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+      Result := CreateScaledPoint(AZInv, AZInv);
+    TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY, TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+      begin
+        LZInv2 := AZInv.Square();
+        LZInv3 := LZInv2.Multiply(AZInv);
+        Result := CreateScaledPoint(LZInv2, LZInv3);
+      end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SNotAProjectiveCoordinateSystem);
+  end;
+end;
+
+function TECPoint.Normalize: IECPoint;
+var
+  LCoord: Int32;
+  LZ: IECFieldElement;
+  LB, LZInv: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  LCoord := GetCurveCoordinateSystem();
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE, TECCurveConstants.COORD_LAMBDA_AFFINE:
+      Result := Self as IECPoint;
+  else
+    begin
+      LZ := RawZCoords[0];
+      if LZ.GetIsOne then
+        Exit(Self as IECPoint);
+
+      if FCurve = nil then
+        raise EInvalidOperationCryptoLibException.Create(SDetachedPointsMustBeInAffine);
+
+      LB := FCurve.RandomFieldElementMult(TSecureRandom.MasterRandom);
+      LZInv := LZ.Multiply(LB).Invert().Multiply(LB);
+      Result := Normalize(LZInv);
+    end;
+  end;
+end;
+
+function TECPoint.GetDetachedPoint: IECPoint;
+begin
+  Result := Normalize().Detach;
+end;
+
+function TECPoint.GetPreCompInfo(const AName: String): IPreCompInfo;
+var
+  LTable: TDictionary<String, IPreCompInfo>;
+begin
+  FPointLock.Enter;
+  try
+    LTable := FPreCompTable;
+  finally
+    FPointLock.Leave;
+  end;
+
+  if LTable = nil then
+    Exit(nil);
+
+  FTableLock.Enter;
+  try
+    if not LTable.TryGetValue(AName, Result) then
+      Result := nil;
+  finally
+    FTableLock.Leave;
+  end;
+end;
+
+function TECPoint.Precompute(const AName: String; const ACallback: IPreCompCallback): IPreCompInfo;
+var
+  LTable: TDictionary<String, IPreCompInfo>;
+  LExisting: IPreCompInfo;
+begin
+  FPointLock.Enter;
+  try
+    LTable := FPreCompTable;
+    if LTable = nil then
+    begin
+      LTable := TDictionary<String, IPreCompInfo>.Create();
+      FPreCompTable := LTable;
+    end;
+  finally
+    FPointLock.Leave;
+  end;
+
+  FTableLock.Enter;
+  try
+    if not LTable.TryGetValue(AName, LExisting) then
+      LExisting := nil;
+    Result := ACallback.Precompute(LExisting);
+    if Result <> LExisting then
+      LTable.AddOrSetValue(AName, Result);
+  finally
+    FTableLock.Leave;
+  end;
+end;
+
+function TECPoint.GetAffineXCoord: IECFieldElement;
+begin
+  CheckNormalized();
+  Result := FX;
+end;
+
+function TECPoint.GetAffineYCoord: IECFieldElement;
+begin
+  CheckNormalized();
+  Result := FY;
+end;
+
+function TECPoint.GetEncoded: TCryptoLibByteArray;
+begin
+  Result := GetEncoded(False);
+end;
+
+{ TECPointBase }
+
+constructor TECPointBase.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
+begin
+  inherited Create(ACurve, AX, AY);
+end;
+
+constructor TECPointBase.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
+begin
+  inherited Create(ACurve, AX, AY, AZs);
+end;
+
+function TECPointBase.GetEncoded(ACompressed: Boolean): TCryptoLibByteArray;
+var
+  LNormed: IECPoint;
+  LX, LY: TCryptoLibByteArray;
+  LLen: Int32;
+begin
+  if GetIsInfinity then
+  begin
+    System.SetLength(Result, 1);
+    Result[0] := $00;
+    Exit;
+  end;
+  LNormed := Normalize();
+  LX := LNormed.XCoord.GetEncoded();
+  if ACompressed then
+  begin
+    System.SetLength(Result, 1 + System.Length(LX));
+    Result[0] := $02;
+    if LNormed.GetCompressionYTilde then
+      Result[0] := $03;
+    System.Move(LX[0], Result[1], System.Length(LX) * System.SizeOf(Byte));
+    Exit;
+  end;
+  LY := LNormed.YCoord.GetEncoded();
+  LLen := 1 + System.Length(LX) + System.Length(LY);
+  System.SetLength(Result, LLen);
+  Result[0] := $04;
+  System.Move(LX[0], Result[1], System.Length(LX) * System.SizeOf(Byte));
+  System.Move(LY[0], Result[1 + System.Length(LX)], System.Length(LY) * System.SizeOf(Byte));
+end;
+
+function TECPointBase.GetEncodedLength(ACompressed: Boolean): Int32;
+begin
+  if GetIsInfinity then
+    Exit(1);
+  if ACompressed then
+    Exit(1 + XCoord.GetEncodedLength())
+  else
+    Exit(1 + XCoord.GetEncodedLength() + YCoord.GetEncodedLength());
+end;
+
+procedure TECPointBase.EncodeTo(ACompressed: Boolean; var ABuf: TCryptoLibByteArray; AOff: Int32);
+var
+  LNormed: IECPoint;
+  LXLen: Int32;
+begin
+  if GetIsInfinity then
+  begin
+    ABuf[AOff] := $00;
+    Exit;
+  end;
+  LNormed := Normalize();
+  if ACompressed then
+  begin
+    ABuf[AOff] := $02;
+    if LNormed.GetCompressionYTilde then
+      ABuf[AOff] := $03;
+    LNormed.XCoord.EncodeTo(ABuf, AOff + 1);
+    Exit;
+  end;
+  ABuf[AOff] := $04;
+  LXLen := LNormed.XCoord.GetEncodedLength();
+  LNormed.XCoord.EncodeTo(ABuf, AOff + 1);
+  LNormed.YCoord.EncodeTo(ABuf, AOff + 1 + LXLen);
+end;
+
+function TECPointBase.Multiply(const AK: TBigInteger): IECPoint;
+begin
+  Result := FCurve.Multiplier.Multiply(Self as IECPoint, AK);
+end;
+
+function TECPoint.TimesPow2(AE: Int32): IECPoint;
+var
+  P: IECPoint;
+begin
+  if AE < 0 then
+    raise EArgumentCryptoLibException.Create(SInvalidTimesPow2Exponent);
+  P := Self as IECPoint;
+  while AE > 0 do
+  begin
+    Dec(AE);
+    P := P.Twice();
+  end;
+  Result := P;
+end;
+
+function TECPoint.TwicePlus(const AB: IECPoint): IECPoint;
+begin
+  Result := Twice().Add(AB);
+end;
+
+function TECPoint.ThreeTimes: IECPoint;
+begin
+  Result := TwicePlus(Self as IECPoint);
+end;
+
+function TECPoint.ImplIsValid(ADecompressed, ACheckOrder: Boolean): Boolean;
+var
+  LCallback: IPreCompCallback;
+  LValidity: IValidityPreCompInfo;
+  LResult: IPreCompInfo;
+begin
+  if GetIsInfinity then
+    Exit(True);
+  LCallback := TValidityCallback.Create(Self, ADecompressed, ACheckOrder);
+  LResult := FCurve.Precompute(Self as IECPoint, TValidityPreCompInfo.PRECOMP_NAME, LCallback);
+  LValidity := LResult as IValidityPreCompInfo;
+  Result := not LValidity.HasFailed;
+end;
+
+function TECPoint.IsValid: Boolean;
+begin
+  Result := ImplIsValid(False, True);
+end;
+
+function TECPoint.IsValidPartial: Boolean;
+begin
+  Result := ImplIsValid(False, False);
+end;
+
+function TECPoint.ScaleX(const AScale: IECFieldElement): IECPoint;
+begin
+  if GetIsInfinity then
+    Result := Self as IECPoint
+  else
+    Result := FCurve.CreateRawPoint(RawXCoord.Multiply(AScale), RawYCoord, RawZCoords);
+end;
+
+function TECPoint.ScaleXNegateY(const AScale: IECFieldElement): IECPoint;
+begin
+  if GetIsInfinity then
+    Result := Self as IECPoint
+  else
+    Result := FCurve.CreateRawPoint(RawXCoord.Multiply(AScale), RawYCoord.Negate(), RawZCoords);
+end;
+
+function TECPoint.ScaleY(const AScale: IECFieldElement): IECPoint;
+begin
+  if GetIsInfinity then
+    Result := Self as IECPoint
+  else
+    Result := FCurve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(AScale), RawZCoords);
+end;
+
+function TECPoint.ScaleYNegateX(const AScale: IECFieldElement): IECPoint;
+begin
+  if GetIsInfinity then
+    Result := Self as IECPoint
+  else
+    Result := FCurve.CreateRawPoint(RawXCoord.Negate(), RawYCoord.Multiply(AScale), RawZCoords);
+end;
+
+function TECPoint.Equals(const AOther: IECPoint): Boolean;
+var
+  LC1, LC2: IECCurve;
+  LN1, LN2, LI1, LI2: Boolean;
+  LP1, LP2: IECPoint;
+  LPoints: TCryptoLibGenericArray<IECPoint>;
+begin
+  if AOther = nil then
+    Exit(False);
+  if (Self as IECPoint) = AOther then
+    Exit(True);
+
+  LC1 := GetCurve();
+  LC2 := AOther.Curve;
+  LN1 := LC1 = nil;
+  LN2 := LC2 = nil;
+  LI1 := GetIsInfinity;
+  LI2 := AOther.GetIsInfinity;
+
+  if LI1 or LI2 then
+    Exit((LI1 and LI2) and (LN1 or LN2 or LC1.Equals(LC2)));
+
+  LP1 := Self as IECPoint;
+  LP2 := AOther;
+
+  if LN1 and LN2 then
+    { points with null curve are in affine form }
+  else if LN1 then
+    LP2 := LP2.Normalize()
+  else if LN2 then
+    LP1 := LP1.Normalize()
+  else if not LC1.Equals(LC2) then
+    Exit(False)
+  else
+  begin
+    LPoints := TCryptoLibGenericArray<IECPoint>.Create(LP1, LC1.ImportPoint(LP2));
+    LC1.NormalizeAll(LPoints);
+    LP1 := LPoints[0];
+    LP2 := LPoints[1];
+  end;
+
+  Result := LP1.XCoord.Equals(LP2.XCoord) and LP1.YCoord.Equals(LP2.YCoord);
+end;
+
+function TECPoint.GetHashCode: {$IFDEF DELPHI}Int32{$ELSE}PtrInt{$ENDIF};
+var
+  LC: IECCurve;
+  LP: IECPoint;
+begin
+  LC := GetCurve();
+  if LC = nil then
+    Result := 0
+  else
+    Result := not LC.GetHashCode();
+
+  if not GetIsInfinity then
+  begin
+    LP := Normalize();
+    Result := Result xor ((LP.XCoord.GetHashCode()) * 17);
+    Result := Result xor ((LP.YCoord.GetHashCode()) * 257);
+  end;
+end;
+
+function TECPoint.ToString: String;
+var
+  I: Int32;
+begin
+  if GetIsInfinity then
+    Exit('INF');
+
+  Result := '(' + RawXCoord.ToString() + ',' + RawYCoord.ToString();
+  for I := 0 to System.High(FZs) do
+    Result := Result + ',' + FZs[I].ToString();
+  Result := Result + ')';
+end;
+
+{ TAbstractFpPoint }
+
+function TAbstractFpPoint.GetCompressionYTilde: Boolean;
+begin
+  Result := GetAffineYCoord.TestBitZero();
+end;
+
+function TAbstractFpPoint.SatisfiesCurveEquation: Boolean;
+var
+  LCoord: Int32;
+  X, Y, A, B, Lhs, Rhs: IECFieldElement;
+  Z, Z2, Z3, Z4, Z6: IECFieldElement;
+begin
+  X := RawXCoord;
+  Y := RawYCoord;
+  A := FCurve.A;
+  B := FCurve.B;
+  Lhs := Y.Square();
+  LCoord := GetCurveCoordinateSystem();
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+      ;
+    TECCurveConstants.COORD_HOMOGENEOUS:
+      begin
+        Z := RawZCoords[0];
+        if not Z.GetIsOne then
+        begin
+          Z2 := Z.Square();
+          Z3 := Z2.Multiply(Z);
+          Lhs := Lhs.Multiply(Z);
+          A := A.Multiply(Z2);
+          B := B.Multiply(Z3);
+        end;
+      end;
+    TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY, TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+      begin
+        Z := RawZCoords[0];
+        if not Z.GetIsOne then
+        begin
+          Z2 := Z.Square();
+          Z4 := Z2.Square();
+          Z6 := Z2.Multiply(Z4);
+          A := A.Multiply(Z4);
+          B := B.Multiply(Z6);
+        end;
+      end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+  Rhs := X.Square().Add(A).Multiply(X).Add(B);
+  Result := Lhs.Equals(Rhs);
+end;
+
+function TAbstractFpPoint.Subtract(const AB: IECPoint): IECPoint;
+begin
+  if AB.GetIsInfinity then
+    Exit(Self as IECPoint);
+  Result := Add(AB.Negate());
+end;
+
+{ TFpPoint }
+
+constructor TFpPoint.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
+begin
+  inherited Create(ACurve, AX, AY);
+  if (AX = nil) <> (AY = nil) then
+    raise EArgumentCryptoLibException.Create('Exactly one of the field elements is null');
+end;
+
+constructor TFpPoint.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
+begin
+  inherited Create(ACurve, AX, AY, AZs);
+end;
+
+function TFpPoint.Detach: IECPoint;
+begin
+  Result := TFpPoint.Create(nil, GetAffineXCoord, GetAffineYCoord);
+end;
+
+function TFpPoint.GetZCoord(AIndex: Int32): IECFieldElement;
+begin
+  if (AIndex = 1) and (TECCurveConstants.COORD_JACOBIAN_MODIFIED = GetCurveCoordinateSystem()) then
+    Exit(GetJacobianModifiedW());
+  Result := inherited GetZCoord(AIndex);
+end;
+
+function TFpPoint.Two(const AX: IECFieldElement): IECFieldElement;
+begin
+  Result := AX.Add(AX);
+end;
+
+function TFpPoint.Three(const AX: IECFieldElement): IECFieldElement;
+begin
+  Result := Two(AX).Add(AX);
+end;
+
+function TFpPoint.Four(const AX: IECFieldElement): IECFieldElement;
+begin
+  Result := Two(Two(AX));
+end;
+
+function TFpPoint.Eight(const AX: IECFieldElement): IECFieldElement;
+begin
+  Result := Four(Two(AX));
+end;
+
+function TFpPoint.DoubleProductFromSquares(const AA, AB, AASquared, ABSquared: IECFieldElement): IECFieldElement;
+begin
+  Result := AA.Add(AB).Square().Subtract(AASquared).Subtract(ABSquared);
+end;
+
+function TFpPoint.CalculateJacobianModifiedW(const AZ, AZSquared: IECFieldElement): IECFieldElement;
+var
+  La4, La4Neg, LW, LZSq: IECFieldElement;
+begin
+  La4 := FCurve.A;
+  if La4.GetIsZero or AZ.IsOne then
+    Exit(La4);
+
+  LZSq := AZSquared;
+  if LZSq = nil then
+    LZSq := AZ.Square();
+
+  LW := LZSq.Square();
+  La4Neg := La4.Negate();
+  if La4Neg.GetBitLength < La4.GetBitLength then
+    LW := LW.Multiply(La4Neg).Negate()
+  else
+    LW := LW.Multiply(La4);
+  Result := LW;
+end;
+
+function TFpPoint.GetJacobianModifiedW: IECFieldElement;
+var
+  LZZ: TCryptoLibGenericArray<IECFieldElement>;
+  LW: IECFieldElement;
+begin
+  LZZ := RawZCoords;
+  LW := LZZ[1];
+  if LW = nil then
+  begin
+    // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
+    LW := CalculateJacobianModifiedW(LZZ[0], nil);
+    LZZ[1] := LW;
+  end;
+  Result := LW;
+end;
+
+function TFpPoint.TwiceJacobianModified(ACalculateW: Boolean): IECPoint;
+var
+  X1, Y1, Z1, W1: IECFieldElement;
+  X1Squared, M, L2Y1, L2Y1Squared, S, X3, L4T, L8T, Y3, W3, Z3: IECFieldElement;
+begin
+  X1 := RawXCoord;
+  Y1 := RawYCoord;
+  Z1 := RawZCoords[0];
+  W1 := GetJacobianModifiedW();
+
+  X1Squared := X1.Square();
+  M := Three(X1Squared).Add(W1);
+  L2Y1 := Two(Y1);
+  L2Y1Squared := L2Y1.Multiply(Y1);
+  S := Two(X1.Multiply(L2Y1Squared));
+  X3 := M.Square().Subtract(Two(S));
+  L4T := L2Y1Squared.Square();
+  L8T := Two(L4T);
+  Y3 := M.Multiply(S.Subtract(X3)).Subtract(L8T);
+  if ACalculateW then
+    W3 := Two(L8T.Multiply(W1))
+  else
+    W3 := nil;
+  if Z1.IsOne then
+    Z3 := L2Y1
+  else
+    Z3 := L2Y1.Multiply(Z1);
+
+  Result := TFpPoint.Create(FCurve, X3, Y3,
+    TCryptoLibGenericArray<IECFieldElement>.Create(Z3, W3));
+end;
+
+function TFpPoint.Add(const AB: IECPoint): IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, Y1, X2, Y2, Dx, Dy, Gamma, X3, Y3, Z3: IECFieldElement;
+  Z1, Z2, LU1, LU2, LV1, LV2, LU, LV, LW: IECFieldElement;
+  LVSquared, LVCubed, LVSquaredV2, LA: IECFieldElement;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  LZ1Squared, LS2, LZ2Squared, LS1, LH, LR: IECFieldElement;
+  LHSquared, LG, LV2: IECFieldElement;
+  LZ1Cubed, LZ2Cubed, LU2b, LS2b, LU1b, LS1b: IECFieldElement;
+  LC, LW1, LW2b, LA1: IECFieldElement;
+  LZ3Squared, LW3: IECFieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if GetIsInfinity then
+    Exit(AB);
+  if AB.GetIsInfinity then
+    Exit(Self as IECPoint);
+  if (Self as IECPoint) = AB then
+    Exit(Twice());
+
+  LCurve := FCurve;
+  LCoord := GetCurveCoordinateSystem();
+  X1 := RawXCoord;
+  Y1 := RawYCoord;
+  X2 := AB.GetRawXCoord;
+  Y2 := AB.GetRawYCoord;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      Dx := X2.Subtract(X1);
+      Dy := Y2.Subtract(Y1);
+      if Dx.GetIsZero then
+      begin
+        if Dy.GetIsZero then
+          Exit(Twice());
+        Exit(LCurve.Infinity);
+      end;
+      Gamma := Dy.Divide(Dx);
+      X3 := Gamma.Square().Subtract(X1).Subtract(X2);
+      Y3 := Gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+      Result := TFpPoint.Create(LCurve, X3, Y3);
+    end;
+
+    TECCurveConstants.COORD_HOMOGENEOUS:
+    begin
+      Z1 := RawZCoords[0];
+      Z2 := AB.GetZCoord(0);
+
+      LZ1IsOne := Z1.IsOne;
+      LZ2IsOne := Z2.IsOne;
+
+      if LZ1IsOne then LU1 := Y2 else LU1 := Y2.Multiply(Z1);
+      if LZ2IsOne then LU2 := Y1 else LU2 := Y1.Multiply(Z2);
+      LU := LU1.Subtract(LU2);
+      if LZ1IsOne then LV1 := X2 else LV1 := X2.Multiply(Z1);
+      if LZ2IsOne then LV2 := X1 else LV2 := X1.Multiply(Z2);
+      LV := LV1.Subtract(LV2);
+
+      // Check if b == this or b == -this
+      if LV.GetIsZero then
+      begin
+        if LU.GetIsZero then
+          Exit(Twice());
+        Exit(LCurve.Infinity);
+      end;
+
+      // TODO Optimize for when w == 1
+      if LZ1IsOne then LW := Z2
+      else if LZ2IsOne then LW := Z1
+      else LW := Z1.Multiply(Z2);
+
+      LVSquared := LV.Square();
+      LVCubed := LVSquared.Multiply(LV);
+      LVSquaredV2 := LVSquared.Multiply(LV2);
+      LA := LU.Square().Multiply(LW).Subtract(LVCubed).Subtract(Two(LVSquaredV2));
+
+      X3 := LV.Multiply(LA);
+      Y3 := LVSquaredV2.Subtract(LA).MultiplyMinusProduct(LU, LU2, LVCubed);
+      Z3 := LVCubed.Multiply(LW);
+
+      Result := TFpPoint.Create(LCurve, X3, Y3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+
+    TECCurveConstants.COORD_JACOBIAN,
+    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+    begin
+      Z1 := RawZCoords[0];
+      Z2 := AB.GetZCoord(0);
+
+      LZ1IsOne := Z1.IsOne;
+
+      X3 := nil;
+      Y3 := nil;
+      Z3 := nil;
+      LZ3Squared := nil;
+
+      if (not LZ1IsOne) and Z1.Equals(Z2) then
+      begin
+        // coZ addition
+        Dx := X1.Subtract(X2);
+        Dy := Y1.Subtract(Y2);
+        if Dx.GetIsZero then
+        begin
+          if Dy.GetIsZero then
+            Exit(Twice());
+          Exit(LCurve.Infinity);
+        end;
+
+        LC := Dx.Square();
+        LW1 := X1.Multiply(LC);
+        LW2b := X2.Multiply(LC);
+        LA1 := LW1.Subtract(LW2b).Multiply(Y1);
+
+        X3 := Dy.Square().Subtract(LW1).Subtract(LW2b);
+        Y3 := LW1.Subtract(X3).Multiply(Dy).Subtract(LA1);
+        Z3 := Dx;
+
+        if LZ1IsOne then
+          LZ3Squared := LC
+        else
+          Z3 := Z3.Multiply(Z1);
+      end
+      else
+      begin
+        if LZ1IsOne then
+        begin
+          LZ1Squared := Z1;
+          LU2b := X2;
+          LS2b := Y2;
+        end
+        else
+        begin
+          LZ1Squared := Z1.Square();
+          LU2b := LZ1Squared.Multiply(X2);
+          LZ1Cubed := LZ1Squared.Multiply(Z1);
+          LS2b := LZ1Cubed.Multiply(Y2);
+        end;
+
+        LZ2IsOne := Z2.IsOne;
+        if LZ2IsOne then
+        begin
+          LZ2Squared := Z2;
+          LU1b := X1;
+          LS1b := Y1;
+        end
+        else
+        begin
+          LZ2Squared := Z2.Square();
+          LU1b := LZ2Squared.Multiply(X1);
+          LZ2Cubed := LZ2Squared.Multiply(Z2);
+          LS1b := LZ2Cubed.Multiply(Y1);
+        end;
+
+        LH := LU1b.Subtract(LU2b);
+        LR := LS1b.Subtract(LS2b);
+
+        // Check if b == this or b == -this
+        if LH.GetIsZero then
+        begin
+          if LR.GetIsZero then
+            Exit(Twice());
+          Exit(LCurve.Infinity);
+        end;
+
+        LHSquared := LH.Square();
+        LG := LHSquared.Multiply(LH);
+        LV2 := LHSquared.Multiply(LU1b);
+
+        X3 := LR.Square().Add(LG).Subtract(Two(LV2));
+        Y3 := LV2.Subtract(X3).MultiplyMinusProduct(LR, LG, LS1b);
+
+        Z3 := LH;
+        if not LZ1IsOne then
+          Z3 := Z3.Multiply(Z1);
+        if not LZ2IsOne then
+          Z3 := Z3.Multiply(Z2);
+
+        if Z3 = LH then
+          LZ3Squared := LHSquared;
+      end;
+
+      if LCoord = TECCurveConstants.COORD_JACOBIAN_MODIFIED then
+      begin
+        // TODO If the result will only be used in a subsequent addition, we don't need W3
+        LW3 := CalculateJacobianModifiedW(Z3, LZ3Squared);
+        LZs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3, LW3);
+      end
+      else
+      begin
+        LZs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
+      end;
+
+      Result := TFpPoint.Create(LCurve, X3, Y3, LZs);
+    end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+end;
+
+function TFpPoint.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, Y1, X3, Y3, Z3: IECFieldElement;
+  X1Squared, Gamma: IECFieldElement;
+  Z1, LW, LS, LT, LB, L4B, LH, L2S, L2T, L4SSquared: IECFieldElement;
+  LZ1IsOne: Boolean;
+  LY1Squared, LT2, La4, La4Neg, LM: IECFieldElement;
+  LZ1Squared, LZ1Pow4: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  Y1 := RawYCoord;
+  if Y1.GetIsZero then
+    Exit(FCurve.Infinity);
+
+  LCurve := FCurve;
+  LCoord := GetCurveCoordinateSystem();
+  X1 := RawXCoord;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      X1Squared := X1.Square();
+      Gamma := Three(X1Squared).Add(LCurve.A).Divide(Two(Y1));
+      X3 := Gamma.Square().Subtract(Two(X1));
+      Y3 := Gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+      Result := TFpPoint.Create(LCurve, X3, Y3);
+    end;
+
+    TECCurveConstants.COORD_HOMOGENEOUS:
+    begin
+      Z1 := RawZCoords[0];
+      LZ1IsOne := Z1.IsOne;
+
+      // TODO Optimize for small negative a4 and -3
+      LW := LCurve.A;
+      if (not LW.GetIsZero) and (not LZ1IsOne) then
+        LW := LW.Multiply(Z1.Square());
+      LW := LW.Add(Three(X1.Square()));
+
+      if LZ1IsOne then LS := Y1 else LS := Y1.Multiply(Z1);
+      if LZ1IsOne then LT := Y1.Square() else LT := LS.Multiply(Y1);
+      LB := X1.Multiply(LT);
+      L4B := Four(LB);
+      LH := LW.Square().Subtract(Two(L4B));
+
+      L2S := Two(LS);
+      X3 := LH.Multiply(L2S);
+      L2T := Two(LT);
+      Y3 := L4B.Subtract(LH).Multiply(LW).Subtract(Two(L2T.Square()));
+      if LZ1IsOne then L4SSquared := Two(L2T) else L4SSquared := L2S.Square();
+      Z3 := Two(L4SSquared).Multiply(LS);
+
+      Result := TFpPoint.Create(LCurve, X3, Y3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+
+    TECCurveConstants.COORD_JACOBIAN:
+    begin
+      Z1 := RawZCoords[0];
+      LZ1IsOne := Z1.IsOne;
+
+      LY1Squared := Y1.Square();
+      LT2 := LY1Squared.Square();
+
+      La4 := LCurve.A;
+      La4Neg := La4.Negate();
+
+      if La4Neg.ToBigInteger().Equals(TBigInteger.Three) then
+      begin
+        if LZ1IsOne then LZ1Squared := Z1 else LZ1Squared := Z1.Square();
+        LM := Three(X1.Add(LZ1Squared).Multiply(X1.Subtract(LZ1Squared)));
+        LS := Four(LY1Squared.Multiply(X1));
+      end
+      else
+      begin
+        X1Squared := X1.Square();
+        LM := Three(X1Squared);
+        if LZ1IsOne then
+        begin
+          LM := LM.Add(La4);
+        end
+        else if not La4.GetIsZero then
+        begin
+          if LZ1IsOne then LZ1Squared := Z1 else LZ1Squared := Z1.Square();
+          LZ1Pow4 := LZ1Squared.Square();
+          if La4Neg.GetBitLength < La4.GetBitLength then
+            LM := LM.Subtract(LZ1Pow4.Multiply(La4Neg))
+          else
+            LM := LM.Add(LZ1Pow4.Multiply(La4));
+        end;
+        LS := Four(X1.Multiply(LY1Squared));
+      end;
+
+      X3 := LM.Square().Subtract(Two(LS));
+      Y3 := LS.Subtract(X3).Multiply(LM).Subtract(Eight(LT2));
+
+      Z3 := Two(Y1);
+      if not LZ1IsOne then
+        Z3 := Z3.Multiply(Z1);
+
+      Result := TFpPoint.Create(LCurve, X3, Y3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+
+    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+    begin
+      Result := TwiceJacobianModified(True);
+    end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+end;
+
+function TFpPoint.TwicePlus(const AB: IECPoint): IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, Y1, X2, Y2, Dx, Dy: IECFieldElement;
+  LX, LY, Ld, LD, LI, LL1, LL2, X4, Y4: IECFieldElement;
+begin
+  if (Self as IECPoint) = AB then
+    Exit(ThreeTimes());
+  if GetIsInfinity then
+    Exit(AB);
+  if AB.GetIsInfinity then
+    Exit(Twice());
+
+  Y1 := RawYCoord;
+  if Y1.GetIsZero then
+    Exit(AB);
+
+  LCurve := FCurve;
+  LCoord := GetCurveCoordinateSystem();
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      X1 := RawXCoord;
+      X2 := AB.GetRawXCoord;
+      Y2 := AB.GetRawYCoord;
+
+      Dx := X2.Subtract(X1);
+      Dy := Y2.Subtract(Y1);
+
+      if Dx.GetIsZero then
+      begin
+        if Dy.GetIsZero then
+          Exit(ThreeTimes());
+        Exit(Self as IECPoint);
+      end;
+
+      LX := Dx.Square();
+      LY := Dy.Square();
+      Ld := LX.Multiply(Two(X1).Add(X2)).Subtract(LY);
+      if Ld.GetIsZero then
+        Exit(LCurve.Infinity);
+
+      LD := Ld.Multiply(Dx);
+      LI := LD.Invert();
+      LL1 := Ld.Multiply(LI).Multiply(Dy);
+      LL2 := Two(Y1).Multiply(LX).Multiply(Dx).Multiply(LI).Subtract(LL1);
+      X4 := LL2.Subtract(LL1).Multiply(LL1.Add(LL2)).Add(X2);
+      Y4 := X1.Subtract(X4).Multiply(LL2).Subtract(Y1);
+
+      Result := TFpPoint.Create(LCurve, X4, Y4);
+    end;
+
+    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+    begin
+      Result := TwiceJacobianModified(False).Add(AB);
+    end;
+  else
+    Result := Twice().Add(AB);
+  end;
+end;
+
+function TFpPoint.ThreeTimes: IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, Y1: IECFieldElement;
+  L2Y1, LX, LZ, LY, Ld, LD, LI, LL1, LL2, X4, Y4: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  Y1 := RawYCoord;
+  if Y1.GetIsZero then
+    Exit(Self as IECPoint);
+
+  LCurve := FCurve;
+  LCoord := GetCurveCoordinateSystem();
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      X1 := RawXCoord;
+
+      L2Y1 := Two(Y1);
+      LX := L2Y1.Square();
+      LZ := Three(X1.Square()).Add(LCurve.A);
+      LY := LZ.Square();
+
+      Ld := Three(X1).Multiply(LX).Subtract(LY);
+      if Ld.GetIsZero then
+        Exit(LCurve.Infinity);
+
+      LD := Ld.Multiply(L2Y1);
+      LI := LD.Invert();
+      LL1 := Ld.Multiply(LI).Multiply(LZ);
+      LL2 := LX.Square().Multiply(LI).Subtract(LL1);
+
+      X4 := LL2.Subtract(LL1).Multiply(LL1.Add(LL2)).Add(X1);
+      Y4 := X1.Subtract(X4).Multiply(LL2).Subtract(Y1);
+      Result := TFpPoint.Create(LCurve, X4, Y4);
+    end;
+
+    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+    begin
+      Result := TwiceJacobianModified(False).Add(Self as IECPoint);
+    end;
+  else
+    // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+    Result := Twice().Add(Self as IECPoint);
+  end;
+end;
+
+function TFpPoint.TimesPow2(AE: Int32): IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord, I: Int32;
+  Y1, X1, Z1, W1: IECFieldElement;
+  LZ1Sq: IECFieldElement;
+  X1Squared, LM, L2Y1, L2Y1Squared, LS, L4T, L8T: IECFieldElement;
+  LZInv, LZInv2, LZInv3: IECFieldElement;
+begin
+  if AE < 0 then
+    raise EArgumentCryptoLibException.Create('cannot be negative');
+  if (AE = 0) or GetIsInfinity then
+    Exit(Self as IECPoint);
+  if AE = 1 then
+    Exit(Twice());
+
+  LCurve := FCurve;
+
+  Y1 := RawYCoord;
+  if Y1.GetIsZero then
+    Exit(LCurve.Infinity);
+
+  LCoord := GetCurveCoordinateSystem();
+
+  W1 := LCurve.A;
+  X1 := RawXCoord;
+  if System.Length(RawZCoords) < 1 then
+    Z1 := LCurve.FromBigInteger(TBigInteger.One)
+  else
+    Z1 := RawZCoords[0];
+
+  if not Z1.IsOne then
+  begin
+    case LCoord of
+      TECCurveConstants.COORD_HOMOGENEOUS:
+      begin
+        LZ1Sq := Z1.Square();
+        X1 := X1.Multiply(Z1);
+        Y1 := Y1.Multiply(LZ1Sq);
+        W1 := CalculateJacobianModifiedW(Z1, LZ1Sq);
+      end;
+      TECCurveConstants.COORD_JACOBIAN:
+      begin
+        W1 := CalculateJacobianModifiedW(Z1, nil);
+      end;
+      TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+      begin
+        W1 := GetJacobianModifiedW();
+      end;
+    end;
+  end;
+
+  for I := 0 to AE - 1 do
+  begin
+    if Y1.GetIsZero then
+      Exit(LCurve.Infinity);
+
+    X1Squared := X1.Square();
+    LM := Three(X1Squared);
+    L2Y1 := Two(Y1);
+    L2Y1Squared := L2Y1.Multiply(Y1);
+    LS := Two(X1.Multiply(L2Y1Squared));
+    L4T := L2Y1Squared.Square();
+    L8T := Two(L4T);
+
+    if not W1.GetIsZero then
+    begin
+      LM := LM.Add(W1);
+      W1 := Two(L8T.Multiply(W1));
+    end;
+
+    X1 := LM.Square().Subtract(Two(LS));
+    Y1 := LM.Multiply(LS.Subtract(X1)).Subtract(L8T);
+    if Z1.IsOne then Z1 := L2Y1 else Z1 := L2Y1.Multiply(Z1);
+  end;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      LZInv := Z1.Invert();
+      LZInv2 := LZInv.Square();
+      LZInv3 := LZInv2.Multiply(LZInv);
+      Result := TFpPoint.Create(LCurve, X1.Multiply(LZInv2), Y1.Multiply(LZInv3));
+    end;
+    TECCurveConstants.COORD_HOMOGENEOUS:
+    begin
+      X1 := X1.Multiply(Z1);
+      Z1 := Z1.Multiply(Z1.Square());
+      Result := TFpPoint.Create(LCurve, X1, Y1,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z1));
+    end;
+    TECCurveConstants.COORD_JACOBIAN:
+    begin
+      Result := TFpPoint.Create(LCurve, X1, Y1,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z1));
+    end;
+    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+    begin
+      Result := TFpPoint.Create(LCurve, X1, Y1,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z1, W1));
+    end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+end;
+
+function TFpPoint.Negate: IECPoint;
+var
+  LCoord: Int32;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+  LCoord := GetCurveCoordinateSystem();
+  if LCoord <> TECCurveConstants.COORD_AFFINE then
+    Exit(TFpPoint.Create(FCurve, RawXCoord, RawYCoord.Negate(), RawZCoords));
+  Result := TFpPoint.Create(FCurve, RawXCoord, RawYCoord.Negate());
+end;
+
+{ TAbstractF2mPoint }
+
+function TAbstractF2mPoint.SatisfiesCurveEquation: Boolean;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X, Y, A, B, Lhs, Rhs: IECFieldElement;
+  Z, L, X2, Z2, Z3, Z4: IECFieldElement;
+  LZIsOne: Boolean;
+begin
+  LCurve := FCurve;
+  X := RawXCoord;
+  Y := RawYCoord;
+  A := LCurve.A;
+  B := LCurve.B;
+
+  LCoord := LCurve.CoordinateSystem;
+  if LCoord = TECCurveConstants.COORD_LAMBDA_PROJECTIVE then
+  begin
+    Z := RawZCoords[0];
+    LZIsOne := Z.IsOne;
+
+    if X.GetIsZero then
+    begin
+      // NOTE: For x == 0, we expect the affine-y instead of the lambda-y
+      Lhs := Y.Square();
+      Rhs := B;
+      if not LZIsOne then
+      begin
+        Z2 := Z.Square();
+        Rhs := Rhs.Multiply(Z2);
+      end;
+    end
+    else
+    begin
+      L := Y;
+      X2 := X.Square();
+      if LZIsOne then
+      begin
+        Lhs := L.Square().Add(L).Add(A);
+        Rhs := X2.Square().Add(B);
+      end
+      else
+      begin
+        Z2 := Z.Square();
+        Z4 := Z2.Square();
+        Lhs := L.Add(Z).MultiplyPlusProduct(L, A, Z2);
+        // TODO If sqrt(b) is precomputed this can be simplified to a single square
+        Rhs := X2.SquarePlusProduct(B, Z4);
+      end;
+      Lhs := Lhs.Multiply(X2);
+    end;
+  end
+  else
+  begin
+    Lhs := Y.Add(X).Multiply(Y);
+
+    case LCoord of
+      TECCurveConstants.COORD_AFFINE:
+        ;
+      TECCurveConstants.COORD_HOMOGENEOUS:
+      begin
+        Z := RawZCoords[0];
+        if not Z.IsOne then
+        begin
+          Z2 := Z.Square();
+          Z3 := Z.Multiply(Z2);
+          Lhs := Lhs.Multiply(Z);
+          A := A.Multiply(Z);
+          B := B.Multiply(Z3);
+        end;
+      end;
+    else
+      raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+    end;
+
+    Rhs := X.Add(A).Multiply(X.Square()).Add(B);
+  end;
+
+  Result := Lhs.Equals(Rhs);
+end;
+
+function TAbstractF2mPoint.SatisfiesOrder: Boolean;
+var
+  LCurve: IECCurve;
+  LCofactor: TBigInteger;
+  LN: IECPoint;
+  LX, LY, LL, LT: IECFieldElement;
+  LF2mCurve: IAbstractF2mCurve;
+begin
+  LCurve := FCurve;
+  LCofactor := LCurve.Cofactor;
+  if TBigInteger.Two.Equals(LCofactor) then
+  begin
+    {
+      Check that 0 == Tr(X + A); then there exists a solution to L^2 + L = X + A, and
+      so a halving is possible, so this point is the double of another.
+
+      Note: Tr(A) == 1 for cofactor 2 curves.
+    }
+    LN := Normalize();
+    LX := LN.AffineXCoord;
+    Exit(0 <> (LX as IAbstractF2mFieldElement).Trace());
+  end;
+  if TBigInteger.Four.Equals(LCofactor) then
+  begin
+    {
+      Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not).
+
+      Note: Tr(A) == 0 for cofactor 4 curves.
+    }
+    LN := Normalize();
+    LX := LN.AffineXCoord;
+    LF2mCurve := LCurve as IAbstractF2mCurve;
+    LL := LF2mCurve.SolveQuadraticEquation(LX.Add(LCurve.A));
+    if LL = nil then
+      Exit(False);
+
+    {
+      A solution exists, therefore 0 == Tr(X + A) == Tr(X).
+    }
+    LY := LN.AffineYCoord;
+    LT := LX.Multiply(LL).Add(LY);
+
+    {
+      Either T or (T + X) is the square of a half-point's x coordinate (hx). In either
+      case, the half-point can be halved again when 0 == Tr(hx + A).
+
+      Check that 0 == Tr(T); then there exists a solution to L^2 + L = hx + A, and so a
+      second halving is possible and this point is four times some other.
+    }
+    Exit(0 = (LT as IAbstractF2mFieldElement).Trace());
+  end;
+  Result := inherited SatisfiesOrder();
+end;
+
+function TAbstractF2mPoint.ScaleX(const AScale: IECFieldElement): IECPoint;
+var
+  LX, LL, LX2, LL2, LZ, LZ2: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  case GetCurveCoordinateSystem() of
+    TECCurveConstants.COORD_LAMBDA_AFFINE:
+    begin
+      // Y is actually Lambda (X + Y/X) here
+      LX := RawXCoord;
+      LL := RawYCoord;
+      LX2 := LX.Multiply(AScale);
+      LL2 := LL.Add(LX).Divide(AScale).Add(LX2);
+      Result := FCurve.CreateRawPoint(LX, LL2, RawZCoords);
+    end;
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      // Y is actually Lambda (X + Y/X) here
+      LX := RawXCoord;
+      LL := RawYCoord;
+      LZ := RawZCoords[0];
+      // We scale the Z coordinate also, to avoid an inversion
+      LX2 := LX.Multiply(AScale.Square());
+      LL2 := LL.Add(LX).Add(LX2);
+      LZ2 := LZ.Multiply(AScale);
+      Result := FCurve.CreateRawPoint(LX, LL2,
+        TCryptoLibGenericArray<IECFieldElement>.Create(LZ2));
+    end;
+  else
+    Result := inherited ScaleX(AScale);
+  end;
+end;
+
+function TAbstractF2mPoint.ScaleXNegateY(const AScale: IECFieldElement): IECPoint;
+begin
+  Result := ScaleX(AScale);
+end;
+
+function TAbstractF2mPoint.ScaleY(const AScale: IECFieldElement): IECPoint;
+var
+  LX, LL, LL2: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  case GetCurveCoordinateSystem() of
+    TECCurveConstants.COORD_LAMBDA_AFFINE,
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      LX := RawXCoord;
+      LL := RawYCoord;
+      // Y is actually Lambda (X + Y/X) here
+      LL2 := LL.Add(LX).Multiply(AScale).Add(LX);
+      Result := FCurve.CreateRawPoint(LX, LL2, RawZCoords);
+    end;
+  else
+    Result := inherited ScaleY(AScale);
+  end;
+end;
+
+function TAbstractF2mPoint.ScaleYNegateX(const AScale: IECFieldElement): IECPoint;
+begin
+  Result := ScaleY(AScale);
+end;
+
+function TAbstractF2mPoint.Subtract(const AB: IECPoint): IECPoint;
+begin
+  if AB.GetIsInfinity then
+    Exit(Self as IECPoint);
+  Result := Add(AB.Negate());
+end;
+
+function TAbstractF2mPoint.Tau: IAbstractF2mPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  LX1, LY1, LZ1: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IAbstractF2mPoint);
+
+  LCurve := GetCurve;
+  LCoord := LCurve.CoordinateSystem;
+
+  LX1 := RawXCoord;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE,
+    TECCurveConstants.COORD_LAMBDA_AFFINE:
+    begin
+      LY1 := RawYCoord;
+      Result := LCurve.CreateRawPoint(LX1.Square(), LY1.Square()) as IAbstractF2mPoint;
+    end;
+    TECCurveConstants.COORD_HOMOGENEOUS,
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      LY1 := RawYCoord;
+      LZ1 := RawZCoords[0];
+      Result := LCurve.CreateRawPoint(LX1.Square(), LY1.Square(),
+        TCryptoLibGenericArray<IECFieldElement>.Create(LZ1.Square())) as IAbstractF2mPoint;
+    end
+  else
+    raise EInvalidOperationCryptoLibException.Create('unsupported coordinate system');
+  end;
+end;
+
+function TAbstractF2mPoint.TauPow(APow: Int32): IAbstractF2mPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  LX1, LY1, LZ1: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IAbstractF2mPoint);
+
+  LCurve := GetCurve;
+  LCoord := LCurve.CoordinateSystem;
+
+  LX1 := RawXCoord;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE,
+    TECCurveConstants.COORD_LAMBDA_AFFINE:
+    begin
+      LY1 := RawYCoord;
+      Result := LCurve.CreateRawPoint(LX1.SquarePow(APow), LY1.SquarePow(APow)) as IAbstractF2mPoint;
+    end;
+    TECCurveConstants.COORD_HOMOGENEOUS,
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      LY1 := RawYCoord;
+      LZ1 := RawZCoords[0];
+      Result := LCurve.CreateRawPoint(LX1.SquarePow(APow), LY1.SquarePow(APow),
+        TCryptoLibGenericArray<IECFieldElement>.Create(LZ1.SquarePow(APow))) as IAbstractF2mPoint;
+    end
+  else
+    raise EInvalidOperationCryptoLibException.Create('unsupported coordinate system');
+  end;
+end;
+
+{ TF2mPoint }
+
+function TF2mPoint.GetCompressionYTilde: Boolean;
+var
+  LX, LY: IECFieldElement;
+begin
+  LX := RawXCoord;
+  if LX.GetIsZero then
+    Exit(False);
+
+  LY := RawYCoord;
+  case GetCurveCoordinateSystem() of
+    TECCurveConstants.COORD_LAMBDA_AFFINE,
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+      Result := LY.TestBitZero() <> LX.TestBitZero();
+  else
+    Result := LY.Divide(LX).TestBitZero();
+  end;
+end;
+
+constructor TF2mPoint.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
+begin
+  inherited Create(ACurve, AX, AY);
+  if (AX = nil) <> (AY = nil) then
+    raise EArgumentCryptoLibException.Create('Exactly one of the field elements is null');
+  if AX <> nil then
+  begin
+    TF2mFieldElement.CheckFieldElements(AX, AY);
+    if ACurve <> nil then
+      TF2mFieldElement.CheckFieldElements(AX, ACurve.A);
+  end;
+end;
+
+constructor TF2mPoint.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
+begin
+  inherited Create(ACurve, AX, AY, AZs);
+end;
+
+function TF2mPoint.Detach: IECPoint;
+begin
+  Result := TF2mPoint.Create(nil, GetAffineXCoord, GetAffineYCoord);
+end;
+
+function TF2mPoint.GetYCoord: IECFieldElement;
+var
+  LCoord: Int32;
+  LX, LL, LY, LZ: IECFieldElement;
+begin
+  LCoord := GetCurveCoordinateSystem();
+  case LCoord of
+    TECCurveConstants.COORD_LAMBDA_AFFINE,
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      LX := RawXCoord;
+      LL := RawYCoord;
+
+      if GetIsInfinity or LX.GetIsZero then
+        Exit(LL);
+
+      // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+      LY := LL.Add(LX).Multiply(LX);
+      if TECCurveConstants.COORD_LAMBDA_PROJECTIVE = LCoord then
+      begin
+        LZ := RawZCoords[0];
+        if not LZ.IsOne then
+          LY := LY.Divide(LZ);
+      end;
+      Result := LY;
+    end;
+  else
+    Result := RawYCoord;
+  end;
+end;
+
+function TF2mPoint.Add(const AB: IECPoint): IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, X2, Y1, Y2, Dx, Dy, LL, X3, Y3, Z3: IECFieldElement;
+  Z1, Z2, LU1, LU2, LV1, LV2, LU, LV: IECFieldElement;
+  LVSq, LVCu, LW, LUV, LA, LVSqZ2: IECFieldElement;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  L1, L2, LS1, LS2, LA2, LB2, LAU1, LAU2, LABZ2, L3: IECFieldElement;
+  LP: IECPoint;
+begin
+  if GetIsInfinity then
+    Exit(AB);
+  if AB.GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  LCurve := FCurve;
+  LCoord := GetCurveCoordinateSystem();
+
+  X1 := RawXCoord;
+  X2 := AB.GetRawXCoord;
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      Y1 := RawYCoord;
+      Y2 := AB.GetRawYCoord;
+
+      Dx := X1.Add(X2);
+      Dy := Y1.Add(Y2);
+
+      if Dx.GetIsZero then
+      begin
+        if Dy.GetIsZero then
+          Exit(Twice());
+        Exit(LCurve.Infinity);
+      end;
+
+      LL := Dy.Divide(Dx);
+      X3 := LL.Square().Add(LL).Add(Dx).Add(LCurve.A);
+      Y3 := LL.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+      Result := TF2mPoint.Create(LCurve, X3, Y3);
+    end;
+
+    TECCurveConstants.COORD_HOMOGENEOUS:
+    begin
+      Y1 := RawYCoord;
+      Z1 := RawZCoords[0];
+      Y2 := AB.GetRawYCoord;
+      Z2 := AB.GetZCoord(0);
+
+      LZ1IsOne := Z1.IsOne;
+      LU1 := Y2;
+      LV1 := X2;
+      if not LZ1IsOne then
+      begin
+        LU1 := LU1.Multiply(Z1);
+        LV1 := LV1.Multiply(Z1);
+      end;
+
+      LZ2IsOne := Z2.IsOne;
+      LU2 := Y1;
+      LV2 := X1;
+      if not LZ2IsOne then
+      begin
+        LU2 := LU2.Multiply(Z2);
+        LV2 := LV2.Multiply(Z2);
+      end;
+
+      LU := LU1.Add(LU2);
+      LV := LV1.Add(LV2);
+
+      if LV.GetIsZero then
+      begin
+        if LU.GetIsZero then
+          Exit(Twice());
+        Exit(LCurve.Infinity);
+      end;
+
+      LVSq := LV.Square();
+      LVCu := LVSq.Multiply(LV);
+      if LZ1IsOne then LW := Z2
+      else if LZ2IsOne then LW := Z1
+      else LW := Z1.Multiply(Z2);
+      LUV := LU.Add(LV);
+      LA := LUV.MultiplyPlusProduct(LU, LVSq, LCurve.A).Multiply(LW).Add(LVCu);
+
+      X3 := LV.Multiply(LA);
+      if LZ2IsOne then LVSqZ2 := LVSq else LVSqZ2 := LVSq.Multiply(Z2);
+      Y3 := LU.MultiplyPlusProduct(X1, LV, Y1).MultiplyPlusProduct(LVSqZ2, LUV, LA);
+      Z3 := LVCu.Multiply(LW);
+
+      Result := TF2mPoint.Create(LCurve, X3, Y3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      if X1.GetIsZero then
+      begin
+        if X2.GetIsZero then
+          Exit(LCurve.Infinity);
+        Exit(AB.Add(Self as IECPoint));
+      end;
+
+      L1 := RawYCoord;
+      Z1 := RawZCoords[0];
+      L2 := AB.GetRawYCoord;
+      Z2 := AB.GetZCoord(0);
+
+      LZ1IsOne := Z1.IsOne;
+      LU2 := X2;
+      LS2 := L2;
+      if not LZ1IsOne then
+      begin
+        LU2 := LU2.Multiply(Z1);
+        LS2 := LS2.Multiply(Z1);
+      end;
+
+      LZ2IsOne := Z2.IsOne;
+      LU1 := X1;
+      LS1 := L1;
+      if not LZ2IsOne then
+      begin
+        LU1 := LU1.Multiply(Z2);
+        LS1 := LS1.Multiply(Z2);
+      end;
+
+      LA2 := LS1.Add(LS2);
+      LB2 := LU1.Add(LU2);
+
+      if LB2.GetIsZero then
+      begin
+        if LA2.GetIsZero then
+          Exit(Twice());
+        Exit(LCurve.Infinity);
+      end;
+
+      if X2.GetIsZero then
+      begin
+        // TODO This can probably be optimized quite a bit
+        LP := (Self as IECPoint).Normalize();
+        X1 := LP.GetRawXCoord;
+        Y1 := LP.GetYCoord;
+
+        Y2 := L2;
+        LL := Y1.Add(Y2).Divide(X1);
+
+        X3 := LL.Square().Add(LL).Add(X1).Add(LCurve.A);
+        if X3.GetIsZero then
+          Exit(TF2mPoint.Create(LCurve, X3, LCurve.B.Sqrt()));
+
+        Y3 := LL.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+        L3 := Y3.Divide(X3).Add(X3);
+        Z3 := LCurve.FromBigInteger(TBigInteger.One);
+      end
+      else
+      begin
+        LB2 := LB2.Square();
+
+        LAU1 := LA2.Multiply(LU1);
+        LAU2 := LA2.Multiply(LU2);
+
+        X3 := LAU1.Multiply(LAU2);
+        if X3.GetIsZero then
+          Exit(TF2mPoint.Create(LCurve, X3, LCurve.B.Sqrt()));
+
+        LABZ2 := LA2.Multiply(LB2);
+        if not LZ2IsOne then
+          LABZ2 := LABZ2.Multiply(Z2);
+
+        L3 := LAU2.Add(LB2).SquarePlusProduct(LABZ2, L1.Add(Z1));
+
+        Z3 := LABZ2;
+        if not LZ1IsOne then
+          Z3 := Z3.Multiply(Z1);
+      end;
+
+      Result := TF2mPoint.Create(LCurve, X3, L3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+end;
+
+function TF2mPoint.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, Y1, L1, X3, Y3, Z3, L3: IECFieldElement;
+  Z1, LX1Z1, LY1Z1, LX1Sq, LS, LV, LVSquared, LSV, LH: IECFieldElement;
+  LZ1IsOne: Boolean;
+  LL1Z1, LZ1Sq, La, LaZ1Sq, LT, Lb, Lt1, Lt2, LX1Z1b: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  LCurve := FCurve;
+  X1 := RawXCoord;
+
+  if X1.GetIsZero then
+    Exit(LCurve.Infinity);
+
+  LCoord := GetCurveCoordinateSystem();
+
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      Y1 := RawYCoord;
+      L1 := Y1.Divide(X1).Add(X1);
+      X3 := L1.Square().Add(L1).Add(LCurve.A);
+      Y3 := X1.SquarePlusProduct(X3, L1.AddOne());
+      Result := TF2mPoint.Create(LCurve, X3, Y3);
+    end;
+
+    TECCurveConstants.COORD_HOMOGENEOUS:
+    begin
+      Y1 := RawYCoord;
+      Z1 := RawZCoords[0];
+
+      LZ1IsOne := Z1.IsOne;
+      if LZ1IsOne then LX1Z1 := X1 else LX1Z1 := X1.Multiply(Z1);
+      if LZ1IsOne then LY1Z1 := Y1 else LY1Z1 := Y1.Multiply(Z1);
+
+      LX1Sq := X1.Square();
+      LS := LX1Sq.Add(LY1Z1);
+      LV := LX1Z1;
+      LVSquared := LV.Square();
+      LSV := LS.Add(LV);
+      LH := LSV.MultiplyPlusProduct(LS, LVSquared, LCurve.A);
+
+      X3 := LV.Multiply(LH);
+      Y3 := LX1Sq.Square().MultiplyPlusProduct(LV, LH, LSV);
+      Z3 := LV.Multiply(LVSquared);
+
+      Result := TF2mPoint.Create(LCurve, X3, Y3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      L1 := RawYCoord;
+      Z1 := RawZCoords[0];
+
+      LZ1IsOne := Z1.IsOne;
+      if LZ1IsOne then LL1Z1 := L1 else LL1Z1 := L1.Multiply(Z1);
+      if LZ1IsOne then LZ1Sq := Z1 else LZ1Sq := Z1.Square();
+      La := LCurve.A;
+      if LZ1IsOne then LaZ1Sq := La else LaZ1Sq := La.Multiply(LZ1Sq);
+      LT := L1.Square().Add(LL1Z1).Add(LaZ1Sq);
+      if LT.GetIsZero then
+        Exit(TF2mPoint.Create(LCurve, LT, LCurve.B.Sqrt()));
+
+      X3 := LT.Square();
+      if LZ1IsOne then Z3 := LT else Z3 := LT.Multiply(LZ1Sq);
+
+      Lb := LCurve.B;
+      if Lb.GetBitLength < TBitOperations.Asr32(LCurve.FieldSize, 1) then
+      begin
+        Lt1 := L1.Add(X1).Square();
+        if Lb.IsOne then
+          Lt2 := LaZ1Sq.Add(LZ1Sq).Square()
+        else
+          // TODO Can be calculated with one square if we pre-compute sqrt(b)
+          Lt2 := LaZ1Sq.SquarePlusProduct(Lb, LZ1Sq.Square());
+        L3 := Lt1.Add(LT).Add(LZ1Sq).Multiply(Lt1).Add(Lt2).Add(X3);
+        if La.GetIsZero then
+          L3 := L3.Add(Z3)
+        else if not La.IsOne then
+          L3 := L3.Add(La.AddOne().Multiply(Z3));
+      end
+      else
+      begin
+        if LZ1IsOne then LX1Z1b := X1 else LX1Z1b := X1.Multiply(Z1);
+        L3 := LX1Z1b.SquarePlusProduct(LT, LL1Z1).Add(X3).Add(Z3);
+      end;
+
+      Result := TF2mPoint.Create(LCurve, X3, L3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+end;
+
+function TF2mPoint.TwicePlus(const AB: IECPoint): IECPoint;
+var
+  LCurve: IECCurve;
+  LCoord: Int32;
+  X1, X2, Z2, L1, Z1, L2: IECFieldElement;
+  LX1Sq, LL1Sq, LZ1Sq, LL1Z1, LT, LL2plus1, LA, LX2Z1Sq, LB2: IECFieldElement;
+  X3, Z3, L3: IECFieldElement;
+begin
+  if GetIsInfinity then
+    Exit(AB);
+  if AB.GetIsInfinity then
+    Exit(Twice());
+
+  LCurve := FCurve;
+  X1 := RawXCoord;
+  if X1.GetIsZero then
+    Exit(AB);
+
+  LCoord := GetCurveCoordinateSystem();
+
+  case LCoord of
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      // NOTE: twicePlus() only optimized for lambda-affine argument
+      X2 := AB.GetRawXCoord;
+      Z2 := AB.GetZCoord(0);
+      if X2.GetIsZero or (not Z2.IsOne) then
+        Exit(Twice().Add(AB));
+
+      L1 := RawYCoord;
+      Z1 := RawZCoords[0];
+      L2 := AB.GetRawYCoord;
+
+      LX1Sq := X1.Square();
+      LL1Sq := L1.Square();
+      LZ1Sq := Z1.Square();
+      LL1Z1 := L1.Multiply(Z1);
+
+      LT := LCurve.A.Multiply(LZ1Sq).Add(LL1Sq).Add(LL1Z1);
+      LL2plus1 := L2.AddOne();
+      LA := LCurve.A.Add(LL2plus1).Multiply(LZ1Sq).Add(LL1Sq).MultiplyPlusProduct(LT, LX1Sq, LZ1Sq);
+      LX2Z1Sq := X2.Multiply(LZ1Sq);
+      LB2 := LX2Z1Sq.Add(LT).Square();
+
+      if LB2.GetIsZero then
+      begin
+        if LA.GetIsZero then
+          Exit(AB.Twice());
+        Exit(LCurve.Infinity);
+      end;
+
+      if LA.GetIsZero then
+        Exit(TF2mPoint.Create(LCurve, LA, LCurve.B.Sqrt()));
+
+      X3 := LA.Square().Multiply(LX2Z1Sq);
+      Z3 := LA.Multiply(LB2).Multiply(LZ1Sq);
+      L3 := LA.Add(LB2).Square().MultiplyPlusProduct(LT, LL2plus1, Z3);
+
+      Result := TF2mPoint.Create(LCurve, X3, L3,
+        TCryptoLibGenericArray<IECFieldElement>.Create(Z3));
+    end;
+  else
+    Result := Twice().Add(AB);
+  end;
+end;
+
+function TF2mPoint.Negate: IECPoint;
+var
+  LCurve: IECCurve;
+  LX, LY, LZ, LL: IECFieldElement;
+  LCoord: Int32;
+begin
+  if GetIsInfinity then
+    Exit(Self as IECPoint);
+
+  LX := RawXCoord;
+  if LX.GetIsZero then
+    Exit(Self as IECPoint);
+
+  LCurve := FCurve;
+  LCoord := LCurve.CoordinateSystem;
+  case LCoord of
+    TECCurveConstants.COORD_AFFINE:
+    begin
+      LY := RawYCoord;
+      Result := TF2mPoint.Create(LCurve, LX, LY.Add(LX));
+    end;
+    TECCurveConstants.COORD_HOMOGENEOUS:
+    begin
+      LY := RawYCoord;
+      LZ := RawZCoords[0];
+      Result := TF2mPoint.Create(LCurve, LX, LY.Add(LX),
+        TCryptoLibGenericArray<IECFieldElement>.Create(LZ));
+    end;
+    TECCurveConstants.COORD_LAMBDA_AFFINE:
+    begin
+      LL := RawYCoord;
+      Result := TF2mPoint.Create(LCurve, LX, LL.AddOne());
+    end;
+    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
+    begin
+      LL := RawYCoord;
+      LZ := RawZCoords[0];
+      Result := TF2mPoint.Create(LCurve, LX, LL.Add(LZ),
+        TCryptoLibGenericArray<IECFieldElement>.Create(LZ));
+    end;
+  else
+    raise EInvalidOperationCryptoLibException.Create(SUnknownCoordinateSystem);
+  end;
+end;
+
+end.

+ 5 - 7
CryptoLib/src/Math/EC/ClpLongArray.pas

@@ -29,7 +29,11 @@ uses
   ClpNat,
   ClpInterleave,
   ClpArrayUtilities,
-  ClpBigInteger;
+  ClpBigInteger,
+  ClpBigIntegers;
+
+resourcestring
+  SInvalidF2mFieldValue = 'invalid F2m field value';
 
 type
   TLongArray = record
@@ -92,14 +96,8 @@ type
     function ToString(): String;
   end;
 
-resourcestring
-  SInvalidF2mFieldValue = 'invalid F2m field value';
-
 implementation
 
-uses
-  ClpBigIntegers;
-
 { TLongArray }
 
 class function TLongArray.AreAliased(const A, B: TLongArray): Boolean;

+ 11 - 24
CryptoLib/src/Math/EC/ClpScaleXNegateYPointMap.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpScaleXNegateYPointMap;
 
 {$I ..\..\Include\CryptoLib.inc}
@@ -22,35 +15,29 @@ unit ClpScaleXNegateYPointMap;
 interface
 
 uses
-  ClpIECC,
-  ClpIScaleXNegateYPointMap;
+  ClpIECCore,
+  ClpIECFieldElement;
 
 type
-  TScaleXNegateYPointMap = class(TInterfacedObject, IECPointMap,
-    IScaleXNegateYPointMap)
-
+  TScaleXNegateYPointMap = class(TInterfacedObject, IECPointMap)
   strict protected
-  var
-    Fscale: IECFieldElement;
-
+    FScale: IECFieldElement;
   public
-    constructor Create(const scale: IECFieldElement);
-    function Map(const p: IECPoint): IECPoint; virtual;
+    constructor Create(const AScale: IECFieldElement);
+    function Map(const AP: IECPoint): IECPoint; virtual;
   end;
 
 implementation
 
-{ TScaleXNegateYPointMap }
-
-constructor TScaleXNegateYPointMap.Create(const scale: IECFieldElement);
+constructor TScaleXNegateYPointMap.Create(const AScale: IECFieldElement);
 begin
-  Inherited Create();
-  Fscale := scale;
+  Inherited Create;
+  FScale := AScale;
 end;
 
-function TScaleXNegateYPointMap.Map(const p: IECPoint): IECPoint;
+function TScaleXNegateYPointMap.Map(const AP: IECPoint): IECPoint;
 begin
-  Result := p.ScaleXNegateY(Fscale);
+  Result := AP.ScaleXNegateY(FScale);
 end;
 
 end.

+ 11 - 29
CryptoLib/src/Math/EC/ClpScaleXPointMap.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpScaleXPointMap;
 
 {$I ..\..\Include\CryptoLib.inc}
@@ -22,40 +15,29 @@ unit ClpScaleXPointMap;
 interface
 
 uses
-  ClpIECC,
-  ClpIScaleXPointMap;
+  ClpIECCore,
+  ClpIECFieldElement;
 
 type
-  TScaleXPointMap = class(TInterfacedObject, IECPointMap, IScaleXPointMap)
-
+  TScaleXPointMap = class(TInterfacedObject, IECPointMap)
   strict protected
-  var
-    Fscale: IECFieldElement;
-
+    FScale: IECFieldElement;
   public
-    constructor Create(const scale: IECFieldElement);
-    destructor Destroy(); override;
-    function Map(const p: IECPoint): IECPoint; virtual;
+    constructor Create(const AScale: IECFieldElement);
+    function Map(const AP: IECPoint): IECPoint; virtual;
   end;
 
 implementation
 
-{ TScaleXPointMap }
-
-constructor TScaleXPointMap.Create(const scale: IECFieldElement);
-begin
-  Inherited Create();
-  Fscale := scale;
-end;
-
-destructor TScaleXPointMap.Destroy;
+constructor TScaleXPointMap.Create(const AScale: IECFieldElement);
 begin
-  inherited Destroy;
+  Inherited Create;
+  FScale := AScale;
 end;
 
-function TScaleXPointMap.Map(const p: IECPoint): IECPoint;
+function TScaleXPointMap.Map(const AP: IECPoint): IECPoint;
 begin
-  Result := p.ScaleX(Fscale);
+  Result := AP.ScaleX(FScale);
 end;
 
 end.

+ 11 - 17
CryptoLib/src/Math/EC/ClpScaleYNegateXPointMap.pas

@@ -13,8 +13,6 @@
 
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpScaleYNegateXPointMap;
 
 {$I ..\..\Include\CryptoLib.inc}
@@ -22,35 +20,31 @@ unit ClpScaleYNegateXPointMap;
 interface
 
 uses
-  ClpIECC,
-  ClpIScaleYNegateXPointMap;
+  ClpIECCore,
+  ClpIECFieldElement;
 
 type
-  TScaleYNegateXPointMap = class(TInterfacedObject, IECPointMap,
-    IScaleYNegateXPointMap)
-
+  TScaleYNegateXPointMap = class(TInterfacedObject, IECPointMap)
   strict protected
-  var
-    Fscale: IECFieldElement;
-
+    FScale: IECFieldElement;
   public
-    constructor Create(const scale: IECFieldElement);
-    function Map(const p: IECPoint): IECPoint; virtual;
+    constructor Create(const AScale: IECFieldElement);
+    function Map(const AP: IECPoint): IECPoint; virtual;
   end;
 
 implementation
 
 { TScaleYNegateXPointMap }
 
-constructor TScaleYNegateXPointMap.Create(const scale: IECFieldElement);
+constructor TScaleYNegateXPointMap.Create(const AScale: IECFieldElement);
 begin
-  Inherited Create();
-  Fscale := scale;
+  Inherited Create;
+  FScale := AScale;
 end;
 
-function TScaleYNegateXPointMap.Map(const p: IECPoint): IECPoint;
+function TScaleYNegateXPointMap.Map(const AP: IECPoint): IECPoint;
 begin
-  Result := p.ScaleYNegateX(Fscale);
+  Result := AP.ScaleYNegateX(FScale);
 end;
 
 end.

+ 23 - 9
CryptoLib/src/Interfaces/Math/EC/ClpIScaleYNegateXPointMap.pas → CryptoLib/src/Math/EC/ClpScaleYPointMap.pas

@@ -13,24 +13,38 @@
 
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+unit ClpScaleYPointMap;
 
-unit ClpIScaleYNegateXPointMap;
-
-{$I ..\..\..\Include\CryptoLib.inc}
+{$I ..\..\Include\CryptoLib.inc}
 
 interface
 
 uses
-  ClpIECC;
+  ClpIECCore,
+  ClpIECFieldElement;
 
 type
-  IScaleYNegateXPointMap = interface(IECPointMap)
-
-    ['{6284EFA2-DE75-437F-86D3-DD93BCAF511B}']
-
+  TScaleYPointMap = class(TInterfacedObject, IECPointMap)
+  strict protected
+    FScale: IECFieldElement;
+  public
+    constructor Create(const AScale: IECFieldElement);
+    function Map(const AP: IECPoint): IECPoint; virtual;
   end;
 
 implementation
 
+{ TScaleYPointMap }
+
+constructor TScaleYPointMap.Create(const AScale: IECFieldElement);
+begin
+  Inherited Create;
+  FScale := AScale;
+end;
+
+function TScaleYPointMap.Map(const AP: IECPoint): IECPoint;
+begin
+  Result := AP.ScaleY(FScale);
+end;
+
 end.

+ 83 - 0
CryptoLib/src/Math/EC/ClpSimpleLookupTable.pas

@@ -0,0 +1,83 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpSimpleLookupTable;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpIECCore,
+  ClpAbstractECLookupTable,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SConstantTimeLookupNotSupported = 'Constant-time lookup not supported';
+
+type
+  TSimpleLookupTable = class(TAbstractECLookupTable, ISimpleLookupTable)
+  strict private
+    FPoints: TCryptoLibGenericArray<IECPoint>;
+
+    class function CopyPoints(const APoints: TCryptoLibGenericArray<IECPoint>; AOff, ALen: Int32)
+      : TCryptoLibGenericArray<IECPoint>; static;
+  public
+    constructor Create(const APoints: TCryptoLibGenericArray<IECPoint>; AOff, ALen: Int32);
+    function GetSize: Int32; override;
+    function Lookup(AIndex: Int32): IECPoint; override;
+    function LookupVar(AIndex: Int32): IECPoint; override;
+  end;
+
+implementation
+
+{ TSimpleLookupTable }
+
+class function TSimpleLookupTable.CopyPoints(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): TCryptoLibGenericArray<IECPoint>;
+var
+  LI: Int32;
+begin
+  System.SetLength(Result, ALen);
+  for LI := 0 to ALen - 1 do
+    Result[LI] := APoints[AOff + LI];
+end;
+
+constructor TSimpleLookupTable.Create(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32);
+begin
+  Inherited Create();
+  FPoints := CopyPoints(APoints, AOff, ALen);
+end;
+
+function TSimpleLookupTable.GetSize: Int32;
+begin
+  Result := System.Length(FPoints);
+end;
+
+function TSimpleLookupTable.Lookup(AIndex: Int32): IECPoint;
+begin
+  raise ENotSupportedCryptoLibException.Create(SConstantTimeLookupNotSupported);
+end;
+
+function TSimpleLookupTable.LookupVar(AIndex: Int32): IECPoint;
+begin
+  Result := FPoints[AIndex];
+end;
+
+end.

+ 20 - 19
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas

@@ -27,12 +27,13 @@ uses
   ClpNat,
   ClpBitOperations,
   ClpNat256,
-  ClpECC,
+  ClpECCurve,
   ClpBigInteger,
   ClpArrayUtilities,
   ClpCryptoLibTypes,
   ClpECCurveConstants,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpISecP256K1Custom;
 
 resourcestring
@@ -93,7 +94,7 @@ type
 
   strict private
 
-    function Equals(const other: ISecP256K1FieldElement): Boolean;
+    function Equals(const AOther: ISecP256K1FieldElement): Boolean;
       reintroduce; overload;
 
     class function GetQ: TBigInteger; static; inline;
@@ -135,7 +136,7 @@ type
     /// </summary>
     function Sqrt(): IECFieldElement; override;
 
-    function Equals(const other: IECFieldElement): Boolean; overload; override;
+    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
 
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -720,25 +721,25 @@ begin
   result := TSecP256K1FieldElement.Create(z);
 end;
 
-function TSecP256K1FieldElement.Equals(const other
-  : ISecP256K1FieldElement): Boolean;
+function TSecP256K1FieldElement.Equals(const AOther: ISecP256K1FieldElement): Boolean;
 begin
-  if ((Self as ISecP256K1FieldElement) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := TNat256.Eq(Fx, other.x);
+  if (Self as ISecP256K1FieldElement) = AOther then
+    Exit(True);
+  if AOther = nil then
+    Exit(False);
+  Result := TNat256.Eq(Fx, AOther.x);
 end;
 
-function TSecP256K1FieldElement.Equals(const other: IECFieldElement): Boolean;
+function TSecP256K1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LSec: ISecP256K1FieldElement;
 begin
-  result := Equals(other as ISecP256K1FieldElement);
+  if AOther = nil then
+    Exit(False);
+  if Supports(AOther, ISecP256K1FieldElement, LSec) then
+    Result := Equals(LSec)
+  else
+    Result := ToBigInteger.Equals(AOther.ToBigInteger);
 end;
 
 { TSecP256K1Point }

+ 20 - 19
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas

@@ -27,12 +27,13 @@ uses
   ClpNat,
   ClpBitOperations,
   ClpNat256,
-  ClpECC,
+  ClpECCurve,
   ClpBigInteger,
   ClpArrayUtilities,
   ClpCryptoLibTypes,
   ClpECCurveConstants,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpISecP256R1Custom;
 
 resourcestring
@@ -94,7 +95,7 @@ type
 
   strict private
 
-    function Equals(const other: ISecP256R1FieldElement): Boolean;
+    function Equals(const AOther: ISecP256R1FieldElement): Boolean;
       reintroduce; overload;
 
     class function GetQ: TBigInteger; static; inline;
@@ -136,7 +137,7 @@ type
     /// </summary>
     function Sqrt(): IECFieldElement; override;
 
-    function Equals(const other: IECFieldElement): Boolean; overload; override;
+    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
 
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -844,25 +845,25 @@ begin
   result := TSecP256R1FieldElement.Create(z);
 end;
 
-function TSecP256R1FieldElement.Equals(const other
-  : ISecP256R1FieldElement): Boolean;
+function TSecP256R1FieldElement.Equals(const AOther: ISecP256R1FieldElement): Boolean;
 begin
-  if ((Self as ISecP256R1FieldElement) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := TNat256.Eq(Fx, other.x);
+  if (Self as ISecP256R1FieldElement) = AOther then
+    Exit(True);
+  if AOther = nil then
+    Exit(False);
+  Result := TNat256.Eq(Fx, AOther.x);
 end;
 
-function TSecP256R1FieldElement.Equals(const other: IECFieldElement): Boolean;
+function TSecP256R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LSec: ISecP256R1FieldElement;
 begin
-  result := Equals(other as ISecP256R1FieldElement);
+  if AOther = nil then
+    Exit(False);
+  if Supports(AOther, ISecP256R1FieldElement, LSec) then
+    Result := Equals(LSec)
+  else
+    Result := ToBigInteger.Equals(AOther.ToBigInteger);
 end;
 
 { TSecP256R1Point }

+ 20 - 19
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas

@@ -27,12 +27,13 @@ uses
   ClpNat,
   ClpBitOperations,
   ClpNat384,
-  ClpECC,
+  ClpECCurve,
   ClpBigInteger,
   ClpArrayUtilities,
   ClpCryptoLibTypes,
   ClpECCurveConstants,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpISecP384R1Custom;
 
 resourcestring
@@ -92,7 +93,7 @@ type
 
   strict private
 
-    function Equals(const other: ISecP384R1FieldElement): Boolean;
+    function Equals(const AOther: ISecP384R1FieldElement): Boolean;
       reintroduce; overload;
 
     class function GetQ: TBigInteger; static; inline;
@@ -134,7 +135,7 @@ type
     /// </summary>
     function Sqrt(): IECFieldElement; override;
 
-    function Equals(const other: IECFieldElement): Boolean; overload; override;
+    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
 
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -847,25 +848,25 @@ begin
   result := TSecP384R1FieldElement.Create(z);
 end;
 
-function TSecP384R1FieldElement.Equals(const other
-  : ISecP384R1FieldElement): Boolean;
+function TSecP384R1FieldElement.Equals(const AOther: ISecP384R1FieldElement): Boolean;
 begin
-  if ((Self as ISecP384R1FieldElement) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := TNat.Eq(12, Fx, other.x);
+  if (Self as ISecP384R1FieldElement) = AOther then
+    Exit(True);
+  if AOther = nil then
+    Exit(False);
+  Result := TNat.Eq(12, Fx, AOther.x);
 end;
 
-function TSecP384R1FieldElement.Equals(const other: IECFieldElement): Boolean;
+function TSecP384R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LSec: ISecP384R1FieldElement;
 begin
-  result := Equals(other as ISecP384R1FieldElement);
+  if AOther = nil then
+    Exit(False);
+  if Supports(AOther, ISecP384R1FieldElement, LSec) then
+    Result := Equals(LSec)
+  else
+    Result := ToBigInteger.Equals(AOther.ToBigInteger);
 end;
 
 { TSecP384R1Point }

+ 20 - 19
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas

@@ -27,10 +27,11 @@ uses
   ClpEncoders,
   ClpBitOperations,
   ClpNat512,
-  ClpECC,
+  ClpECCurve,
   ClpBigInteger,
   ClpArrayUtilities,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes,
   ClpECCurveConstants,
   ClpISecP521R1Custom;
@@ -89,7 +90,7 @@ type
 
   strict private
 
-    function Equals(const other: ISecP521R1FieldElement): Boolean;
+    function Equals(const AOther: ISecP521R1FieldElement): Boolean;
       reintroduce; overload;
 
     class function GetQ: TBigInteger; static; inline;
@@ -131,7 +132,7 @@ type
     /// </summary>
     function Sqrt(): IECFieldElement; override;
 
-    function Equals(const other: IECFieldElement): Boolean; overload; override;
+    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
 
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -645,25 +646,25 @@ begin
   result := TSecP521R1FieldElement.Create(z);
 end;
 
-function TSecP521R1FieldElement.Equals(const other
-  : ISecP521R1FieldElement): Boolean;
+function TSecP521R1FieldElement.Equals(const AOther: ISecP521R1FieldElement): Boolean;
 begin
-  if ((Self as ISecP521R1FieldElement) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := TNat.Eq(17, Fx, other.x);
+  if (Self as ISecP521R1FieldElement) = AOther then
+    Exit(True);
+  if AOther = nil then
+    Exit(False);
+  Result := TNat.Eq(17, Fx, AOther.x);
 end;
 
-function TSecP521R1FieldElement.Equals(const other: IECFieldElement): Boolean;
+function TSecP521R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LSec: ISecP521R1FieldElement;
 begin
-  result := Equals(other as ISecP521R1FieldElement);
+  if AOther = nil then
+    Exit(False);
+  if Supports(AOther, ISecP521R1FieldElement, LSec) then
+    Result := Equals(LSec)
+  else
+    Result := ToBigInteger.Equals(AOther.ToBigInteger);
 end;
 
 { TSecP521R1Point }

+ 20 - 19
CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283Custom.pas

@@ -26,11 +26,12 @@ uses
   ClpEncoders,
   ClpNat,
   ClpNat320,
-  ClpECC,
+  ClpECCurve,
   ClpInterleave,
   ClpBigInteger,
   ClpArrayUtilities,
-  ClpIECC,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpMultipliers,
   ClpCryptoLibTypes,
   ClpECCurveConstants,
@@ -113,7 +114,7 @@ type
     function GetK2: Int32; inline;
     function GetK3: Int32; inline;
 
-    function Equals(const other: ISecT283FieldElement): Boolean;
+    function Equals(const AOther: ISecT283FieldElement): Boolean;
       reintroduce; overload;
 
   strict protected
@@ -169,7 +170,7 @@ type
     /// </summary>
     function Sqrt(): IECFieldElement; override;
 
-    function Equals(const other: IECFieldElement): Boolean; overload; override;
+    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
 
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -857,25 +858,25 @@ begin
   result := Multiply(b.Invert());
 end;
 
-function TSecT283FieldElement.Equals(const other: ISecT283FieldElement)
-  : Boolean;
+function TSecT283FieldElement.Equals(const AOther: ISecT283FieldElement): Boolean;
 begin
-  if ((Self as ISecT283FieldElement) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := TNat320.Eq64(Fx, other.x);
+  if (Self as ISecT283FieldElement) = AOther then
+    Exit(True);
+  if AOther = nil then
+    Exit(False);
+  Result := TNat320.Eq64(Fx, AOther.x);
 end;
 
-function TSecT283FieldElement.Equals(const other: IECFieldElement): Boolean;
+function TSecT283FieldElement.Equals(const AOther: IECFieldElement): Boolean;
+var
+  LSec: ISecT283FieldElement;
 begin
-  result := Equals(other as ISecT283FieldElement);
+  if AOther = nil then
+    Exit(False);
+  if Supports(AOther, ISecT283FieldElement, LSec) then
+    Result := Equals(LSec)
+  else
+    Result := ToBigInteger.Equals(AOther.ToBigInteger);
 end;
 
 function TSecT283FieldElement.GetFieldName: string;

+ 14 - 50
CryptoLib/src/Math/EC/Endo/ClpEndoPreCompInfo.pas

@@ -1,20 +1,3 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpEndoPreCompInfo;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,63 +5,44 @@ unit ClpEndoPreCompInfo;
 interface
 
 uses
-  ClpIECC,
+  ClpIECCore,
   ClpIPreCompInfo,
   ClpIEndoPreCompInfo;
 
 type
-  TEndoPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo,
-    IEndoPreCompInfo)
-
+  TEndoPreCompInfo = class(TInterfacedObject, IPreCompInfo, IEndoPreCompInfo)
   strict private
-  var
     FEndomorphism: IECEndomorphism;
     FMappedPoint: IECPoint;
-
-    function GetEndomorphism: IECEndomorphism; inline;
-    procedure SetEndomorphism(const value: IECEndomorphism); inline;
-
-    function GetMappedPoint: IECPoint; inline;
-    procedure SetMappedPoint(const value: IECPoint); inline;
-
+    function GetEndomorphism: IECEndomorphism;
+    procedure SetEndomorphism(const AValue: IECEndomorphism);
+    function GetMappedPoint: IECPoint;
+    procedure SetMappedPoint(const AValue: IECPoint);
   public
-
-    destructor Destroy; override;
-
-    property Endomorphism: IECEndomorphism read GetEndomorphism
-      write SetEndomorphism;
+    property Endomorphism: IECEndomorphism read GetEndomorphism write SetEndomorphism;
     property MappedPoint: IECPoint read GetMappedPoint write SetMappedPoint;
   end;
 
 implementation
 
-{ TEndoPreCompInfo }
-
-destructor TEndoPreCompInfo.Destroy;
-begin
-  FEndomorphism := nil;
-  FMappedPoint := nil;
-  inherited;
-end;
-
 function TEndoPreCompInfo.GetEndomorphism: IECEndomorphism;
 begin
-  result := FEndomorphism;
+  Result := FEndomorphism;
 end;
 
-function TEndoPreCompInfo.GetMappedPoint: IECPoint;
+procedure TEndoPreCompInfo.SetEndomorphism(const AValue: IECEndomorphism);
 begin
-  result := FMappedPoint;
+  FEndomorphism := AValue;
 end;
 
-procedure TEndoPreCompInfo.SetEndomorphism(const value: IECEndomorphism);
+function TEndoPreCompInfo.GetMappedPoint: IECPoint;
 begin
-  FEndomorphism := value;
+  Result := FMappedPoint;
 end;
 
-procedure TEndoPreCompInfo.SetMappedPoint(const value: IECPoint);
+procedure TEndoPreCompInfo.SetMappedPoint(const AValue: IECPoint);
 begin
-  FMappedPoint := value;
+  FMappedPoint := AValue;
 end;
 
 end.

+ 120 - 0
CryptoLib/src/Math/EC/Endo/ClpEndoUtilities.pas

@@ -0,0 +1,120 @@
+unit ClpEndoUtilities;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBigInteger,
+  ClpIECCore,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpIEndoPreCompInfo,
+  ClpIScalarSplitParameters,
+  ClpEndoPreCompInfo,
+  ClpCryptoLibTypes;
+
+type
+  TEndoUtilities = class sealed(TObject)
+  public
+    const PRECOMP_NAME = 'bc_endo';
+    class function DecomposeScalar(const AP: IScalarSplitParameters;
+      const AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>; static;
+    class function MapPoint(const AEndomorphism: IECEndomorphism;
+      const AP: IECPoint): IECPoint; static;
+  private
+    class function CalculateB(const AK, AG: TBigInteger;
+      AT: Int32): TBigInteger; static;
+  end;
+
+implementation
+
+type
+  TMapPointCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FEndomorphism: IECEndomorphism;
+    FPoint: IECPoint;
+    function CheckExisting(const AExistingEndo: IEndoPreCompInfo;
+      const AEndomorphism: IECEndomorphism): Boolean;
+  public
+    constructor Create(const AEndomorphism: IECEndomorphism; const APoint: IECPoint);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TMapPointCallback.Create(const AEndomorphism: IECEndomorphism;
+  const APoint: IECPoint);
+begin
+  inherited Create;
+  FEndomorphism := AEndomorphism;
+  FPoint := APoint;
+end;
+
+function TMapPointCallback.CheckExisting(const AExistingEndo: IEndoPreCompInfo;
+  const AEndomorphism: IECEndomorphism): Boolean;
+begin
+  Result := (AExistingEndo <> nil) and (AExistingEndo.Endomorphism = AEndomorphism) and
+    (AExistingEndo.MappedPoint <> nil);
+end;
+
+function TMapPointCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+var
+  LExistingEndo: IEndoPreCompInfo;
+  LResult: TEndoPreCompInfo;
+begin
+  if Supports(AExisting, IEndoPreCompInfo, LExistingEndo) and
+    CheckExisting(LExistingEndo, FEndomorphism) then
+    Exit(LExistingEndo);
+
+  LResult := TEndoPreCompInfo.Create;
+  LResult.Endomorphism := FEndomorphism;
+  LResult.MappedPoint := FEndomorphism.PointMap.Map(FPoint);
+  Result := LResult;
+end;
+
+class function TEndoUtilities.CalculateB(const AK, AG: TBigInteger;
+  AT: Int32): TBigInteger;
+var
+  LNegative: Boolean;
+  LB: TBigInteger;
+  LExtra: Boolean;
+begin
+  LNegative := AG.SignValue < 0;
+  LB := AK.Multiply(AG.Abs());
+  LExtra := LB.TestBit(AT - 1);
+  LB := LB.ShiftRight(AT);
+  if LExtra then
+    LB := LB.Add(TBigInteger.One);
+  if LNegative then
+    Result := LB.Negate()
+  else
+    Result := LB;
+end;
+
+class function TEndoUtilities.DecomposeScalar(const AP: IScalarSplitParameters;
+  const AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
+var
+  LBits: Int32;
+  LB1, LB2, LA, LB: TBigInteger;
+begin
+  LBits := AP.Bits;
+  LB1 := CalculateB(AK, AP.G1, LBits);
+  LB2 := CalculateB(AK, AP.G2, LBits);
+  LA := AK.Subtract((LB1.Multiply(AP.V1A)).Add(LB2.Multiply(AP.V2A)));
+  LB := (LB1.Multiply(AP.V1B)).Add(LB2.Multiply(AP.V2B)).Negate();
+  Result := TCryptoLibGenericArray<TBigInteger>.Create(LA, LB);
+end;
+
+class function TEndoUtilities.MapPoint(const AEndomorphism: IECEndomorphism;
+  const AP: IECPoint): IECPoint;
+var
+  LPrecomp: IPreCompInfo;
+  LEndo: IEndoPreCompInfo;
+begin
+  LPrecomp := AP.Curve.Precompute(AP, PRECOMP_NAME,
+    TMapPointCallback.Create(AEndomorphism, AP) as IPreCompCallback);
+  if not Supports(LPrecomp, IEndoPreCompInfo, LEndo) then
+    raise EInvalidCastCryptoLibException.Create('Expected EndoPreCompInfo');
+  Result := LEndo.MappedPoint;
+end;
+
+end.

+ 0 - 92
CryptoLib/src/Math/EC/Endo/ClpGlvTypeAEndomorphism.pas

@@ -1,92 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpGlvTypeAEndomorphism;
-
-{$I ..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpCryptoLibTypes,
-  ClpBigInteger,
-  ClpECCompUtilities,
-  ClpScaleYNegateXPointMap,
-  ClpIGlvTypeAEndomorphism,
-  ClpIECC,
-  ClpIGlvTypeAParameters,
-  ClpIGlvEndomorphism;
-
-type
-  TGlvTypeAEndomorphism = class(TInterfacedObject, IECEndomorphism,
-    IGlvEndomorphism, IGlvTypeAEndomorphism)
-
-  strict private
-    function GetHasEfficientPointMap: Boolean; virtual;
-    function GetPointMap: IECPointMap; virtual;
-
-  strict protected
-  var
-    FParameters: IGlvTypeAParameters;
-    FPointMap: IECPointMap;
-
-  public
-    constructor Create(const curve: IECCurve;
-      const parameters: IGlvTypeAParameters);
-
-    function DecomposeScalar(const k: TBigInteger)
-      : TCryptoLibGenericArray<TBigInteger>; virtual;
-
-    property PointMap: IECPointMap read GetPointMap;
-    property HasEfficientPointMap: Boolean read GetHasEfficientPointMap;
-  end;
-
-implementation
-
-{ TGlvTypeAEndomorphism }
-
-constructor TGlvTypeAEndomorphism.Create(const curve: IECCurve;
-  const parameters: IGlvTypeAParameters);
-begin
-  Inherited Create();
-  (*
-    * NOTE: 'curve' MUST only be used to create a suitable ECFieldElement. Due to the way
-    * ECCurve configuration works, 'curve' will not be the actual instance of ECCurve that the
-    * endomorphism is being used with.
-  *)
-  FParameters := parameters;
-  FPointMap := TScaleYNegateXPointMap.Create
-    (curve.FromBigInteger(parameters.I));
-end;
-
-function TGlvTypeAEndomorphism.DecomposeScalar(const k: TBigInteger)
-  : TCryptoLibGenericArray<TBigInteger>;
-begin
-  Result := TEndoUtilities.DecomposeScalar(FParameters.SplitParams, k);
-end;
-
-function TGlvTypeAEndomorphism.GetHasEfficientPointMap: Boolean;
-begin
-  Result := true;
-end;
-
-function TGlvTypeAEndomorphism.GetPointMap: IECPointMap;
-begin
-  Result := FPointMap;
-end;
-
-end.

+ 0 - 80
CryptoLib/src/Math/EC/Endo/ClpGlvTypeAParameters.pas

@@ -1,80 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpGlvTypeAParameters;
-
-{$I ..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpBigInteger,
-  ClpIGlvTypeAParameters,
-  ClpIScalarSplitParameters;
-
-type
-  TGlvTypeAParameters = class sealed(TInterfacedObject, IGlvTypeAParameters)
-
-  strict private
-  var
-    FI, Flambda: TBigInteger;
-    FsplitParams: IScalarSplitParameters;
-
-    function GetLambda: TBigInteger; inline;
-    function GetI: TBigInteger; inline;
-    function GetSplitParams: IScalarSplitParameters; inline;
-
-  public
-
-    constructor Create(const I, lambda: TBigInteger;
-      const splitParams: IScalarSplitParameters);
-
-    property lambda: TBigInteger read GetLambda;
-    property I: TBigInteger read GetI;
-    property splitParams: IScalarSplitParameters read GetSplitParams;
-
-  end;
-
-implementation
-
-{ TGlvTypeAParameters }
-
-constructor TGlvTypeAParameters.Create(const I, lambda: TBigInteger;
-  const splitParams: IScalarSplitParameters);
-begin
-  Inherited Create();
-  FI := I;
-  Flambda := lambda;
-  FsplitParams := splitParams;
-end;
-
-function TGlvTypeAParameters.GetI: TBigInteger;
-begin
-  Result := FI;
-end;
-
-function TGlvTypeAParameters.GetLambda: TBigInteger;
-begin
-  Result := Flambda;
-end;
-
-function TGlvTypeAParameters.GetSplitParams: IScalarSplitParameters;
-begin
-  Result := FsplitParams;
-end;
-
-end.

+ 28 - 45
CryptoLib/src/Math/EC/Endo/ClpGlvTypeBEndomorphism.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpGlvTypeBEndomorphism;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,70 +15,60 @@ unit ClpGlvTypeBEndomorphism;
 interface
 
 uses
-  ClpCryptoLibTypes,
   ClpBigInteger,
-  ClpScaleXPointMap,
-  ClpIGlvTypeBEndomorphism,
-  ClpIECC,
+  ClpIECCore,
   ClpIGlvTypeBParameters,
-  ClpIGlvEndomorphism,
-  ClpECCompUtilities;
+  ClpIGlvTypeBEndomorphism,
+  ClpCryptoLibTypes;
 
 type
-  TGlvTypeBEndomorphism = class(TInterfacedObject, IECEndomorphism,
-    IGlvEndomorphism, IGlvTypeBEndomorphism)
-
+  TGlvTypeBEndomorphism = class(TInterfacedObject, IECEndomorphism, IGlvEndomorphism, IGlvTypeBEndomorphism)
   strict private
-    function GetHasEfficientPointMap: Boolean; virtual;
-    function GetPointMap: IECPointMap; virtual;
-
-  strict protected
-  var
     FParameters: IGlvTypeBParameters;
     FPointMap: IECPointMap;
-
   public
-    constructor Create(const curve: IECCurve;
-      const parameters: IGlvTypeBParameters);
-
-    function DecomposeScalar(const k: TBigInteger)
-      : TCryptoLibGenericArray<TBigInteger>; virtual;
-
+    constructor Create(const ACurve: IECCurve; const AParameters: IGlvTypeBParameters);
+    function DecomposeScalar(const AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
+    function GetPointMap: IECPointMap;
+    function GetHasEfficientPointMap: Boolean;
     property PointMap: IECPointMap read GetPointMap;
     property HasEfficientPointMap: Boolean read GetHasEfficientPointMap;
   end;
 
 implementation
 
+uses
+  ClpEndoUtilities,
+  ClpScaleXPointMap;
+
 { TGlvTypeBEndomorphism }
 
-constructor TGlvTypeBEndomorphism.Create(const curve: IECCurve;
-  const parameters: IGlvTypeBParameters);
+constructor TGlvTypeBEndomorphism.Create(const ACurve: IECCurve;
+  const AParameters: IGlvTypeBParameters);
 begin
-  Inherited Create();
-  (*
-    * NOTE: 'curve' MUST only be used to create a suitable ECFieldElement. Due to the way
-    * ECCurve configuration works, 'curve' will not be the actual instance of ECCurve that the
-    * endomorphism is being used with.
-  *)
-  FParameters := parameters;
-  FPointMap := TScaleXPointMap.Create(curve.FromBigInteger(parameters.Beta));
+  inherited Create;
+  {
+    NOTE: 'curve' MUST only be used to create a suitable ECFieldElement. Due to the way
+    ECCurve configuration works, 'curve' will not be the actual instance of ECCurve that the
+    endomorphism is being used with.
+  }
+  FParameters := AParameters;
+  FPointMap := TScaleXPointMap.Create(ACurve.FromBigInteger(AParameters.Beta));
 end;
 
-function TGlvTypeBEndomorphism.DecomposeScalar(const k: TBigInteger)
-  : TCryptoLibGenericArray<TBigInteger>;
+function TGlvTypeBEndomorphism.DecomposeScalar(const AK: TBigInteger): TCryptoLibGenericArray<TBigInteger>;
 begin
-  Result := TEndoUtilities.DecomposeScalar(FParameters.SplitParams, k);
+  Result := TEndoUtilities.DecomposeScalar(FParameters.SplitParams, AK);
 end;
 
-function TGlvTypeBEndomorphism.GetHasEfficientPointMap: Boolean;
+function TGlvTypeBEndomorphism.GetPointMap: IECPointMap;
 begin
-  Result := true;
+  Result := FPointMap;
 end;
 
-function TGlvTypeBEndomorphism.GetPointMap: IECPointMap;
+function TGlvTypeBEndomorphism.GetHasEfficientPointMap: Boolean;
 begin
-  Result := FPointMap;
+  Result := True;
 end;
 
 end.

+ 22 - 36
CryptoLib/src/Math/EC/Endo/ClpGlvTypeBParameters.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpGlvTypeBParameters;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -23,58 +16,51 @@ interface
 
 uses
   ClpBigInteger,
-  ClpIGlvTypeBParameters,
-  ClpIScalarSplitParameters;
+  ClpIScalarSplitParameters,
+  ClpIGlvTypeBParameters;
 
 type
-  TGlvTypeBParameters = class sealed(TInterfacedObject, IGlvTypeBParameters)
-
+  TGlvTypeBParameters = class(TInterfacedObject, IGlvTypeBParameters)
   strict private
-  var
-    Fbeta, Flambda: TBigInteger;
-    FsplitParams: IScalarSplitParameters;
-
-    function GetLambda: TBigInteger; inline;
-    function GetBeta: TBigInteger; inline;
-    function GetSplitParams: IScalarSplitParameters; inline;
-
+    FBeta, FLambda: TBigInteger;
+    FSplitParams: IScalarSplitParameters;
+    function GetBeta: TBigInteger;
+    function GetLambda: TBigInteger;
+    function GetSplitParams: IScalarSplitParameters;
   public
-
-    constructor Create(const beta, lambda: TBigInteger;
-      const splitParams: IScalarSplitParameters);
-
-    property lambda: TBigInteger read GetLambda;
-    property beta: TBigInteger read GetBeta;
-    property splitParams: IScalarSplitParameters read GetSplitParams;
-
+    constructor Create(const ABeta, ALambda: TBigInteger;
+      const ASplitParams: IScalarSplitParameters);
+    property Beta: TBigInteger read GetBeta;
+    property Lambda: TBigInteger read GetLambda;
+    property SplitParams: IScalarSplitParameters read GetSplitParams;
   end;
 
 implementation
 
 { TGlvTypeBParameters }
 
-constructor TGlvTypeBParameters.Create(const beta, lambda: TBigInteger;
-  const splitParams: IScalarSplitParameters);
+constructor TGlvTypeBParameters.Create(const ABeta, ALambda: TBigInteger;
+  const ASplitParams: IScalarSplitParameters);
 begin
-  Inherited Create();
-  Fbeta := beta;
-  Flambda := lambda;
-  FsplitParams := splitParams;
+  inherited Create;
+  FBeta := ABeta;
+  FLambda := ALambda;
+  FSplitParams := ASplitParams;
 end;
 
 function TGlvTypeBParameters.GetBeta: TBigInteger;
 begin
-  Result := Fbeta;
+  Result := FBeta;
 end;
 
 function TGlvTypeBParameters.GetLambda: TBigInteger;
 begin
-  Result := Flambda;
+  Result := FLambda;
 end;
 
 function TGlvTypeBParameters.GetSplitParams: IScalarSplitParameters;
 begin
-  Result := FsplitParams;
+  Result := FSplitParams;
 end;
 
 end.

+ 47 - 66
CryptoLib/src/Math/EC/Endo/ClpScalarSplitParameters.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpScalarSplitParameters;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -26,106 +19,94 @@ uses
   ClpIScalarSplitParameters,
   ClpCryptoLibTypes;
 
-resourcestring
-  SInvalidParameters = '"%s" must consist of exactly 2 (initialized) values';
-
 type
-  TScalarSplitParameters = class sealed(TInterfacedObject,
-    IScalarSplitParameters)
-
+  TScalarSplitParameters = class(TInterfacedObject, IScalarSplitParameters)
   strict private
-    function GetG1: TBigInteger; inline;
-    function GetG2: TBigInteger; inline;
-    function GetV1A: TBigInteger; inline;
-    function GetV1B: TBigInteger; inline;
-    function GetV2A: TBigInteger; inline;
-    function GetV2B: TBigInteger; inline;
-    function GetBits: Int32; inline;
-
-    class procedure CheckVector(const v: TCryptoLibGenericArray<TBigInteger>;
-      const name: String); static;
-
-  strict protected
-    Fg1, Fg2, Fv1A, Fv1B, Fv2A, Fv2B: TBigInteger;
-    Fbits: Int32;
-
+    FV1A, FV1B, FV2A, FV2B, FG1, FG2: TBigInteger;
+    FBits: Int32;
+    function GetV1A: TBigInteger;
+    function GetV1B: TBigInteger;
+    function GetV2A: TBigInteger;
+    function GetV2B: TBigInteger;
+    function GetG1: TBigInteger;
+    function GetG2: TBigInteger;
+    function GetBits: Int32;
+  private
+    class procedure CheckVector(const AV: TCryptoLibGenericArray<TBigInteger>;
+      const AName: String); static;
   public
-    constructor Create(const v1, v2: TCryptoLibGenericArray<TBigInteger>;
-      const g1, g2: TBigInteger; bits: Int32);
-
-    property g1: TBigInteger read GetG1;
-    property g2: TBigInteger read GetG2;
+    constructor Create(const AV1, AV2: TCryptoLibGenericArray<TBigInteger>;
+      const AG1, AG2: TBigInteger; ABits: Int32);
     property V1A: TBigInteger read GetV1A;
     property V1B: TBigInteger read GetV1B;
     property V2A: TBigInteger read GetV2A;
     property V2B: TBigInteger read GetV2B;
-    property bits: Int32 read GetBits;
-
+    property G1: TBigInteger read GetG1;
+    property G2: TBigInteger read GetG2;
+    property Bits: Int32 read GetBits;
   end;
 
 implementation
 
 { TScalarSplitParameters }
 
-class procedure TScalarSplitParameters.CheckVector
-  (const v: TCryptoLibGenericArray<TBigInteger>; const name: String);
+class procedure TScalarSplitParameters.CheckVector(
+  const AV: TCryptoLibGenericArray<TBigInteger>; const AName: String);
 begin
-  if ((v = Nil) or (System.length(v) <> 2) or (not v[0].IsInitialized) or
-    (not v[1].IsInitialized)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt(@SInvalidParameters, [name]);
-  end;
+  if (AV = nil) or (System.Length(AV) <> 2) or (not AV[0].IsInitialized) or
+    (not AV[1].IsInitialized) then
+    raise EArgumentCryptoLibException.Create('Must consist of exactly 2 (non-null) values: ' + AName);
 end;
 
-constructor TScalarSplitParameters.Create(const v1,
-  v2: TCryptoLibGenericArray<TBigInteger>; const g1, g2: TBigInteger;
-  bits: Int32);
+constructor TScalarSplitParameters.Create(const AV1,
+  AV2: TCryptoLibGenericArray<TBigInteger>; const AG1, AG2: TBigInteger;
+  ABits: Int32);
+begin
+  Inherited Create;
+  CheckVector(AV1, 'v1');
+  CheckVector(AV2, 'v2');
+  FV1A := AV1[0];
+  FV1B := AV1[1];
+  FV2A := AV2[0];
+  FV2B := AV2[1];
+  FG1 := AG1;
+  FG2 := AG2;
+  FBits := ABits;
+end;
+
+function TScalarSplitParameters.GetBits: Int32;
 begin
-  CheckVector(v1, 'v1');
-  CheckVector(v2, 'v2');
-
-  Fv1A := v1[0];
-  Fv1B := v1[1];
-  Fv2A := v2[0];
-  Fv2B := v2[1];
-  Fg1 := g1;
-  Fg2 := g2;
-  Fbits := bits;
+  Result := FBits;
 end;
 
 function TScalarSplitParameters.GetG1: TBigInteger;
 begin
-  Result := Fg1;
+  Result := FG1;
 end;
 
 function TScalarSplitParameters.GetG2: TBigInteger;
 begin
-  Result := Fg2;
+  Result := FG2;
 end;
 
 function TScalarSplitParameters.GetV1A: TBigInteger;
 begin
-  Result := Fv1A;
+  Result := FV1A;
 end;
 
 function TScalarSplitParameters.GetV1B: TBigInteger;
 begin
-  Result := Fv1B;
+  Result := FV1B;
 end;
 
 function TScalarSplitParameters.GetV2A: TBigInteger;
 begin
-  Result := Fv2A;
+  Result := FV2A;
 end;
 
 function TScalarSplitParameters.GetV2B: TBigInteger;
 begin
-  Result := Fv2B;
-end;
-
-function TScalarSplitParameters.GetBits: Int32;
-begin
-  Result := Fbits;
+  Result := FV2B;
 end;
 
 end.

+ 27 - 66
CryptoLib/src/Math/EC/Multiplier/ClpFixedPointPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpFixedPointPreCompInfo;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,100 +15,68 @@ unit ClpFixedPointPreCompInfo;
 interface
 
 uses
-  ClpIECC,
+  ClpIECCore,
+  ClpIPreCompInfo,
   ClpIFixedPointPreCompInfo,
-  ClpIPreCompInfo;
+  ClpCryptoLibTypes;
 
 type
-
-  /// <summary>
-  /// Class holding precomputation data for fixed-point multiplications.
-  /// </summary>
-  TFixedPointPreCompInfo = class(TInterfacedObject, IPreCompInfo,
+  TFixedPointPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo,
     IFixedPointPreCompInfo)
-
   strict private
-    function GetWidth: Int32;
-    procedure SetWidth(const Value: Int32);
-
+    FLookupTable: IECLookupTable;
+    FOffset: IECPoint;
+    FWidth: Int32;
     function GetLookupTable: IECLookupTable;
-    procedure SetLookupTable(const Value: IECLookupTable);
-
+  public
+    constructor Create;
+    procedure SetLookupTable(const AValue: IECLookupTable);
     function GetOffset: IECPoint;
-    procedure SetOffset(const Value: IECPoint);
-
-  strict protected
-  var
-    Fm_offset: IECPoint;
-
-    /// <summary>
-    /// Array holding the precomputed <c>ECPoint</c>s used for a fixed point
-    /// multiplication.
-    /// </summary>
-    Fm_lookupTable: IECLookupTable;
-
-    /// <summary>
-    /// The width used for the precomputation. If a larger width
-    /// precomputation is already available this may be larger than was
-    /// requested, so calling code should refer to the actual width.
-    /// </summary>
-    Fm_width: Int32;
-
+    procedure SetOffset(const AValue: IECPoint);
+    function GetWidth: Int32;
+    procedure SetWidth(AValue: Int32);
   public
-    constructor Create();
-    destructor Destroy; override;
+    property LookupTable: IECLookupTable read GetLookupTable write SetLookupTable;
     property Offset: IECPoint read GetOffset write SetOffset;
-    property LookupTable: IECLookupTable read GetLookupTable
-      write SetLookupTable;
     property Width: Int32 read GetWidth write SetWidth;
-
   end;
 
 implementation
 
-{ TFixedPointPreCompInfo }
-
 constructor TFixedPointPreCompInfo.Create;
 begin
-  inherited Create();
-  Fm_width := -1;
-end;
-
-destructor TFixedPointPreCompInfo.Destroy;
-begin
-  Fm_offset := nil;
-  Fm_lookupTable := nil;
-  inherited;
+  Inherited Create;
+  FWidth := -1;
 end;
 
 function TFixedPointPreCompInfo.GetLookupTable: IECLookupTable;
 begin
-  Result := Fm_lookupTable;
+  Result := FLookupTable;
 end;
 
-function TFixedPointPreCompInfo.GetOffset: IECPoint;
+procedure TFixedPointPreCompInfo.SetLookupTable(const AValue: IECLookupTable);
 begin
-  Result := Fm_offset;
+  FLookupTable := AValue;
 end;
 
-function TFixedPointPreCompInfo.GetWidth: Int32;
+function TFixedPointPreCompInfo.GetOffset: IECPoint;
 begin
-  Result := Fm_width;
+  Result := FOffset;
 end;
 
-procedure TFixedPointPreCompInfo.SetLookupTable(const Value: IECLookupTable);
+procedure TFixedPointPreCompInfo.SetOffset(const AValue: IECPoint);
 begin
-  Fm_lookupTable := Value;
+  FOffset := AValue;
 end;
 
-procedure TFixedPointPreCompInfo.SetOffset(const Value: IECPoint);
+function TFixedPointPreCompInfo.GetWidth: Int32;
 begin
-  Fm_offset := Value;
+  Result := FWidth;
 end;
 
-procedure TFixedPointPreCompInfo.SetWidth(const Value: Int32);
+procedure TFixedPointPreCompInfo.SetWidth(AValue: Int32);
 begin
-  Fm_width := Value;
+  FWidth := AValue;
 end;
 
 end.

+ 159 - 0
CryptoLib/src/Math/EC/Multiplier/ClpFixedPointUtilities.pas

@@ -0,0 +1,159 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ * ******************************************************************************* * }
+
+unit ClpFixedPointUtilities;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBigInteger,
+  ClpIECCore,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpIFixedPointPreCompInfo,
+  ClpCryptoLibTypes;
+
+type
+  TFixedPointUtilities = class sealed(TObject)
+  public
+    const PRECOMP_NAME = 'bc_fixed_point';
+    class function GetCombSize(const AC: IECCurve): Int32; static;
+    class function GetFixedPointPreCompInfo(const APreCompInfo: IPreCompInfo): IFixedPointPreCompInfo; static;
+    class function Precompute(const AP: IECPoint): IFixedPointPreCompInfo; static;
+  end;
+
+implementation
+
+uses
+  ClpFixedPointPreCompInfo,
+  ClpECCurve,
+  ClpCryptoLibTypes;
+
+type
+  TFixedPointCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FP: IECPoint;
+    function CheckExisting(const AExistingFP: IFixedPointPreCompInfo; AN: Int32): Boolean;
+    function CheckTable(const ATable: IECLookupTable; AN: Int32): Boolean;
+  public
+    constructor Create(const AP: IECPoint);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TFixedPointCallback.Create(const AP: IECPoint);
+begin
+  Inherited Create;
+  FP := AP;
+end;
+
+function TFixedPointCallback.CheckTable(const ATable: IECLookupTable; AN: Int32): Boolean;
+begin
+  Result := (ATable <> nil) and (ATable.Size >= AN);
+end;
+
+function TFixedPointCallback.CheckExisting(const AExistingFP: IFixedPointPreCompInfo; AN: Int32): Boolean;
+begin
+  Result := (AExistingFP <> nil) and CheckTable(AExistingFP.LookupTable, AN);
+end;
+
+function TFixedPointCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+var
+  LExistingFP: IFixedPointPreCompInfo;
+  LC: IECCurve;
+  LBits, LMinWidth, LN, LD, LBit, LStep, LI: Int32;
+  LPow2Table, LLookupTable: TCryptoLibGenericArray<IECPoint>;
+  LPow2: IECPoint;
+  LResult: TFixedPointPreCompInfo;
+begin
+  if not Supports(AExisting, IFixedPointPreCompInfo, LExistingFP) then
+    LExistingFP := nil;
+
+  LC := FP.Curve;
+  LBits := TFixedPointUtilities.GetCombSize(LC);
+  if LBits > 250 then
+    LMinWidth := 6
+  else
+    LMinWidth := 5;
+  LN := 1 shl LMinWidth;
+
+  if CheckExisting(LExistingFP, LN) then
+    Exit(LExistingFP);
+
+  LD := (LBits + LMinWidth - 1) div LMinWidth;
+
+  System.SetLength(LPow2Table, LMinWidth + 1);
+  LPow2Table[0] := FP;
+  for LI := 1 to LMinWidth - 1 do
+    LPow2Table[LI] := LPow2Table[LI - 1].TimesPow2(LD);
+  LPow2Table[LMinWidth] := LPow2Table[0].Subtract(LPow2Table[1]);
+
+  LC.NormalizeAll(LPow2Table);
+
+  System.SetLength(LLookupTable, LN);
+  LLookupTable[0] := LPow2Table[0];
+
+  for LBit := LMinWidth - 1 downto 0 do
+  begin
+    LPow2 := LPow2Table[LBit];
+    LStep := 1 shl LBit;
+    LI := LStep;
+    while LI < LN do
+    begin
+      LLookupTable[LI] := LLookupTable[LI - LStep].Add(LPow2);
+      LI := LI + (LStep shl 1);
+    end;
+  end;
+
+  LC.NormalizeAll(LLookupTable);
+
+  LResult := TFixedPointPreCompInfo.Create;
+  LResult.LookupTable := LC.CreateCacheSafeLookupTable(LLookupTable, 0, System.Length(LLookupTable));
+  LResult.Offset := LPow2Table[LMinWidth];
+  LResult.Width := LMinWidth;
+  Result := LResult;
+end;
+
+class function TFixedPointUtilities.GetCombSize(const AC: IECCurve): Int32;
+var
+  LOrder: TBigInteger;
+begin
+  LOrder := AC.Order;
+  if not LOrder.IsInitialized then
+    Result := AC.FieldSize + 1
+  else
+    Result := LOrder.BitLength;
+end;
+
+class function TFixedPointUtilities.GetFixedPointPreCompInfo(const APreCompInfo: IPreCompInfo): IFixedPointPreCompInfo;
+var
+  LFP: IFixedPointPreCompInfo;
+begin
+  if Supports(APreCompInfo, IFixedPointPreCompInfo, LFP) then
+    Result := LFP
+  else
+    Result := nil;
+end;
+
+class function TFixedPointUtilities.Precompute(const AP: IECPoint): IFixedPointPreCompInfo;
+var
+  LPrecomp: IPreCompInfo;
+  LFP: IFixedPointPreCompInfo;
+begin
+  LPrecomp := AP.Curve.Precompute(AP, PRECOMP_NAME,
+    TFixedPointCallback.Create(AP) as IPreCompCallback);
+  if Supports(LPrecomp, IFixedPointPreCompInfo, LFP) then
+    Result := LFP
+  else
+    Result := nil;
+end;
+
+end.

+ 259 - 487
CryptoLib/src/Math/EC/Multiplier/ClpMultipliers.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpMultipliers;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,596 +15,375 @@ unit ClpMultipliers;
 interface
 
 uses
-  SysUtils,
   ClpBigInteger,
-  ClpBitOperations,
-  ClpNat,
-  ClpTnaf,
-  ClpIECC,
-  ClpIGlvEndomorphism,
-  ClpIFixedPointPreCompInfo,
-  ClpIWTauNafPreCompInfo,
-  ClpWTauNafPreCompInfo,
+  ClpIECCore,
+  ClpIECFieldElement,
   ClpIZTauElement,
-  ClpIPreCompInfo,
-  ClpIPreCompCallBack,
-  ClpIMultipliers,
   ClpIWNafPreCompInfo,
-  ClpECCompUtilities,
-  ClpWeakRef,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpWNafUtilities,
   ClpCryptoLibTypes;
 
-resourcestring
-  SInvalidComputation =
-    'Fixed-Point Comb Doesn''t Support Scalars Larger Than The Curve Order';
-  SCurveUnknownGroupOrder = 'Need Curve With Known Group Order, "curve"';
-  SInCompatiblePoint = 'Only AbstractF2mPoint can be used in WTauNafMultiplier';
-
 type
-  TAbstractECMultiplier = class abstract(TInterfacedObject,
-    IAbstractECMultiplier, IECMultiplier)
-
+  TAbstractECMultiplier = class abstract(TInterfacedObject, IECMultiplier)
   strict protected
-
-    function CheckResult(const p: IECPoint): IECPoint; virtual;
-    function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
-      : IECPoint; virtual; abstract;
-
+    function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; virtual; abstract;
+    function CheckResult(const AP: IECPoint): IECPoint; virtual;
   public
-
-    constructor Create();
-    function Multiply(const p: IECPoint; const k: TBigInteger)
-      : IECPoint; virtual;
-
+    function Multiply(const APoint: IECPoint; const AK: TBigInteger): IECPoint; virtual;
   end;
 
-type
-  TFixedPointCombMultiplier = class sealed(TAbstractECMultiplier,
-    IFixedPointCombMultiplier)
-
+  TWNafL2RMultiplier = class sealed(TAbstractECMultiplier, IECMultiplier, IWNafL2RMultiplier)
   strict protected
-    function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
-      : IECPoint; override;
-
-  public
-    constructor Create();
-
+    function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; override;
   end;
 
-type
-  TGlvMultiplier = class(TAbstractECMultiplier, IGlvMultiplier)
-
+  TGlvMultiplier = class sealed(TAbstractECMultiplier, IECMultiplier)
   strict protected
-  var
-    Fcurve: TWeakRef<IECCurve>;
-    FglvEndomorphism: IGlvEndomorphism;
-
-    function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
-      : IECPoint; override;
-
+    FCurve: IECCurve;
+    FGlvEndomorphism: IGlvEndomorphism;
+    function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; override;
   public
-    constructor Create(const curve: IECCurve;
-      const glvEndomorphism: IGlvEndomorphism);
-    destructor Destroy; override;
-
+    constructor Create(const ACurve: IECCurve; const AGlvEndomorphism: IGlvEndomorphism);
   end;
 
-type
-
-  /// <summary>
-  /// Class implementing the WNAF (Window Non-Adjacent Form) multiplication
-  /// algorithm.
-  /// </summary>
-  TWNafL2RMultiplier = class(TAbstractECMultiplier, IWNafL2RMultiplier)
-
+  TWTauNafMultiplier = class sealed(TAbstractECMultiplier, IECMultiplier)
+  strict private
+    class var PRECOMP_NAME: String;
+    function MultiplyWTnaf(const AP: IAbstractF2mPoint; const ALambda: IZTauElement;
+      AA, AMu: ShortInt): IAbstractF2mPoint;
+    class function MultiplyFromWTnaf(const AP: IAbstractF2mPoint;
+      const AU: TCryptoLibShortIntArray): IAbstractF2mPoint; static;
   strict protected
-    // /**
-    // * Multiplies <code>this</code> by an integer <code>k</code> using the
-    // * Window NAF method.
-    // * @param k The integer by which <code>this</code> is multiplied.
-    // * @return A new <code>ECPoint</code> which equals <code>this</code>
-    // * multiplied by <code>k</code>.
-    // */
-    function MultiplyPositive(const p: IECPoint; const k: TBigInteger)
-      : IECPoint; override;
-
+    function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; override;
   public
-
-    constructor Create();
-
+    class constructor Create;
   end;
 
-type
-  /// **
-  // * Class implementing the WTNAF (Window
-  // * <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
-  // */
-  TWTauNafMultiplier = class(TAbstractECMultiplier, IWTauNafMultiplier)
-
-  strict private
-    // TODO Create WTauNafUtilities class and move various functionality into it
-
-  type
-    IWTauNafCallback = interface(IPreCompCallback)
-      ['{4D6F7B4A-B925-42C9-8D60-B7F24632EDC1}']
-
-    end;
-
-  type
-    TWTauNafCallback = class(TInterfacedObject, IPreCompCallback,
-      IWTauNafCallback)
-
-    strict private
-    var
-      Fm_p: IAbstractF2mPoint;
-      Fm_a: ShortInt;
-
-    public
-      constructor Create(const p: IAbstractF2mPoint; a: ShortInt);
-
-      function Precompute(const existing: IPreCompInfo): IPreCompInfo;
-
-    end;
-
-  const
-    PRECOMP_NAME: String = 'bc_wtnaf';
-
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code> using
-    // * the <code>&#964;</code>-adic NAF (TNAF) method.
-    // * @param p The AbstractF2mPoint to multiply.
-    // * @param lambda The element <code>&#955;</code> of
-    // * <code><b>Z</b>[&#964;]</code> of which to compute the
-    // * <code>[&#964;]</code>-adic NAF.
-    // * @return <code>p</code> multiplied by <code>&#955;</code>.
-    // */
-    function MultiplyWTnaf(const p: IAbstractF2mPoint;
-      const lambda: IZTauElement; a, mu: ShortInt): IAbstractF2mPoint; inline;
-
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
-    // * using the window <code>&#964;</code>-adic NAF (TNAF) method, given the
-    // * WTNAF of <code>&#955;</code>.
-    // * @param p The AbstractF2mPoint to multiply.
-    // * @param u The the WTNAF of <code>&#955;</code>..
-    // * @return <code>&#955; * p</code>
-    // */
-    class function MultiplyFromWTnaf(const p: IAbstractF2mPoint;
-      const u: TCryptoLibShortIntArray): IAbstractF2mPoint; static;
-
+  TFixedPointCombMultiplier = class sealed(TAbstractECMultiplier, IECMultiplier)
   strict protected
-    // /**
-    // * Multiplies an AbstractF2mPoint
-    // * by <code>k</code> using the reduced <code>&#964;</code>-adic NAF (RTNAF)
-    // * method.
-    // * @param p The AbstractF2mPoint to multiply.
-    // * @param k The integer by which to multiply <code>k</code>.
-    // * @return <code>p</code> multiplied by <code>k</code>.
-    // */
-    function MultiplyPositive(const point: IECPoint; const k: TBigInteger)
-      : IECPoint; override;
-
-  public
-    constructor Create();
-
+    function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; override;
   end;
 
 implementation
 
 uses
-  ClpECAlgorithms;
+  System.Math,
+  ClpCryptoLibTypes,
+  ClpECAlgorithms,
+  ClpECPoint,
+  ClpEndoUtilities,
+  ClpFixedPointUtilities,
+  ClpIFixedPointPreCompInfo,
+  ClpNat,
+  ClpBitOperations,
+  ClpTnaf,
+  ClpIWTauNafPreCompInfo,
+  ClpWTauNafPreCompInfo;
 
 { TAbstractECMultiplier }
 
-function TAbstractECMultiplier.CheckResult(const p: IECPoint): IECPoint;
-begin
-  result := TECAlgorithms.ImplCheckResult(p);
-end;
-
-constructor TAbstractECMultiplier.Create;
+function TAbstractECMultiplier.CheckResult(const AP: IECPoint): IECPoint;
 begin
-  Inherited Create();
+  Result := TECAlgorithms.ImplCheckResult(AP);
 end;
 
-function TAbstractECMultiplier.Multiply(const p: IECPoint; const k: TBigInteger)
-  : IECPoint;
+function TAbstractECMultiplier.Multiply(const APoint: IECPoint; const AK: TBigInteger): IECPoint;
 var
-  positive: IECPoint;
-  sign: Int32;
+  LSign: Int32;
+  LPositive, LResult: IECPoint;
 begin
-
-  sign := k.SignValue;
-  if ((sign = 0) or (p.IsInfinity)) then
-  begin
-    result := p.curve.Infinity;
-    Exit;
-  end;
-
-  positive := MultiplyPositive(p, k.Abs());
-
-  if sign > 0 then
-  begin
-    result := positive
-  end
+  LSign := AK.SignValue;
+  if (LSign = 0) or APoint.IsInfinity then
+    Exit(APoint.Curve.Infinity);
+  LPositive := MultiplyPositive(APoint, AK.Abs());
+  if LSign > 0 then
+    LResult := LPositive
   else
-  begin
-    result := positive.Negate();
-  end;
-
-  // /*
-  // * Although the various multipliers ought not to produce invalid output under normal
-  // * circumstances, a final check here is advised to guard against fault attacks.
-  // */
-  result := CheckResult(result);
-
+    LResult := LPositive.Negate();
+  Result := CheckResult(LResult);
 end;
 
-{ TFixedPointCombMultiplier }
-
-constructor TFixedPointCombMultiplier.Create;
-begin
-  Inherited Create();
-end;
+{ TWNafL2RMultiplier }
 
-function TFixedPointCombMultiplier.MultiplyPositive(const p: IECPoint;
-  const k: TBigInteger): IECPoint;
+function TWNafL2RMultiplier.MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint;
 var
-  c: IECCurve;
-  R, add: IECPoint;
-  size, width, d, top, i, j, fullComb: Int32;
-  secretIndex, secretBit: UInt32;
-  info: IFixedPointPreCompInfo;
-  lookupTable: IECLookupTable;
-  LK: TCryptoLibUInt32Array;
+  LMinWidth, LWidth, LI, LWi, LDigit, LZeroes, LN, LHighest, LScale, LLowBits, LI1, LI2: Int32;
+  LInfo: IWNafPreCompInfo;
+  LPreComp, LPreCompNeg: TCryptoLibGenericArray<IECPoint>;
+  LWnaf: TCryptoLibInt32Array;
+  LTable: TCryptoLibGenericArray<IECPoint>;
+  LR, LSmallR: IECPoint;
 begin
-  c := p.curve;
-  size := TFixedPointUtilities.GetCombSize(c);
-  if (k.BitLength > size) then
-  begin
-    // /*
-    // * TODO The comb works best when the scalars are less than the (possibly unknown) order.
-    // * Still, if we want to handle larger scalars, we could allow customization of the comb
-    // * size, or alternatively we could deal with the 'extra' bits either by running the comb
-    // * multiple times as necessary, or by using an alternative multiplier as prelude.
-    // */
-    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidComputation);
-  end;
-
-  info := TFixedPointUtilities.Precompute(p);
-  lookupTable := info.lookupTable;
-  width := info.width;
-
-  d := (size + width - 1) div width;
-
-  R := c.Infinity;
-  fullComb := d * width;
-  LK := TNat.FromBigInteger(fullComb, k);
+  LMinWidth := TWNafUtilities.GetWindowSize(AK.BitLength);
+  LInfo := TWNafUtilities.Precompute(AP, LMinWidth, True);
+  LPreComp := LInfo.PreComp;
+  LPreCompNeg := LInfo.PreCompNeg;
+  LWidth := LInfo.Width;
 
-  top := fullComb - 1;
+  LWnaf := TWNafUtilities.GenerateCompactWindowNaf(LWidth, AK);
+  LR := AP.Curve.Infinity;
+  LI := System.Length(LWnaf);
 
-  for i := 0 to System.Pred(d) do
+  if LI > 1 then
   begin
+    Dec(LI);
+    LWi := LWnaf[LI];
+    LDigit := TBitOperations.Asr32(LWi, 16);
+    LZeroes := LWi and $FFFF;
+
+    LN := System.Math.Abs(LDigit);
+    if LDigit < 0 then
+      LTable := LPreCompNeg
+    else
+      LTable := LPreComp;
 
-    secretIndex := 0;
-
-    j := (top - i);
-
-    while j >= 0 do
+    if (LN shl 2) < (1 shl LWidth) then
     begin
+      LHighest := 32 - TBitOperations.NumberOfLeadingZeros32(UInt32(LN));
+      LScale := LWidth - LHighest;
+      LLowBits := LN xor (1 shl (LHighest - 1));
+      LI1 := (1 shl (LWidth - 1)) - 1;
+      LI2 := (LLowBits shl LScale) + 1;
+      LR := LTable[TBitOperations.Asr32(LI1, 1)].Add(LTable[TBitOperations.Asr32(LI2, 1)]);
+      Dec(LZeroes, LScale);
+    end
+    else
+      LR := LTable[TBitOperations.Asr32(LN, 1)];
 
-      secretBit := LK[TBitOperations.Asr32(j, 5)] shr (j and $1F);
-      secretIndex := secretIndex xor (secretBit shr 1);
-      secretIndex := secretIndex shl 1;
-      secretIndex := secretIndex xor secretBit;
-
-      System.Dec(j, d);
-    end;
+    LR := LR.TimesPow2(LZeroes);
+  end;
 
-    add := lookupTable.Lookup(Int32(secretIndex));
-    R := R.TwicePlus(add);
+  while LI > 0 do
+  begin
+    Dec(LI);
+    LWi := LWnaf[LI];
+    LDigit := TBitOperations.Asr32(LWi, 16);
+    LZeroes := LWi and $FFFF;
+
+    LN := System.Math.Abs(LDigit);
+    if LDigit < 0 then
+      LTable := LPreCompNeg
+    else
+      LTable := LPreComp;
+    LSmallR := LTable[TBitOperations.Asr32(LN, 1)];
 
+    LR := LR.TwicePlus(LSmallR);
+    LR := LR.TimesPow2(LZeroes);
   end;
 
-  result := R.add(info.Offset);
-
+  Result := LR;
 end;
 
 { TGlvMultiplier }
 
-constructor TGlvMultiplier.Create(const curve: IECCurve;
-  const glvEndomorphism: IGlvEndomorphism);
+constructor TGlvMultiplier.Create(const ACurve: IECCurve; const AGlvEndomorphism: IGlvEndomorphism);
 begin
-  inherited Create();
-  if ((curve = Nil) or (not(curve.Order.IsInitialized))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SCurveUnknownGroupOrder);
-  end;
-
-  Fcurve := curve;
-  FglvEndomorphism := glvEndomorphism;
-end;
-
-destructor TGlvMultiplier.Destroy;
-begin
-  //TSetWeakRef.SetWeakReference(@Fcurve, Nil);
-  inherited Destroy;
+  Inherited Create;
+  if (ACurve = nil) or (not ACurve.Order.IsInitialized) then
+    raise EArgumentCryptoLibException.Create('Need curve with known group order');
+  FCurve := ACurve;
+  FGlvEndomorphism := AGlvEndomorphism;
 end;
 
-function TGlvMultiplier.MultiplyPositive(const p: IECPoint;
-  const k: TBigInteger): IECPoint;
+function TGlvMultiplier.MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint;
 var
-  n, a, b: TBigInteger;
-  ab: TCryptoLibGenericArray<TBigInteger>;
-  q: IECPoint;
-  LCurve: IECCurve;
+  LN: TBigInteger;
+  LAB: TCryptoLibGenericArray<TBigInteger>;
+  LA, LB: TBigInteger;
+  LQ: IECPoint;
 begin
-  LCurve :=  Fcurve;
-  if (not(LCurve.Equals(p.curve))) then
-  begin
+  if not FCurve.Equals(AP.Curve) then
     raise EInvalidOperationCryptoLibException.Create('');
-  end;
-
-  n := p.curve.Order;
-  ab := FglvEndomorphism.DecomposeScalar(k.&Mod(n));
-  a := ab[0];
-  b := ab[1];
-
-  if (FglvEndomorphism.HasEfficientPointMap) then
+  LN := AP.Curve.Order;
+  LAB := FGlvEndomorphism.DecomposeScalar(AK.Mod(LN));
+  LA := LAB[0];
+  LB := LAB[1];
+  if FGlvEndomorphism.HasEfficientPointMap then
+    Result := TECAlgorithms.ImplShamirsTrickWNaf(FGlvEndomorphism as IECEndomorphism, AP, LA, LB)
+  else
   begin
-    result := TECAlgorithms.ImplShamirsTrickWNaf(FglvEndomorphism, p, a, b);
-    Exit;
+    LQ := TEndoUtilities.MapPoint(FGlvEndomorphism as IECEndomorphism, AP);
+    Result := TECAlgorithms.ImplShamirsTrickWNaf(AP, LA, LQ, LB);
   end;
-
-  q := TEndoUtilities.MapPoint(FglvEndomorphism, p);
-
-  result := TECAlgorithms.ImplShamirsTrickWNaf(p, a, q, b);
 end;
 
-{ TWNafL2RMultiplier }
+{ TWTauNafMultiplier }
 
-constructor TWNafL2RMultiplier.Create;
+type
+  TWTauNafCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FP: IAbstractF2mPoint;
+    FA: ShortInt;
+  public
+    constructor Create(const AP: IAbstractF2mPoint; AA: ShortInt);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TWTauNafCallback.Create(const AP: IAbstractF2mPoint; AA: ShortInt);
 begin
-  Inherited Create();
+  inherited Create;
+  FP := AP;
+  FA := AA;
 end;
 
-function TWNafL2RMultiplier.MultiplyPositive(const p: IECPoint;
-  const k: TBigInteger): IECPoint;
+function TWTauNafCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
 var
-  width, minWidth, i, wi, digit, zeroes, n, highest, scale, lowBits, i1,
-    i2: Int32;
-  info: IWNafPreCompInfo;
-  preComp, preCompNeg, table: TCryptoLibGenericArray<IECPoint>;
-  wnaf: TCryptoLibInt32Array;
-  R, lr: IECPoint;
+  LExisting: IWTauNafPreCompInfo;
+  LResult: TWTauNafPreCompInfo;
 begin
-  minWidth := TWNafUtilities.GetWindowSize(k.BitLength);
-
-  info := TWNafUtilities.Precompute(p, minWidth, true);
-  preComp := info.preComp;
-  preCompNeg := info.preCompNeg;
-  width := info.width;
-
-  wnaf := TWNafUtilities.GenerateCompactWindowNaf(width, k);
-
-  R := p.curve.Infinity;
+  if Supports(AExisting, IWTauNafPreCompInfo, LExisting) then
+    Exit(AExisting);
 
-  i := System.Length(wnaf);
-
-  // /*
-  // * NOTE: We try to optimize the first window using the precomputed points to substitute an
-  // * addition for 2 or more doublings.
-  // */
-  if (i > 1) then
-  begin
-    System.Dec(i);
-    wi := wnaf[i];
-    digit := TBitOperations.Asr32(wi, 16);
-    zeroes := wi and $FFFF;
-
-    n := System.Abs(digit);
-    if digit < 0 then
-    begin
-      table := preCompNeg;
-    end
-    else
-    begin
-      table := preComp;
-    end;
-
-    // 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 - TBitOperations.NumberOfLeadingZeros32(n);
-
-      // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting?
-      scale := width - highest;
-      lowBits := n xor (1 shl (highest - 1));
-
-      i1 := ((1 shl (width - 1)) - 1);
-      i2 := (lowBits shl scale) + 1;
-      R := table[TBitOperations.Asr32(i1, 1)].add(table[TBitOperations.Asr32(i2, 1)]);
-
-      zeroes := zeroes - scale;
-    end
-    else
-    begin
-      R := table[TBitOperations.Asr32(n, 1)];
-    end;
+  LResult := TWTauNafPreCompInfo.Create;
+  LResult.PreComp := TTnaf.GetPreComp(FP, FA);
+  Result := LResult;
+end;
 
-    R := R.TimesPow2(zeroes);
-  end;
+class constructor TWTauNafMultiplier.Create;
+begin
+  PRECOMP_NAME := 'bc_wtnaf';
+end;
 
-  while (i > 0) do
-  begin
-    System.Dec(i);
-    wi := wnaf[i];
-    digit := TBitOperations.Asr32(wi, 16);
-    zeroes := wi and $FFFF;
+function TWTauNafMultiplier.MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint;
+var
+  LP: IAbstractF2mPoint;
+  LCurve: IAbstractF2mCurve;
+  LA, LMu: ShortInt;
+  LRho: IZTauElement;
+begin
+  if not Supports(AP, IAbstractF2mPoint, LP) then
+    raise EArgumentCryptoLibException.Create('Only AbstractF2mPoint can be used in WTauNafMultiplier');
 
-    n := System.Abs(digit);
-    if digit < 0 then
-    begin
-      table := preCompNeg;
-    end
-    else
-    begin
-      table := preComp;
-    end;
+  LCurve := LP.Curve as IAbstractF2mCurve;
+  LA := ShortInt(LCurve.A.ToBigInteger().Int32Value);
+  LMu := TTnaf.GetMu(LA);
 
-    lr := table[TBitOperations.Asr32(n, 1)];
+  LRho := TTnaf.PartModReduction(LCurve, AK, LA, LMu, ShortInt(10));
 
-    R := R.TwicePlus(lr);
-    R := R.TimesPow2(zeroes);
-  end;
+  Result := MultiplyWTnaf(LP, LRho, LA, LMu);
+end;
 
-  result := R;
+function TWTauNafMultiplier.MultiplyWTnaf(const AP: IAbstractF2mPoint;
+  const ALambda: IZTauElement; AA, AMu: ShortInt): IAbstractF2mPoint;
+var
+  LAlpha: TCryptoLibGenericArray<IZTauElement>;
+  LTw: TBigInteger;
+  LU: TCryptoLibShortIntArray;
+begin
+  if AA = 0 then
+    LAlpha := TTnaf.Alpha0
+  else
+    LAlpha := TTnaf.Alpha1;
 
-end;
+  LTw := TTnaf.GetTw(AMu, TTnaf.Width);
 
-{ TWTauNafMultiplier }
+  LU := TTnaf.TauAdicWNaf(AMu, ALambda, TTnaf.Width, LTw.Int32Value, LAlpha);
 
-constructor TWTauNafMultiplier.Create;
-begin
-  Inherited Create();
+  Result := MultiplyFromWTnaf(AP, LU);
 end;
 
-class function TWTauNafMultiplier.MultiplyFromWTnaf(const p: IAbstractF2mPoint;
-  const u: TCryptoLibShortIntArray): IAbstractF2mPoint;
+class function TWTauNafMultiplier.MultiplyFromWTnaf(const AP: IAbstractF2mPoint;
+  const AU: TCryptoLibShortIntArray): IAbstractF2mPoint;
 var
-  curve: IAbstractF2mCurve;
-  a: ShortInt;
-  i, tauCount, ui: Int32;
-  pu, puNeg: TCryptoLibGenericArray<IAbstractF2mPoint>;
-  pre: IWTauNafPreCompInfo;
-  q: IAbstractF2mPoint;
-  x: IECPoint;
+  LCurve: IAbstractF2mCurve;
+  LA: ShortInt;
+  LCallback: IPreCompCallback;
+  LPreCompInfo: IWTauNafPreCompInfo;
+  LPu, LPuNeg: TCryptoLibGenericArray<IAbstractF2mPoint>;
+  LQ: IAbstractF2mPoint;
+  LTauCount, LI, LUi: Int32;
+  LX: IECPoint;
 begin
-  curve := p.curve as IAbstractF2mCurve;
-  a := ShortInt(curve.a.ToBigInteger().Int32Value);
+  LCurve := AP.Curve as IAbstractF2mCurve;
+  LA := ShortInt(LCurve.A.ToBigInteger().Int32Value);
 
-  pre := curve.Precompute(p, PRECOMP_NAME, TWTauNafCallback.Create(p, a)
-    as IWTauNafCallback) as IWTauNafPreCompInfo;
+  LCallback := TWTauNafCallback.Create(AP, LA);
+  LPreCompInfo := LCurve.Precompute(AP, PRECOMP_NAME, LCallback) as IWTauNafPreCompInfo;
+  LPu := LPreCompInfo.PreComp;
 
-  pu := pre.preComp;
   // TODO Include negations in precomp (optionally) and use from here
-  System.SetLength(puNeg, System.Length(pu));
-  for i := 0 to System.Pred(System.Length(pu)) do
-  begin
-    puNeg[i] := pu[i].Negate() as IAbstractF2mPoint;
-  end;
+  SetLength(LPuNeg, System.Length(LPu));
+  for LI := 0 to System.Length(LPu) - 1 do
+    LPuNeg[LI] := LPu[LI].Negate() as IAbstractF2mPoint;
 
-  q := p.curve.Infinity as IAbstractF2mPoint;
-  tauCount := 0;
-  i := System.Length(u) - 1;
-  while i >= 0 do
+  // q = infinity
+  LQ := AP.Curve.Infinity as IAbstractF2mPoint;
+
+  LTauCount := 0;
+  for LI := System.Length(AU) - 1 downto 0 do
   begin
-    System.Inc(tauCount);
-    ui := u[i];
-    if (ui <> 0) then
+    System.Inc(LTauCount);
+    LUi := AU[LI];
+    if LUi <> 0 then
     begin
-      q := q.TauPow(tauCount);
-      tauCount := 0;
+      LQ := LQ.TauPow(LTauCount);
+      LTauCount := 0;
 
-      if ui > 0 then
-      begin
-        x := pu[TBitOperations.Asr32(ui, 1)];
-      end
+      if LUi > 0 then
+        LX := LPu[TBitOperations.Asr32(LUi, 1)]
       else
-      begin
-        x := puNeg[TBitOperations.Asr32(-ui, 1)];
-      end;
-
-      q := q.add(x) as IAbstractF2mPoint;
+        LX := LPuNeg[TBitOperations.Asr32(-LUi, 1)];
+      LQ := LQ.Add(LX) as IAbstractF2mPoint;
     end;
-    System.Dec(i);
   end;
-  if (tauCount > 0) then
-  begin
-    q := q.TauPow(tauCount);
-  end;
-  result := q;
+  if LTauCount > 0 then
+    LQ := LQ.TauPow(LTauCount);
 
+  Result := LQ;
 end;
 
-function TWTauNafMultiplier.MultiplyWTnaf(const p: IAbstractF2mPoint;
-  const lambda: IZTauElement; a, mu: ShortInt): IAbstractF2mPoint;
-var
-  alpha: TCryptoLibGenericArray<IZTauElement>;
-  tw: TBigInteger;
-  u: TCryptoLibShortIntArray;
-begin
-  if a = 0 then
-  begin
-    alpha := TTnaf.Alpha0;
-  end
-  else
-  begin
-    alpha := TTnaf.Alpha1;
-  end;
-
-  tw := TTnaf.GetTw(mu, TTnaf.width);
-
-  u := TTnaf.TauAdicWNaf(mu, lambda, TTnaf.width,
-    TBigInteger.ValueOf(TTnaf.Pow2Width), tw, alpha);
-
-  result := MultiplyFromWTnaf(p, u);
-end;
+{ TFixedPointCombMultiplier }
 
-function TWTauNafMultiplier.MultiplyPositive(const point: IECPoint;
-  const k: TBigInteger): IECPoint;
+function TFixedPointCombMultiplier.MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint;
 var
-  p: IAbstractF2mPoint;
-  curve: IAbstractF2mCurve;
-  m: Int32;
-  a, mu: ShortInt;
-  s: TCryptoLibGenericArray<TBigInteger>;
-  rho: IZTauElement;
+  LC: IECCurve;
+  LSize, LWidth, LD, LFullComb, LI, LJ: Int32;
+  LInfo: IFixedPointPreCompInfo;
+  LLookupTable: IECLookupTable;
+  LK: TCryptoLibUInt32Array;
+  LSecretIndex: UInt32;
+  LSecretBit: UInt32;
+  LR, LAdd: IECPoint;
 begin
-  if (not(Supports(point, IAbstractF2mPoint))) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInCompatiblePoint);
-  end;
+  LC := AP.Curve;
+  LSize := TFixedPointUtilities.GetCombSize(LC);
 
-  p := point as IAbstractF2mPoint;
-  curve := p.curve as IAbstractF2mCurve;
-  m := curve.FieldSize;
-  a := ShortInt(curve.a.ToBigInteger().Int32Value);
-  mu := TTnaf.GetMu(a);
-  s := curve.GetSi();
+  if AK.BitLength > LSize then
+    raise EInvalidOperationCryptoLibException.Create(
+      'fixed-point comb doesn''t support scalars larger than the curve order');
 
-  rho := TTnaf.PartModReduction(k, m, a, s, mu, ShortInt(10));
+  LInfo := TFixedPointUtilities.Precompute(AP);
+  LLookupTable := LInfo.LookupTable;
+  LWidth := LInfo.Width;
+  LD := (LSize + LWidth - 1) div LWidth;
+  LFullComb := LD * LWidth;
 
-  result := MultiplyWTnaf(p, rho, a, mu);
+  LK := TNat.FromBigInteger(LFullComb, AK);
 
-end;
+  LR := LC.Infinity;
 
-{ TWTauNafMultiplier.TWTauNafCallback }
+  for LI := 1 to LD do
+  begin
+    LSecretIndex := 0;
 
-constructor TWTauNafMultiplier.TWTauNafCallback.Create
-  (const p: IAbstractF2mPoint; a: ShortInt);
-begin
-  Inherited Create();
-  Fm_p := p;
-  Fm_a := a;
-end;
+    LJ := LFullComb - LI;
+    while LJ >= 0 do
+    begin
+      LSecretBit := LK[TBitOperations.Asr32(LJ, 5)] shr (LJ and $1F);
+      LSecretIndex := LSecretIndex xor (LSecretBit shr 1);
+      LSecretIndex := LSecretIndex shl 1;
+      LSecretIndex := LSecretIndex xor LSecretBit;
+      LJ := LJ - LD;
+    end;
 
-function TWTauNafMultiplier.TWTauNafCallback.Precompute(const existing
-  : IPreCompInfo): IPreCompInfo;
-var
-  tempResult: IWTauNafPreCompInfo;
-begin
+    LAdd := LLookupTable.Lookup(Int32(LSecretIndex));
 
-   if (Supports(existing, IWTauNafPreCompInfo)) then
-   begin
-     result := existing;
-     Exit;
-   end;
+    LR := LR.TwicePlus(LAdd);
+  end;
 
-  tempResult := TWTauNafPreCompInfo.Create();
-  tempResult.preComp := TTnaf.GetPreComp(Fm_p, Fm_a);
-  result := tempResult;
+  Result := LR.Add(LInfo.Offset);
 end;
 
 end.

+ 24 - 47
CryptoLib/src/Math/EC/Multiplier/ClpValidityPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpValidityPreCompInfo;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,74 +15,58 @@ unit ClpValidityPreCompInfo;
 interface
 
 uses
-  ClpIPreCompInfo,
-  ClpIValidityPreCompInfo;
+  ClpIValidityPreCompInfo,
+  ClpIPreCompInfo;
 
 type
-  TValidityPreCompInfo = class(TInterfacedObject, IPreCompInfo,
+  TValidityPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo,
     IValidityPreCompInfo)
-
   strict private
-
-  var
-    Ffailed, FcurveEquationPassed, ForderPassed: Boolean;
-
+    FFailed: Boolean;
+    FCurveEquationPassed: Boolean;
+    FOrderPassed: Boolean;
   public
-
     const
-    PRECOMP_NAME = 'bc_validity';
-
-    function HasFailed(): Boolean; inline;
-    procedure ReportFailed(); inline;
-    function HasCurveEquationPassed(): Boolean; inline;
-    procedure ReportCurveEquationPassed(); inline;
-    function HasOrderPassed(): Boolean; inline;
-    procedure ReportOrderPassed(); inline;
-
-    constructor Create();
-
+      PRECOMP_NAME = 'bc_validity';
+
+    function HasFailed: Boolean;
+    procedure ReportFailed;
+    function HasCurveEquationPassed: Boolean;
+    procedure ReportCurveEquationPassed;
+    function HasOrderPassed: Boolean;
+    procedure ReportOrderPassed;
   end;
 
 implementation
 
-{ TValidityPreCompInfo }
-
-constructor TValidityPreCompInfo.Create;
-begin
-  Inherited Create();
-  Ffailed := False;
-  FcurveEquationPassed := False;
-  ForderPassed := False;
-end;
-
-function TValidityPreCompInfo.HasCurveEquationPassed: Boolean;
+function TValidityPreCompInfo.HasFailed: Boolean;
 begin
-  result := FcurveEquationPassed;
+  Result := FFailed;
 end;
 
-function TValidityPreCompInfo.HasFailed: Boolean;
+procedure TValidityPreCompInfo.ReportFailed;
 begin
-  result := Ffailed;
+  FFailed := True;
 end;
 
-function TValidityPreCompInfo.HasOrderPassed: Boolean;
+function TValidityPreCompInfo.HasCurveEquationPassed: Boolean;
 begin
-  result := ForderPassed;
+  Result := FCurveEquationPassed;
 end;
 
 procedure TValidityPreCompInfo.ReportCurveEquationPassed;
 begin
-  FcurveEquationPassed := True;
+  FCurveEquationPassed := True;
 end;
 
-procedure TValidityPreCompInfo.ReportFailed;
+function TValidityPreCompInfo.HasOrderPassed: Boolean;
 begin
-  Ffailed := True;
+  Result := FOrderPassed;
 end;
 
 procedure TValidityPreCompInfo.ReportOrderPassed;
 begin
-  ForderPassed := True;
+  FOrderPassed := True;
 end;
 
 end.

+ 61 - 139
CryptoLib/src/Math/EC/Multiplier/ClpWNafPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpWNafPreCompInfo;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,84 +15,50 @@ unit ClpWNafPreCompInfo;
 interface
 
 uses
-  ClpCryptoLibTypes,
-  ClpIECC,
+  ClpIECCore,
+  ClpIPreCompInfo,
   ClpIWNafPreCompInfo,
-  ClpIPreCompInfo;
+  ClpCryptoLibTypes;
 
 type
-
-  /// <summary>
-  /// Class holding precomputation data for the WNAF (Window Non-Adjacent
-  /// Form) algorithm.
-  /// </summary>
-  TWNafPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo,
-    IWNafPreCompInfo)
-
+  TWNafPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo, IWNafPreCompInfo)
   strict private
-  var
-    /// <summary>
-    /// Array holding the precomputed <c>ECPoint</c>s used for a Window NAF
-    /// multiplication.
-    /// </summary>
+    FPromotionCountdown: Int32;
+    FConfWidth: Int32;
     FPreComp: TCryptoLibGenericArray<IECPoint>;
-
-    /// <summary>
-    /// Array holding the negations of the precomputed <c>ECPoint</c>s used
-    /// for a Window NAF multiplication.
-    /// </summary>
     FPreCompNeg: TCryptoLibGenericArray<IECPoint>;
-
-    /// <summary>
-    /// Holds an <c>ECPoint</c> representing Twice(this). Used for the Window
-    /// NAF multiplication to create or extend the precomputed values.
-    /// </summary>
     FTwice: IECPoint;
-
-    FConfWidth, FWidth: Int32;
-
-{$IFNDEF FPC}
-{$IFDEF HAS_VOLATILE}[volatile]
-{$ENDIF}
-{$ENDIF}
-    FPromotionCountdown: Int32;
-
-    function GetPreComp: TCryptoLibGenericArray<IECPoint>; inline;
-    procedure SetPreComp(const Value: TCryptoLibGenericArray<IECPoint>); inline;
-    function GetPreCompNeg: TCryptoLibGenericArray<IECPoint>; inline;
-    procedure SetPreCompNeg(const Value
-      : TCryptoLibGenericArray<IECPoint>); inline;
-    function GetTwice: IECPoint; inline;
-    procedure SetTwice(const Value: IECPoint); inline;
-
-    function GetConfWidth: Int32; inline;
-    procedure SetConfWidth(Value: Int32); inline;
-
-    function GetWidth: Int32; inline;
-    procedure SetWidth(Value: Int32); inline;
-
-    function GetPromotionCountdown: Int32; inline;
-    procedure SetPromotionCountdown(Value: Int32); inline;
-
-    function DecrementPromotionCountdown: Int32; inline;
-    function IsPromoted: Boolean; inline;
-
+    FWidth: Int32;
   public
-
-    constructor Create();
-    destructor Destroy; override;
-    property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp
-      write SetPreComp;
-    property PreCompNeg: TCryptoLibGenericArray<IECPoint> read GetPreCompNeg
-      write SetPreCompNeg;
-    property Twice: IECPoint read GetTwice write SetTwice;
+    const
+      PRECOMP_NAME = 'bc_wnaf';
+
+    constructor Create;
+
+    function DecrementPromotionCountdown: Int32;
+    function GetConfWidth: Int32;
+    function GetPreComp: TCryptoLibGenericArray<IECPoint>;
+    function GetPreCompNeg: TCryptoLibGenericArray<IECPoint>;
+    function GetTwice: IECPoint;
+    function GetWidth: Int32;
+    function GetIsPromoted: Boolean;
+
+    procedure SetConfWidth(AValue: Int32);
+    procedure SetPreComp(const AValue: TCryptoLibGenericArray<IECPoint>);
+    procedure SetPreCompNeg(const AValue: TCryptoLibGenericArray<IECPoint>);
+    procedure SetTwice(const AValue: IECPoint);
+    procedure SetWidth(AValue: Int32);
+    procedure SetPromotionCountdown(AValue: Int32);
 
     property ConfWidth: Int32 read GetConfWidth write SetConfWidth;
+    property PreComp: TCryptoLibGenericArray<IECPoint> read GetPreComp write SetPreComp;
+    property PreCompNeg: TCryptoLibGenericArray<IECPoint> read GetPreCompNeg write SetPreCompNeg;
+    property Twice: IECPoint read GetTwice write SetTwice;
     property Width: Int32 read GetWidth write SetWidth;
+    function GetPromotionCountdown: Int32;
 
-    property PromotionCountdown: Int32 read GetPromotionCountdown
-      write SetPromotionCountdown;
-
+    property IsPromoted: Boolean read GetIsPromoted;
+    property PromotionCountdown: Int32 read GetPromotionCountdown write SetPromotionCountdown;
   end;
 
 implementation
@@ -108,122 +67,85 @@ implementation
 
 constructor TWNafPreCompInfo.Create;
 begin
-  inherited Create();
+  inherited Create;
+  FPromotionCountdown := 4;
   FConfWidth := -1;
   FWidth := -1;
-  FPromotionCountdown := 4;
 end;
 
 function TWNafPreCompInfo.DecrementPromotionCountdown: Int32;
-var
-  t: Int32;
 begin
-  t := PromotionCountdown;
-  if (t > 0) then
+  Result := FPromotionCountdown;
+  if Result > 0 then
   begin
-    System.Dec(t);
-    PromotionCountdown := t;
+    Dec(FPromotionCountdown);
+    Result := FPromotionCountdown;
   end;
-  result := t;
 end;
 
-destructor TWNafPreCompInfo.Destroy;
-var
-  i: Integer;
-begin
-  if Assigned(FPreComp) then
-  begin
-    for i := 0 to Length(FPreComp) - 1 do
-      FPreComp[i] := nil;
-    FPreComp := nil;
-  end;
-
-  if Assigned(FPreCompNeg) then
-  begin
-    for i := 0 to Length(FPreCompNeg) - 1 do
-      FPreCompNeg[i] := nil;
-    FPreCompNeg := nil;
-  end;
-
-  FTwice := nil;
-
-  inherited;
-end;
-
-
 function TWNafPreCompInfo.GetConfWidth: Int32;
 begin
-  result := FConfWidth;
+  Result := FConfWidth;
 end;
 
 function TWNafPreCompInfo.GetPreComp: TCryptoLibGenericArray<IECPoint>;
 begin
-  result := FPreComp;
+  Result := FPreComp;
 end;
 
 function TWNafPreCompInfo.GetPreCompNeg: TCryptoLibGenericArray<IECPoint>;
 begin
-  result := FPreCompNeg;
+  Result := FPreCompNeg;
 end;
 
-function TWNafPreCompInfo.GetPromotionCountdown: Int32;
+function TWNafPreCompInfo.GetTwice: IECPoint;
 begin
-{$IFDEF FPC}
-  result := {$IFDEF HAS_VOLATILE}volatile{$ENDIF}(FPromotionCountdown);
-{$ELSE}
-    result := FPromotionCountdown;
-{$ENDIF}
+  Result := FTwice;
 end;
 
-function TWNafPreCompInfo.GetTwice: IECPoint;
+function TWNafPreCompInfo.GetWidth: Int32;
 begin
-  result := FTwice;
+  Result := FWidth;
 end;
 
-function TWNafPreCompInfo.GetWidth: Int32;
+function TWNafPreCompInfo.GetIsPromoted: Boolean;
 begin
-  result := FWidth;
+  Result := FPromotionCountdown <= 0;
 end;
 
-function TWNafPreCompInfo.IsPromoted: Boolean;
+function TWNafPreCompInfo.GetPromotionCountdown: Int32;
 begin
-  result := PromotionCountdown <= 0;
+  Result := FPromotionCountdown;
 end;
 
-procedure TWNafPreCompInfo.SetConfWidth(Value: Int32);
+procedure TWNafPreCompInfo.SetConfWidth(AValue: Int32);
 begin
-  FConfWidth := Value;
+  FConfWidth := AValue;
 end;
 
-procedure TWNafPreCompInfo.SetPreComp(const Value
-  : TCryptoLibGenericArray<IECPoint>);
+procedure TWNafPreCompInfo.SetPreComp(const AValue: TCryptoLibGenericArray<IECPoint>);
 begin
-  FPreComp := Value;
+  FPreComp := AValue;
 end;
 
-procedure TWNafPreCompInfo.SetPreCompNeg(const Value
-  : TCryptoLibGenericArray<IECPoint>);
+procedure TWNafPreCompInfo.SetPreCompNeg(const AValue: TCryptoLibGenericArray<IECPoint>);
 begin
-  FPreCompNeg := Value;
+  FPreCompNeg := AValue;
 end;
 
-procedure TWNafPreCompInfo.SetPromotionCountdown(Value: Int32);
+procedure TWNafPreCompInfo.SetTwice(const AValue: IECPoint);
 begin
-{$IFDEF FPC}
-  FPromotionCountdown := {$IFDEF HAS_VOLATILE}volatile{$ENDIF}(Value);
-{$ELSE}
-    FPromotionCountdown := Value;
-{$ENDIF}
+  FTwice := AValue;
 end;
 
-procedure TWNafPreCompInfo.SetTwice(const Value: IECPoint);
+procedure TWNafPreCompInfo.SetWidth(AValue: Int32);
 begin
-  FTwice := Value;
+  FWidth := AValue;
 end;
 
-procedure TWNafPreCompInfo.SetWidth(Value: Int32);
+procedure TWNafPreCompInfo.SetPromotionCountdown(AValue: Int32);
 begin
-  FWidth := Value;
+  FPromotionCountdown := AValue;
 end;
 
 end.

+ 754 - 0
CryptoLib/src/Math/EC/Multiplier/ClpWNafUtilities.pas

@@ -0,0 +1,754 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ * ******************************************************************************* * }
+
+unit ClpWNafUtilities;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBigInteger,
+  ClpIECCore,
+  ClpIPreCompCallback,
+  ClpIPreCompInfo,
+  ClpIWNafPreCompInfo,
+  ClpWNafPreCompInfo,
+  ClpCryptoLibTypes;
+
+type
+  TWNafUtilities = class sealed(TObject)
+  strict private
+    class var
+      FDefaultWindowSizeCutoffs: TCryptoLibInt32Array;
+    class function GetWindowSize(ABits: Int32; const AWindowSizeCutoffs: TCryptoLibInt32Array;
+      AMaxWidth: Int32): Int32; overload; static;
+    class function Trim(const AArray: TCryptoLibInt32Array; ALength: Int32): TCryptoLibInt32Array; static;
+    class function TrimBytes(const AArray: TCryptoLibByteArray; ALength: Int32): TCryptoLibByteArray; static;
+    class function ResizeTable(const AArray: TCryptoLibGenericArray<IECPoint>;
+      ALength: Int32): TCryptoLibGenericArray<IECPoint>; static;
+  public
+    const
+      PRECOMP_NAME = 'bc_wnaf';
+      MAX_WIDTH = 16;
+    class procedure ConfigureBasepoint(const AP: IECPoint); static;
+    class function GetWindowSize(ABits: Int32): Int32; overload; static;
+    class function GetWindowSize(ABits: Int32; AMaxWidth: Int32): Int32; overload; static;
+    class function GetWindowSize(ABits: Int32; const AWindowSizeCutoffs: TCryptoLibInt32Array): Int32; overload; static;
+    class function GenerateNaf(const AK: TBigInteger): TCryptoLibByteArray; static;
+    class function GenerateCompactNaf(const AK: TBigInteger): TCryptoLibInt32Array; static;
+    class function GenerateCompactWindowNaf(AWidth: Int32;
+      const AK: TBigInteger): TCryptoLibInt32Array; static;
+    class function GenerateWindowNaf(AWidth: Int32; const AK: TBigInteger): TCryptoLibByteArray; static;
+    class function GenerateJsf(const AG, AH: TBigInteger): TCryptoLibByteArray; static;
+    class function GetNafWeight(const AK: TBigInteger): Int32; static;
+    class function GetWNafPreCompInfo(const AP: IECPoint): IWNafPreCompInfo; overload; static;
+    class function GetWNafPreCompInfo(const APreCompInfo: IPreCompInfo): IWNafPreCompInfo; overload; static;
+    class function Precompute(const AP: IECPoint; AMinWidth: Int32;
+      AIncludeNegated: Boolean): IWNafPreCompInfo; static;
+    class function PrecomputeWithPointMap(const AP: IECPoint; const APointMap: IECPointMap;
+      const AFromWNaf: IWNafPreCompInfo; AIncludeNegated: Boolean): IWNafPreCompInfo; static;
+  end;
+
+implementation
+
+uses
+  System.Math,
+  ClpArrayUtilities,
+  ClpBitOperations,
+  ClpECCurve,
+  ClpECCurveConstants,
+  ClpECAlgorithms,
+  ClpECPoint;
+
+type
+  TConfigureBasepointCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FCurve: IECCurve;
+    FConfWidth: Int32;
+  public
+    constructor Create(const ACurve: IECCurve; AConfWidth: Int32);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TConfigureBasepointCallback.Create(const ACurve: IECCurve; AConfWidth: Int32);
+begin
+  Inherited Create;
+  FCurve := ACurve;
+  FConfWidth := AConfWidth;
+end;
+
+function TConfigureBasepointCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+var
+  LExistingWNaf: IWNafPreCompInfo;
+  LResult: IWNafPreCompInfo;
+begin
+  if not Supports(AExisting, IWNafPreCompInfo, LExistingWNaf) then
+    LExistingWNaf := nil;
+
+  if (LExistingWNaf <> nil) and (LExistingWNaf.ConfWidth = FConfWidth) then
+  begin
+    LExistingWNaf.PromotionCountdown := 0;
+    Result := LExistingWNaf;
+    Exit;
+  end;
+
+  LResult := TWNafPreCompInfo.Create as IWNafPreCompInfo;
+  LResult.PromotionCountdown := 0;
+  LResult.ConfWidth := FConfWidth;
+
+  if LExistingWNaf <> nil then
+  begin
+    LResult.PreComp := LExistingWNaf.PreComp;
+    LResult.PreCompNeg := LExistingWNaf.PreCompNeg;
+    LResult.Twice := LExistingWNaf.Twice;
+    LResult.Width := LExistingWNaf.Width;
+  end;
+
+  Result := LResult;
+end;
+
+{ TWNafUtilities }
+
+class procedure TWNafUtilities.ConfigureBasepoint(const AP: IECPoint);
+var
+  LC: IECCurve;
+  LBits: Int32;
+  LConfWidth: Int32;
+  LOrder: TBigInteger;
+begin
+  LC := AP.Curve;
+  if LC = nil then
+    Exit;
+
+  LOrder := LC.Order;
+  if not LOrder.IsInitialized then
+    LBits := LC.FieldSize + 1
+  else
+    LBits := LOrder.BitLength;
+
+  LConfWidth := System.Math.Min(MAX_WIDTH, GetWindowSize(LBits) + 3);
+  LC.Precompute(AP, PRECOMP_NAME,
+    TConfigureBasepointCallback.Create(LC, LConfWidth) as IPreCompCallback);
+end;
+
+class function TWNafUtilities.GetWindowSize(ABits: Int32): Int32;
+begin
+  if FDefaultWindowSizeCutoffs = nil then
+    FDefaultWindowSizeCutoffs := TCryptoLibInt32Array.Create(13, 41, 121, 337, 897, 2305);
+  Result := GetWindowSize(ABits, FDefaultWindowSizeCutoffs, MAX_WIDTH);
+end;
+
+class function TWNafUtilities.GetWindowSize(ABits: Int32; AMaxWidth: Int32): Int32;
+begin
+  if FDefaultWindowSizeCutoffs = nil then
+    FDefaultWindowSizeCutoffs := TCryptoLibInt32Array.Create(13, 41, 121, 337, 897, 2305);
+  Result := GetWindowSize(ABits, FDefaultWindowSizeCutoffs, AMaxWidth);
+end;
+
+class function TWNafUtilities.GetWindowSize(ABits: Int32; const AWindowSizeCutoffs: TCryptoLibInt32Array): Int32;
+begin
+  Result := GetWindowSize(ABits, AWindowSizeCutoffs, MAX_WIDTH);
+end;
+
+class function TWNafUtilities.GetWindowSize(ABits: Int32;
+  const AWindowSizeCutoffs: TCryptoLibInt32Array; AMaxWidth: Int32): Int32;
+var
+  LW: Int32;
+begin
+  LW := 0;
+  while (LW < System.Length(AWindowSizeCutoffs)) and (ABits >= AWindowSizeCutoffs[LW]) do
+    Inc(LW);
+  Result := System.Math.Max(2, System.Math.Min(AMaxWidth, LW + 2));
+end;
+
+class function TWNafUtilities.Trim(const AArray: TCryptoLibInt32Array;
+  ALength: Int32): TCryptoLibInt32Array;
+var
+  LI: Int32;
+begin
+  System.SetLength(Result, ALength);
+  for LI := 0 to ALength - 1 do
+    Result[LI] := AArray[LI];
+end;
+
+class function TWNafUtilities.ResizeTable(const AArray: TCryptoLibGenericArray<IECPoint>;
+  ALength: Int32): TCryptoLibGenericArray<IECPoint>;
+var
+  LI, LLen: Int32;
+begin
+  System.SetLength(Result, ALength);
+  if AArray <> nil then
+  begin
+    LLen := System.Math.Min(System.Length(AArray), ALength);
+    for LI := 0 to LLen - 1 do
+      Result[LI] := AArray[LI];
+  end;
+end;
+
+class function TWNafUtilities.TrimBytes(const AArray: TCryptoLibByteArray;
+  ALength: Int32): TCryptoLibByteArray;
+var
+  LI: Int32;
+begin
+  System.SetLength(Result, ALength);
+  for LI := 0 to ALength - 1 do
+    Result[LI] := AArray[LI];
+end;
+
+class function TWNafUtilities.GenerateNaf(const AK: TBigInteger): TCryptoLibByteArray;
+var
+  L3k, LDiff: TBigInteger;
+  LDigits, LI: Int32;
+  LDigit: ShortInt;
+begin
+  if AK.SignValue = 0 then
+  begin
+    System.SetLength(Result, 0);
+    Exit;
+  end;
+  L3k := AK.ShiftLeft(1).Add(AK);
+  LDigits := L3k.BitLength - 1;
+  System.SetLength(Result, LDigits);
+  TArrayUtilities.Fill<Byte>(Result, 0, LDigits, Byte(0));
+  LDiff := L3k.Xor(AK);
+  LI := 1;
+  while LI < LDigits do
+  begin
+    if LDiff.TestBit(LI) then
+    begin
+      if AK.TestBit(LI) then
+        LDigit := -1
+      else
+        LDigit := 1;
+      Result[LI - 1] := Byte(LDigit);
+      Inc(LI);
+    end;
+    Inc(LI);
+  end;
+  Result[LDigits - 1] := 1;
+end;
+
+class function TWNafUtilities.GenerateWindowNaf(AWidth: Int32;
+  const AK: TBigInteger): TCryptoLibByteArray;
+var
+  LPow2, LMask, LSign, LLength, LPos: Int32;
+  LK: TBigInteger;
+  LDigit: Int32;
+  LCarry: Boolean;
+begin
+  if AWidth = 2 then
+  begin
+    Result := GenerateNaf(AK);
+    Exit;
+  end;
+  if (AWidth < 2) or (AWidth > 8) then
+    raise EArgumentCryptoLibException.Create('must be in the range [2, 8]');
+  if AK.SignValue = 0 then
+  begin
+    System.SetLength(Result, 0);
+    Exit;
+  end;
+  System.SetLength(Result, AK.BitLength + 1);
+  LPow2 := 1 shl AWidth;
+  LMask := LPow2 - 1;
+  LSign := TBitOperations.Asr32(LPow2, 1);
+  LCarry := False;
+  LLength := 0;
+  LPos := 0;
+  LK := AK;
+  while LPos <= LK.BitLength do
+  begin
+    if (LK.TestBit(LPos) = LCarry) then
+    begin
+      Inc(LPos);
+      continue;
+    end;
+    LK := LK.ShiftRight(LPos);
+    LDigit := LK.Int32Value and LMask;
+    if LCarry then
+      Inc(LDigit);
+    LCarry := (LDigit and LSign) <> 0;
+    if LCarry then
+      LDigit := LDigit - LPow2;
+    if LLength > 0 then
+      Inc(LLength, LPos - 1)
+    else
+      Inc(LLength, LPos);
+    Result[LLength] := Byte(LDigit);
+    Inc(LLength);
+    LPos := AWidth;
+  end;
+  if System.Length(Result) > LLength then
+    Result := TrimBytes(Result, LLength);
+end;
+
+class function TWNafUtilities.GenerateJsf(const AG, AH: TBigInteger): TCryptoLibByteArray;
+var
+  LDigits, LJ, Ld0, Ld1, LOffset, Ln0, Ln1, Lu0, Lu1: Int32;
+  LJsf: TCryptoLibByteArray;
+  LK0, LK1: TBigInteger;
+begin
+  LDigits := System.Math.Max(AG.BitLength, AH.BitLength) + 1;
+  System.SetLength(LJsf, LDigits);
+  LK0 := AG;
+  LK1 := AH;
+  LJ := 0;
+  Ld0 := 0;
+  Ld1 := 0;
+  LOffset := 0;
+  while ((Ld0 or Ld1) <> 0) or (LK0.BitLength > LOffset) or (LK1.BitLength > LOffset) do
+  begin
+    Ln0 := (Int32(UInt32(LK0.GetInt32Value) shr LOffset) + Ld0) and 7;
+    Ln1 := (Int32(UInt32(LK1.GetInt32Value) shr LOffset) + Ld1) and 7;
+    Lu0 := Ln0 and 1;
+    if Lu0 <> 0 then
+    begin
+      Lu0 := Lu0 - (Ln0 and 2);
+      if (Ln0 + Lu0 = 4) and (Ln1 and 3 = 2) then
+        Lu0 := -Lu0;
+    end;
+    Lu1 := Ln1 and 1;
+    if Lu1 <> 0 then
+    begin
+      Lu1 := Lu1 - (Ln1 and 2);
+      if (Ln1 + Lu1 = 4) and (Ln0 and 3 = 2) then
+        Lu1 := -Lu1;
+    end;
+    if (Ld0 shl 1) = 1 + Lu0 then
+      Ld0 := Ld0 xor 1;
+    if (Ld1 shl 1) = 1 + Lu1 then
+      Ld1 := Ld1 xor 1;
+    Inc(LOffset);
+    if LOffset = 30 then
+    begin
+      LOffset := 0;
+      LK0 := LK0.ShiftRight(30);
+      LK1 := LK1.ShiftRight(30);
+    end;
+    LJsf[LJ] := Byte((Lu0 shl 4) or (Lu1 and $0F));
+    Inc(LJ);
+  end;
+  if System.Length(LJsf) > LJ then
+    Result := TrimBytes(LJsf, LJ)
+  else
+    Result := LJsf;
+end;
+
+class function TWNafUtilities.GetNafWeight(const AK: TBigInteger): Int32;
+var
+  L3k, LDiff: TBigInteger;
+begin
+  if AK.SignValue = 0 then
+    Exit(0);
+  L3k := AK.ShiftLeft(1).Add(AK);
+  LDiff := L3k.Xor(AK);
+  Result := LDiff.BitCount;
+end;
+
+class function TWNafUtilities.GetWNafPreCompInfo(const AP: IECPoint): IWNafPreCompInfo;
+begin
+  Result := GetWNafPreCompInfo(AP.Curve.GetPreCompInfo(AP, PRECOMP_NAME));
+end;
+
+class function TWNafUtilities.GetWNafPreCompInfo(const APreCompInfo: IPreCompInfo): IWNafPreCompInfo;
+var
+  LWNaf: IWNafPreCompInfo;
+begin
+  if Supports(APreCompInfo, IWNafPreCompInfo, LWNaf) then
+    Result := LWNaf
+  else
+    Result := nil;
+end;
+
+class function TWNafUtilities.GenerateCompactNaf(const AK: TBigInteger): TCryptoLibInt32Array;
+var
+  L3k, LDiff: TBigInteger;
+  LBits, LHighBit, LLength, LZeroes, LI: Int32;
+  LDigit: Int32;
+begin
+  if TBitOperations.Asr32(AK.BitLength, 16) <> 0 then
+    raise EArgumentCryptoLibException.Create('must have bitlength < 2^16');
+  if AK.SignValue = 0 then
+  begin
+    System.SetLength(Result, 0);
+    Exit;
+  end;
+  L3k := AK.ShiftLeft(1).Add(AK);
+  LBits := L3k.BitLength;
+  System.SetLength(Result, TBitOperations.Asr32(LBits, 1));
+  LDiff := L3k.Xor(AK);
+  LHighBit := LBits - 1;
+  LLength := 0;
+  LZeroes := 0;
+  LI := 1;
+  while LI < LHighBit do
+  begin
+    if not LDiff.TestBit(LI) then
+    begin
+      Inc(LZeroes);
+      Inc(LI);
+      continue;
+    end;
+    if AK.TestBit(LI) then
+      LDigit := -1
+    else
+      LDigit := 1;
+    Result[LLength] := (LDigit shl 16) or LZeroes;
+    Inc(LLength);
+    LZeroes := 1;
+    Inc(LI, 2);
+  end;
+  Result[LLength] := (1 shl 16) or LZeroes;
+  Inc(LLength);
+  if System.Length(Result) > LLength then
+    Result := Trim(Result, LLength);
+end;
+
+class function TWNafUtilities.GenerateCompactWindowNaf(AWidth: Int32;
+  const AK: TBigInteger): TCryptoLibInt32Array;
+var
+  LPow2, LMask, LSign, LLength, LPos, LDigit, LZeroes: Int32;
+  LK: TBigInteger;
+  LCarry: Boolean;
+begin
+  if AWidth = 2 then
+  begin
+    Result := GenerateCompactNaf(AK);
+    Exit;
+  end;
+  if (AWidth < 2) or (AWidth > 16) then
+    raise EArgumentCryptoLibException.Create('must be in the range [2, 16]');
+  if TBitOperations.Asr32(AK.BitLength, 16) <> 0 then
+    raise EArgumentCryptoLibException.Create('must have bitlength < 2^16');
+  if AK.SignValue = 0 then
+  begin
+    System.SetLength(Result, 0);
+    Exit;
+  end;
+  System.SetLength(Result, AK.BitLength div AWidth + 1);
+  LPow2 := 1 shl AWidth;
+  LMask := LPow2 - 1;
+  LSign := TBitOperations.Asr32(LPow2, 1);
+  LCarry := False;
+  LLength := 0;
+  LPos := 0;
+  LK := AK;
+
+  while LPos <= LK.BitLength do
+  begin
+    if LK.TestBit(LPos) = LCarry then
+    begin
+      Inc(LPos);
+      continue;
+    end;
+    LK := LK.ShiftRight(LPos);
+    LDigit := LK.Int32Value and LMask;
+    if LCarry then
+      Inc(LDigit);
+    LCarry := (LDigit and LSign) <> 0;
+    if LCarry then
+      LDigit := LDigit - LPow2;
+    if LLength > 0 then
+      LZeroes := LPos - 1
+    else
+      LZeroes := LPos;
+    Result[LLength] := (LDigit shl 16) or LZeroes;
+    Inc(LLength);
+    LPos := AWidth;
+  end;
+
+  if System.Length(Result) > LLength then
+    Result := Trim(Result, LLength);
+end;
+
+type
+  TPrecomputeCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FP: IECPoint;
+    FMinWidth: Int32;
+    FIncludeNegated: Boolean;
+    function CheckExisting(const AExistingWNaf: IWNafPreCompInfo; AWidth, AReqPreCompLen: Int32;
+      AIncludeNegated: Boolean): Boolean;
+    function CheckTable(const ATable: TCryptoLibGenericArray<IECPoint>; AReqLen: Int32): Boolean;
+  public
+    constructor Create(const AP: IECPoint; AMinWidth: Int32; AIncludeNegated: Boolean);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TPrecomputeCallback.Create(const AP: IECPoint; AMinWidth: Int32; AIncludeNegated: Boolean);
+begin
+  inherited Create;
+  FP := AP;
+  FMinWidth := AMinWidth;
+  FIncludeNegated := AIncludeNegated;
+end;
+
+function TPrecomputeCallback.CheckTable(const ATable: TCryptoLibGenericArray<IECPoint>;
+  AReqLen: Int32): Boolean;
+begin
+  Result := (ATable <> nil) and (System.Length(ATable) >= AReqLen);
+end;
+
+function TPrecomputeCallback.CheckExisting(const AExistingWNaf: IWNafPreCompInfo;
+  AWidth, AReqPreCompLen: Int32; AIncludeNegated: Boolean): Boolean;
+var
+  LConfWidth: Int32;
+begin
+  if AExistingWNaf = nil then
+    Exit(False);
+  LConfWidth := AExistingWNaf.ConfWidth;
+  Result := (AExistingWNaf.Width >= System.Math.Max(LConfWidth, AWidth)) and
+    CheckTable(AExistingWNaf.PreComp, AReqPreCompLen) and
+    (not AIncludeNegated or CheckTable(AExistingWNaf.PreCompNeg, AReqPreCompLen));
+end;
+
+function TPrecomputeCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+var
+  LExistingWNaf: IWNafPreCompInfo;
+  LResultInfo: IWNafPreCompInfo;
+  LC: IECCurve;
+  LPreComp, LPreCompNeg: TCryptoLibGenericArray<IECPoint>;
+  LTwiceP: IECPoint;
+  LWidth, LReqPreCompLen, LIniPreCompLen, LCurPreCompLen, LPos: Int32;
+  LLast, LIsoTwiceP: IECPoint;
+  LIso, LIso2, LIso3: IECFieldElement;
+begin
+  if not Supports(AExisting, IWNafPreCompInfo, LExistingWNaf) then
+    LExistingWNaf := nil;
+
+  LWidth := System.Math.Max(2, System.Math.Min(TWNafUtilities.MAX_WIDTH, FMinWidth));
+  LReqPreCompLen := 1 shl (LWidth - 2);
+
+  if CheckExisting(LExistingWNaf, LWidth, LReqPreCompLen, FIncludeNegated) then
+  begin
+    LExistingWNaf.DecrementPromotionCountdown;
+    Result := LExistingWNaf;
+    Exit;
+  end;
+
+  LResultInfo := TWNafPreCompInfo.Create as IWNafPreCompInfo;
+  LC := FP.Curve;
+  LPreComp := nil;
+  LPreCompNeg := nil;
+  LTwiceP := nil;
+
+  if LExistingWNaf <> nil then
+  begin
+    LResultInfo.PromotionCountdown := LExistingWNaf.DecrementPromotionCountdown;
+    LResultInfo.ConfWidth := LExistingWNaf.ConfWidth;
+    LPreComp := LExistingWNaf.PreComp;
+    LPreCompNeg := LExistingWNaf.PreCompNeg;
+    LTwiceP := LExistingWNaf.Twice;
+  end;
+
+  LWidth := System.Math.Min(TWNafUtilities.MAX_WIDTH, System.Math.Max(LResultInfo.ConfWidth, LWidth));
+  LReqPreCompLen := 1 shl (LWidth - 2);
+
+  LIniPreCompLen := 0;
+  if LPreComp <> nil then
+    LIniPreCompLen := System.Length(LPreComp);
+
+  LIso := nil;
+  if LIniPreCompLen < LReqPreCompLen then
+  begin
+    LPreComp := TWNafUtilities.ResizeTable(LPreComp, LReqPreCompLen);
+
+    if LReqPreCompLen = 1 then
+      LPreComp[0] := FP.Normalize()
+    else
+    begin
+      LCurPreCompLen := LIniPreCompLen;
+      if LCurPreCompLen = 0 then
+      begin
+        LPreComp[0] := FP;
+        LCurPreCompLen := 1;
+      end;
+
+      if LReqPreCompLen = 2 then
+        LPreComp[1] := FP.ThreeTimes()
+      else
+      begin
+        LLast := LPreComp[LCurPreCompLen - 1];
+        if LTwiceP = nil then
+        begin
+          LIsoTwiceP := LPreComp[0].Twice();
+          LTwiceP := LIsoTwiceP;
+          { Fp quasi-isomorphism: affine twiceP and scale last for cheaper additions }
+          if (not LIsoTwiceP.GetIsInfinity) and TECAlgorithms.IsFpCurve(LC) and
+            (LC.FieldSize >= 64) then
+            case LC.CoordinateSystem of
+              TECCurveConstants.COORD_JACOBIAN, TECCurveConstants.COORD_JACOBIAN_CHUDNOVSKY,
+              TECCurveConstants.COORD_JACOBIAN_MODIFIED:
+                begin
+                  LIso := LIsoTwiceP.GetZCoord(0);
+                  LIsoTwiceP := LC.CreatePoint(LIsoTwiceP.XCoord.ToBigInteger(),
+                    LIsoTwiceP.YCoord.ToBigInteger());
+                  LIso2 := LIso.Square();
+                  LIso3 := LIso2.Multiply(LIso);
+                  LLast := LLast.ScaleX(LIso2).ScaleY(LIso3);
+                  if LIniPreCompLen = 0 then
+                    LPreComp[0] := LLast;
+                end;
+            end;
+        end
+        else
+          LIsoTwiceP := LTwiceP;
+        while LCurPreCompLen < LReqPreCompLen do
+        begin
+          LPreComp[LCurPreCompLen] := LLast.Add(LIsoTwiceP);
+          LLast := LPreComp[LCurPreCompLen];
+          Inc(LCurPreCompLen);
+        end;
+      end;
+
+      LC.NormalizeAll(LPreComp, LIniPreCompLen, LReqPreCompLen - LIniPreCompLen, LIso);
+    end;
+  end;
+
+  if FIncludeNegated then
+  begin
+    if LPreCompNeg = nil then
+      LPos := 0
+    else
+      LPos := System.Length(LPreCompNeg);
+    if LPos < LReqPreCompLen then
+    begin
+      SetLength(LPreCompNeg, LReqPreCompLen);
+      while LPos < LReqPreCompLen do
+      begin
+        LPreCompNeg[LPos] := LPreComp[LPos].Negate();
+        Inc(LPos);
+      end;
+    end;
+  end;
+
+  LResultInfo.PreComp := LPreComp;
+  LResultInfo.PreCompNeg := LPreCompNeg;
+  LResultInfo.Twice := LTwiceP;
+  LResultInfo.Width := LWidth;
+  Result := LResultInfo;
+end;
+
+type
+  TPrecomputeWithPointMapCallback = class sealed(TInterfacedObject, IPreCompCallback)
+  strict private
+    FPoint: IECPoint;
+    FPointMap: IECPointMap;
+    FFromWNaf: IWNafPreCompInfo;
+    FIncludeNegated: Boolean;
+    function CheckTable(const ATable: TCryptoLibGenericArray<IECPoint>; AReqLen: Int32): Boolean;
+    function CheckExisting(const AExistingWNaf: IWNafPreCompInfo; AWidth, AReqPreCompLen: Int32;
+      AIncludeNegated: Boolean): Boolean;
+  public
+    constructor Create(const APoint: IECPoint; const APointMap: IECPointMap;
+      const AFromWNaf: IWNafPreCompInfo; AIncludeNegated: Boolean);
+    function Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+  end;
+
+constructor TPrecomputeWithPointMapCallback.Create(const APoint: IECPoint;
+  const APointMap: IECPointMap; const AFromWNaf: IWNafPreCompInfo; AIncludeNegated: Boolean);
+begin
+  inherited Create;
+  FPoint := APoint;
+  FPointMap := APointMap;
+  FFromWNaf := AFromWNaf;
+  FIncludeNegated := AIncludeNegated;
+end;
+
+function TPrecomputeWithPointMapCallback.CheckTable(
+  const ATable: TCryptoLibGenericArray<IECPoint>; AReqLen: Int32): Boolean;
+begin
+  Result := (ATable <> nil) and (System.Length(ATable) >= AReqLen);
+end;
+
+function TPrecomputeWithPointMapCallback.CheckExisting(
+  const AExistingWNaf: IWNafPreCompInfo; AWidth, AReqPreCompLen: Int32;
+  AIncludeNegated: Boolean): Boolean;
+begin
+  Result := (AExistingWNaf <> nil) and (AExistingWNaf.Width >= AWidth) and
+    CheckTable(AExistingWNaf.PreComp, AReqPreCompLen) and
+    (not AIncludeNegated or CheckTable(AExistingWNaf.PreCompNeg, AReqPreCompLen));
+end;
+
+function TPrecomputeWithPointMapCallback.Precompute(const AExisting: IPreCompInfo): IPreCompInfo;
+var
+  LExistingWNaf: IWNafPreCompInfo;
+  LResultInfo: IWNafPreCompInfo;
+  LWidth, LReqPreCompLen, LI: Int32;
+  LPreCompFrom, LPreComp, LPreCompNeg: TCryptoLibGenericArray<IECPoint>;
+  LTwiceFrom: IECPoint;
+begin
+  if not Supports(AExisting, IWNafPreCompInfo, LExistingWNaf) then
+    LExistingWNaf := nil;
+
+  LWidth := FFromWNaf.Width;
+  LReqPreCompLen := System.Length(FFromWNaf.PreComp);
+
+  if CheckExisting(LExistingWNaf, LWidth, LReqPreCompLen, FIncludeNegated) then
+  begin
+    LExistingWNaf.DecrementPromotionCountdown;
+    Result := LExistingWNaf;
+    Exit;
+  end;
+
+  LResultInfo := TWNafPreCompInfo.Create as IWNafPreCompInfo;
+  LResultInfo.PromotionCountdown := FFromWNaf.PromotionCountdown;
+
+  LTwiceFrom := FFromWNaf.Twice;
+  if LTwiceFrom <> nil then
+    LResultInfo.Twice := FPointMap.Map(LTwiceFrom);
+
+  LPreCompFrom := FFromWNaf.PreComp;
+  System.SetLength(LPreComp, System.Length(LPreCompFrom));
+  for LI := 0 to System.High(LPreCompFrom) do
+    LPreComp[LI] := FPointMap.Map(LPreCompFrom[LI]);
+  LResultInfo.PreComp := LPreComp;
+  LResultInfo.Width := LWidth;
+
+  if FIncludeNegated then
+  begin
+    System.SetLength(LPreCompNeg, System.Length(LPreComp));
+    for LI := 0 to System.High(LPreComp) do
+      LPreCompNeg[LI] := LPreComp[LI].Negate();
+    LResultInfo.PreCompNeg := LPreCompNeg;
+  end;
+
+  Result := LResultInfo;
+end;
+
+class function TWNafUtilities.PrecomputeWithPointMap(const AP: IECPoint;
+  const APointMap: IECPointMap; const AFromWNaf: IWNafPreCompInfo;
+  AIncludeNegated: Boolean): IWNafPreCompInfo;
+var
+  LResult: IPreCompInfo;
+  LWNaf: IWNafPreCompInfo;
+begin
+  LResult := AP.Curve.Precompute(AP, PRECOMP_NAME,
+    TPrecomputeWithPointMapCallback.Create(AP, APointMap, AFromWNaf, AIncludeNegated) as IPreCompCallback);
+  if not Supports(LResult, IWNafPreCompInfo, LWNaf) then
+    raise EInvalidCastCryptoLibException.Create('Expected IWNafPreCompInfo');
+  Result := LWNaf;
+end;
+
+class function TWNafUtilities.Precompute(const AP: IECPoint; AMinWidth: Int32;
+  AIncludeNegated: Boolean): IWNafPreCompInfo;
+var
+  LResult: IPreCompInfo;
+  LWNaf: IWNafPreCompInfo;
+begin
+  LResult := AP.Curve.Precompute(AP, PRECOMP_NAME,
+    TPrecomputeCallback.Create(AP, AMinWidth, AIncludeNegated) as IPreCompCallback);
+  if not Supports(LResult, IWNafPreCompInfo, LWNaf) then
+    raise EInvalidCastCryptoLibException.Create('Expected IWNafPreCompInfo');
+  Result := LWNaf;
+end;
+
+end.

+ 12 - 52
CryptoLib/src/Math/EC/Multiplier/ClpWTauNafPreCompInfo.pas

@@ -6,15 +6,8 @@
 { *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
 { *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
 
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
 { * ******************************************************************************* * }
 
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
 unit ClpWTauNafPreCompInfo;
 
 {$I ..\..\..\Include\CryptoLib.inc}
@@ -22,67 +15,34 @@ unit ClpWTauNafPreCompInfo;
 interface
 
 uses
+  ClpIECCore,
   ClpIPreCompInfo,
-  ClpIECC,
-  ClpCryptoLibTypes,
-  ClpIWTauNafPreCompInfo;
+  ClpIWTauNafPreCompInfo,
+  ClpCryptoLibTypes;
 
 type
-  /// **
-  // * Class holding precomputation data for the WTNAF (Window
-  // * <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
-  // */
-  TWTauNafPreCompInfo = class(TInterfacedObject, IPreCompInfo,
+  TWTauNafPreCompInfo = class sealed(TInterfacedObject, IPreCompInfo,
     IWTauNafPreCompInfo)
-
   strict private
-    function GetPreComp: TCryptoLibGenericArray<IAbstractF2mPoint>; virtual;
-    procedure SetPreComp(const value
-      : TCryptoLibGenericArray<IAbstractF2mPoint>); virtual;
-  strict protected
-  var
-    // /**
-    // * Array holding the precomputed <code>AbstractF2mPoint</code>s used for the
-    // * WTNAF multiplication in <code>
-    // * math.ec.multiplier.WTauNafMultiplier.multiply()
-    // * WTauNafMultiplier.multiply()</code>.
-    // */
-    Fm_preComp: TCryptoLibGenericArray<IAbstractF2mPoint>;
-
+    FPreComp: TCryptoLibGenericArray<IAbstractF2mPoint>;
+    function GetPreComp: TCryptoLibGenericArray<IAbstractF2mPoint>;
+    procedure SetPreComp(const AValue: TCryptoLibGenericArray<IAbstractF2mPoint>);
   public
-    destructor Destroy; override;
-
-    property PreComp: TCryptoLibGenericArray<IAbstractF2mPoint> read GetPreComp
-      write SetPreComp;
+    property PreComp: TCryptoLibGenericArray<IAbstractF2mPoint> read GetPreComp write SetPreComp;
   end;
 
 implementation
 
 { TWTauNafPreCompInfo }
 
-destructor TWTauNafPreCompInfo.Destroy;
-var
-  i: Integer;
-begin
-  if Assigned(Fm_preComp) then
-  begin
-    for i := 0 to Length(Fm_preComp) - 1 do
-      Fm_preComp[i] := nil;
-    Fm_preComp := nil;
-  end;
-  inherited;
-end;
-
-function TWTauNafPreCompInfo.GetPreComp
-  : TCryptoLibGenericArray<IAbstractF2mPoint>;
+function TWTauNafPreCompInfo.GetPreComp: TCryptoLibGenericArray<IAbstractF2mPoint>;
 begin
-  Result := Fm_preComp;
+  Result := FPreComp;
 end;
 
-procedure TWTauNafPreCompInfo.SetPreComp(const value
-  : TCryptoLibGenericArray<IAbstractF2mPoint>);
+procedure TWTauNafPreCompInfo.SetPreComp(const AValue: TCryptoLibGenericArray<IAbstractF2mPoint>);
 begin
-  Fm_preComp := value;
+  FPreComp := AValue;
 end;
 
 end.

+ 39 - 68
CryptoLib/src/Math/Field/ClpFiniteFields.pas

@@ -22,111 +22,82 @@ unit ClpFiniteFields;
 interface
 
 uses
+  SysUtils,
   ClpBigInteger,
   ClpCryptoLibTypes,
+  ClpIFiniteField,
+  ClpIPolynomialExtensionField,
   ClpPrimeField,
   ClpGF2Polynomial,
-  ClpIGF2Polynomial,
-  ClpGenericPolynomialExtensionField,
-  ClpIPolynomialExtensionField,
-  ClpIFiniteField;
+  ClpGenericPolynomialExtensionField;
 
 resourcestring
-  SInvalidCharacteristic = 'Must be >= 2 , " characteristic "';
-  SUnConstantTerm =
-    'Irreducible polynomials in GF(2) must have constant term, "exponents"';
-  SPolynomialError =
-    'Polynomial Exponents must be montonically increasing", "exponents"';
+  SIrreduciblePolynomialsConstantTerm = 'Irreducible polynomials in GF(2) must have constant term';
+  SPolynomialExponentsMonotonic = 'Polynomial exponents must be monotonically increasing';
+  SCharacteristicMustBeAtLeast2 = 'Must be >= 2';
 
 type
-  TFiniteFields = class abstract(TObject)
-
+  TFiniteFields = class sealed(TObject)
   strict private
     class var
-
       FGF_2, FGF_3: IFiniteField;
-
-    class procedure Boot(); static;
-    class constructor FiniteFields();
-
+    class constructor Create;
   public
-    class function GetBinaryExtensionField(const exponents
-      : TCryptoLibInt32Array): IPolynomialExtensionField; static;
-
-    class function GetPrimeField(const characteristic: TBigInteger)
+    class function GetBinaryExtensionField(const AExponents: TCryptoLibInt32Array)
+      : IPolynomialExtensionField; static;
+    class function GetPrimeField(const ACharacteristic: TBigInteger)
       : IFiniteField; static;
+    class property GF_2: IFiniteField read FGF_2;
+    class property GF_3: IFiniteField read FGF_3;
   end;
 
 implementation
 
 { TFiniteFields }
 
-class procedure TFiniteFields.Boot;
-begin
-
-  FGF_2 := TPrimeField.Create(TBigInteger.ValueOf(2));
-  FGF_3 := TPrimeField.Create(TBigInteger.ValueOf(3));
-end;
-
-class constructor TFiniteFields.FiniteFields;
+class constructor TFiniteFields.Create;
 begin
-  TFiniteFields.Boot;
+  FGF_2 := TPrimeField.Create(TBigInteger.Two);
+  FGF_3 := TPrimeField.Create(TBigInteger.Three);
 end;
 
-class function TFiniteFields.GetBinaryExtensionField(const exponents
-  : TCryptoLibInt32Array): IPolynomialExtensionField;
+class function TFiniteFields.GetBinaryExtensionField
+  (const AExponents: TCryptoLibInt32Array): IPolynomialExtensionField;
 var
-  i: Int32;
+  LExponents: TCryptoLibInt32Array;
+  I: Int32;
 begin
-  if (exponents[0] <> 0) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SUnConstantTerm);
-  end;
-
-  for i := 1 to System.Pred(System.Length(exponents)) do
-
+  if System.Length(AExponents) = 0 then
+    raise EArgumentCryptoLibException.CreateRes(@SIrreduciblePolynomialsConstantTerm);
+  if AExponents[0] <> 0 then
+    raise EArgumentCryptoLibException.CreateRes(@SIrreduciblePolynomialsConstantTerm);
+  for I := 1 to System.High(AExponents) do
   begin
-    if (exponents[i] <= exponents[i - 1]) then
-    begin
-      raise EArgumentCryptoLibException.CreateRes(@SPolynomialError);
-    end;
+    if AExponents[I] <= AExponents[I - 1] then
+      raise EArgumentCryptoLibException.CreateRes(@SPolynomialExponentsMonotonic);
   end;
-
   Result := TGenericPolynomialExtensionField.Create(FGF_2,
-    TGF2Polynomial.Create(exponents) as IGF2Polynomial);
+    TGF2Polynomial.Create(AExponents) as IPolynomial);
 end;
 
-class function TFiniteFields.GetPrimeField(const characteristic: TBigInteger)
+class function TFiniteFields.GetPrimeField(const ACharacteristic: TBigInteger)
   : IFiniteField;
 var
-  bitLength: Int32;
+  LBitLength: Int32;
 begin
-  bitLength := characteristic.bitLength;
-  if ((characteristic.SignValue <= 0) or (bitLength < 2)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidCharacteristic);
-  end;
-
-  if (bitLength < 3) then
+  LBitLength := ACharacteristic.BitLength;
+  if (ACharacteristic.SignValue <= 0) or (LBitLength < 2) then
+    raise EArgumentCryptoLibException.CreateRes(@SCharacteristicMustBeAtLeast2);
+  if LBitLength < 3 then
   begin
-    case characteristic.Int32Value of
+    case ACharacteristic.Int32Value of
       2:
-        begin
-          Result := FGF_2;
-          Exit;
-        end;
-
+        Exit(FGF_2);
       3:
-        begin
-          Result := FGF_3;
-          Exit;
-        end;
+        Exit(FGF_3);
     end;
-
   end;
-
-  Result := TPrimeField.Create(characteristic);
-
+  Result := TPrimeField.Create(ACharacteristic);
 end;
 
 end.

+ 23 - 53
CryptoLib/src/Math/Field/ClpGF2Polynomial.pas

@@ -24,86 +24,56 @@ interface
 uses
   ClpCryptoLibTypes,
   ClpArrayUtilities,
-  ClpIGF2Polynomial,
-  ClpIPolynomial;
+  ClpIPolynomial,
+  ClpIGF2Polynomial;
 
 type
-  TGF2Polynomial = class(TInterfacedObject, IPolynomial, IGF2Polynomial)
-
+  TGF2Polynomial = class sealed(TInterfacedObject, IPolynomial, IGF2Polynomial)
   strict private
-    function GetDegree: Int32; virtual;
-    function GetExponents: TCryptoLibInt32Array; inline;
-  strict protected
-  var
-    Fexponents: TCryptoLibInt32Array;
+    FExponents: TCryptoLibInt32Array;
 
+    function GetDegree: Int32;
+    function GetExponentsPresent: TCryptoLibInt32Array;
   public
-    constructor Create(const exponents: TCryptoLibInt32Array);
-
-    function GetExponentsPresent(): TCryptoLibInt32Array; virtual;
-
-    function Equals(other: TObject): Boolean; overload; override;
-    function Equals(const other: IGF2Polynomial): Boolean; reintroduce;
-      overload;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
+    constructor Create(const AExponents: TCryptoLibInt32Array);
+    function Equals(const AOther: IPolynomial): Boolean; reintroduce;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
     property Degree: Int32 read GetDegree;
-
-    property exponents: TCryptoLibInt32Array read GetExponents;
-
+    property ExponentsPresent: TCryptoLibInt32Array read GetExponentsPresent;
   end;
 
 implementation
 
 { TGF2Polynomial }
 
-constructor TGF2Polynomial.Create(const exponents: TCryptoLibInt32Array);
+constructor TGF2Polynomial.Create(const AExponents: TCryptoLibInt32Array);
 begin
-  Fexponents := System.Copy(exponents);
-end;
-
-function TGF2Polynomial.Equals(const other: IGF2Polynomial): Boolean;
-begin
-
-  if ((Self as IGF2Polynomial) = other) then
-  begin
-    Result := true;
-    Exit;
-  end;
-
-  if (other = Nil) then
-  begin
-    Result := false;
-    Exit;
-  end;
-  Result := TArrayUtilities.AreEqual<Int32>(Fexponents, other.exponents);
-end;
-
-function TGF2Polynomial.Equals(other: TObject): Boolean;
-begin
-  Result := Self.Equals((other as TGF2Polynomial) as IGF2Polynomial);
+  Inherited Create();
+  FExponents := TArrayUtilities.CopyOf(AExponents, System.Length(AExponents));
 end;
 
 function TGF2Polynomial.GetDegree: Int32;
 begin
-  Result := Fexponents[System.Length(Fexponents) - 1];
+  Result := FExponents[System.High(FExponents)];
 end;
 
-function TGF2Polynomial.GetExponents: TCryptoLibInt32Array;
+function TGF2Polynomial.GetExponentsPresent: TCryptoLibInt32Array;
 begin
-  Result := Fexponents;
+  Result := TArrayUtilities.CopyOf(FExponents, System.Length(FExponents));
 end;
 
-function TGF2Polynomial.GetExponentsPresent: TCryptoLibInt32Array;
+function TGF2Polynomial.Equals(const AOther: IPolynomial): Boolean;
 begin
-  Result := System.Copy(Fexponents);
+  if AOther = nil then
+    Exit(False);
+  Result := (Degree = AOther.Degree) and
+    TArrayUtilities.AreEqual<Int32>(FExponents, AOther.ExponentsPresent);
 end;
 
-function TGF2Polynomial.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+function TGF2Polynomial.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI};
 begin
-  Result := TArrayUtilities.GetArrayHashCode(Fexponents);
+  Result := TArrayUtilities.GetArrayHashCode(FExponents);
 end;
 
 end.

+ 50 - 66
CryptoLib/src/Math/Field/ClpGenericPolynomialExtensionField.pas

@@ -22,112 +22,96 @@ unit ClpGenericPolynomialExtensionField;
 interface
 
 uses
-  ClpBitOperations,
   ClpBigInteger,
+  ClpCryptoLibTypes,
+  ClpBitOperations,
   ClpIFiniteField,
   ClpIPolynomial,
-  ClpIGenericPolynomialExtensionField,
-  ClpIPolynomialExtensionField;
+  ClpIExtensionField,
+  ClpIPolynomialExtensionField,
+  ClpIGenericPolynomialExtensionField;
 
 type
-  TGenericPolynomialExtensionField = class(TInterfacedObject,
-    IPolynomialExtensionField, IGenericPolynomialExtensionField)
-
+  TGenericPolynomialExtensionField = class sealed(TInterfacedObject,
+    IFiniteField, IExtensionField, IPolynomialExtensionField,
+    IGenericPolynomialExtensionField)
   strict private
-    function GetCharacteristic: TBigInteger; virtual;
-    function GetDegree: Int32; virtual;
-    function GetDimension: Int32; virtual;
-    function GetMinimalPolynomial: IPolynomial; virtual;
-    function GetSubField: IFiniteField; virtual;
-  strict protected
-  var
-    Fsubfield: IFiniteField;
-    FminimalPolynomial: IPolynomial;
+    FSubfield: IFiniteField;
+    FMinimalPolynomial: IPolynomial;
+
+    function GetCharacteristic: TBigInteger;
+    function GetDimension: Int32;
+    function GetSubfield: IFiniteField;
+    function GetDegree: Int32;
+    function GetMinimalPolynomial: IPolynomial;
+  public
+    constructor Create(const ASubfield: IFiniteField;
+      const APolynomial: IPolynomial);
+    function Equals(const AOther: IFiniteField): Boolean; reintroduce;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
     property Characteristic: TBigInteger read GetCharacteristic;
     property Dimension: Int32 read GetDimension;
-    property subfield: IFiniteField read GetSubField;
+    property Subfield: IFiniteField read GetSubfield;
     property Degree: Int32 read GetDegree;
     property MinimalPolynomial: IPolynomial read GetMinimalPolynomial;
-
-  public
-    constructor Create(const subfield: IFiniteField;
-      const polynomial: IPolynomial);
-
-    function Equals(other: TObject): Boolean; overload; override;
-    function Equals(const other: IGenericPolynomialExtensionField): Boolean;
-      reintroduce; overload;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
   end;
 
 implementation
 
 { TGenericPolynomialExtensionField }
 
-constructor TGenericPolynomialExtensionField.Create(const subfield
-  : IFiniteField; const polynomial: IPolynomial);
+constructor TGenericPolynomialExtensionField.Create(const ASubfield: IFiniteField;
+  const APolynomial: IPolynomial);
 begin
-  Fsubfield := subfield;
-  FminimalPolynomial := polynomial;
+  Inherited Create();
+  FSubfield := ASubfield;
+  FMinimalPolynomial := APolynomial;
 end;
 
-function TGenericPolynomialExtensionField.Equals(const other
-  : IGenericPolynomialExtensionField): Boolean;
+function TGenericPolynomialExtensionField.GetCharacteristic: TBigInteger;
 begin
-  if ((Self as IGenericPolynomialExtensionField) = other) then
-  begin
-    Result := true;
-    Exit;
-  end;
-
-  if (other = Nil) then
-  begin
-    Result := false;
-    Exit;
-  end;
-  Result := (subfield as TObject).Equals(other.subfield as TObject) and
-    (MinimalPolynomial as TObject).Equals(other.MinimalPolynomial as TObject);
+  Result := FSubfield.Characteristic;
 end;
 
-function TGenericPolynomialExtensionField.Equals(other: TObject): Boolean;
+function TGenericPolynomialExtensionField.GetDimension: Int32;
 begin
-  Result := Self.Equals((other as TGenericPolynomialExtensionField)
-    as IGenericPolynomialExtensionField);
+  Result := FSubfield.Dimension * FMinimalPolynomial.Degree;
 end;
 
-function TGenericPolynomialExtensionField.GetCharacteristic: TBigInteger;
+function TGenericPolynomialExtensionField.GetSubfield: IFiniteField;
 begin
-  Result := Fsubfield.Characteristic;
+  Result := FSubfield;
 end;
 
 function TGenericPolynomialExtensionField.GetDegree: Int32;
 begin
-  Result := FminimalPolynomial.Degree;
-end;
-
-function TGenericPolynomialExtensionField.GetDimension: Int32;
-begin
-  Result := Fsubfield.Dimension * FminimalPolynomial.Degree;
+  Result := FMinimalPolynomial.Degree;
 end;
 
-function TGenericPolynomialExtensionField.GetHashCode: {$IFDEF DELPHI}Int32;
-{$ELSE}PtrInt; {$ENDIF DELPHI}
+function TGenericPolynomialExtensionField.GetMinimalPolynomial: IPolynomial;
 begin
-  Result := (subfield as TObject).GetHashCode()
-    xor Int32(TBitOperations.RotateLeft32((MinimalPolynomial as TObject)
-    .GetHashCode(), 16));
+  Result := FMinimalPolynomial;
 end;
 
-function TGenericPolynomialExtensionField.GetMinimalPolynomial: IPolynomial;
+function TGenericPolynomialExtensionField.Equals(const AOther: IFiniteField): Boolean;
+var
+  LOther: IGenericPolynomialExtensionField;
+  LExt: IExtensionField;
 begin
-  Result := FminimalPolynomial;
+  if AOther = nil then
+    Exit(False);
+  if not Supports(AOther, IGenericPolynomialExtensionField, LOther) then
+    Exit(False);
+  LExt := AOther as IExtensionField;
+  Result := FSubfield.Equals(LExt.Subfield) and
+    FMinimalPolynomial.Equals(LOther.MinimalPolynomial);
 end;
 
-function TGenericPolynomialExtensionField.GetSubField: IFiniteField;
+function TGenericPolynomialExtensionField.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI};
 begin
-  Result := Fsubfield;
+  Result := Int32(UInt32(FSubfield.GetHashCode) xor
+    TBitOperations.RotateLeft32(UInt32(FMinimalPolynomial.GetHashCode), 16));
 end;
 
 end.

+ 22 - 43
CryptoLib/src/Math/Field/ClpPrimeField.pas

@@ -23,66 +23,39 @@ interface
 
 uses
   ClpBigInteger,
+  ClpCryptoLibTypes,
   ClpIFiniteField,
   ClpIPrimeField;
 
 type
-  TPrimeField = class(TInterfacedObject, IFiniteField, IPrimeField)
-
+  TPrimeField = class sealed(TInterfacedObject, IFiniteField, IPrimeField)
   strict private
-    function GetCharacteristic: TBigInteger; virtual;
-    function GetDimension: Int32; virtual;
-
-  strict protected
-  var
-    Fcharacteristic: TBigInteger;
+    FCharacteristic: TBigInteger;
 
+    function GetCharacteristic: TBigInteger;
+    function GetDimension: Int32;
   public
-    constructor Create(const characteristic: TBigInteger);
+    constructor Create(const ACharacteristic: TBigInteger);
+    function Equals(const AOther: IFiniteField): Boolean; reintroduce;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
-    function Equals(other: TObject): Boolean; overload; override;
-    function Equals(const other: IPrimeField): Boolean; reintroduce; overload;
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    property characteristic: TBigInteger read GetCharacteristic;
+    property Characteristic: TBigInteger read GetCharacteristic;
     property Dimension: Int32 read GetDimension;
-
   end;
 
 implementation
 
 { TPrimeField }
 
-constructor TPrimeField.Create(const characteristic: TBigInteger);
-begin
-  Fcharacteristic := characteristic;
-end;
-
-function TPrimeField.Equals(const other: IPrimeField): Boolean;
-begin
-  if ((Self as IPrimeField) = other) then
-  begin
-    Result := true;
-    Exit;
-  end;
-
-  if (other = Nil) then
-  begin
-    Result := false;
-    Exit;
-  end;
-  Result := Fcharacteristic.Equals(other.characteristic);
-end;
-
-function TPrimeField.Equals(other: TObject): Boolean;
+constructor TPrimeField.Create(const ACharacteristic: TBigInteger);
 begin
-  Result := Self.Equals((other as TPrimeField) as IPrimeField);
+  Inherited Create();
+  FCharacteristic := ACharacteristic;
 end;
 
 function TPrimeField.GetCharacteristic: TBigInteger;
 begin
-  Result := Fcharacteristic;
+  Result := FCharacteristic;
 end;
 
 function TPrimeField.GetDimension: Int32;
@@ -90,10 +63,16 @@ begin
   Result := 1;
 end;
 
-function TPrimeField.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+function TPrimeField.Equals(const AOther: IFiniteField): Boolean;
+begin
+  if AOther = nil then
+    Exit(False);
+  Result := FCharacteristic.Equals(AOther.Characteristic);
+end;
+
+function TPrimeField.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI};
 begin
-  Result := Fcharacteristic.GetHashCode();
+  Result := FCharacteristic.GetHashCode();
 end;
 
 end.

+ 1 - 1
CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk

@@ -56,7 +56,7 @@ contains
   ClpBigInteger in '..\..\Math\ClpBigInteger.pas',
   ClpCurve25519Custom in '..\..\Math\EC\Custom\Djb\ClpCurve25519Custom.pas',
   ClpLongArray in '..\..\Math\EC\ClpLongArray.pas',
-  ClpECC in '..\..\Math\EC\ClpECC.pas',
+  ClpECCurve in '..\..\Math\EC\ClpECCurve.pas',
   ClpIX25519PublicKeyParameters in '..\..\Interfaces\ClpIX25519PublicKeyParameters.pas',
   ClpIXSalsa20Engine in '..\..\Interfaces\ClpIXSalsa20Engine.pas',
   ClpIX25519PrivateKeyParameters in '..\..\Interfaces\ClpIX25519PrivateKeyParameters.pas',