Ver Fonte

some ec updates

Ugochukwu Mmaduekwe há 5 dias atrás
pai
commit
60e8c16d32

+ 5 - 5
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -72,8 +72,6 @@ uses
   ClpCryptoLibComparers in '..\..\CryptoLib\src\Misc\ClpCryptoLibComparers.pas',
   ClpCryptoLibTypes in '..\..\CryptoLib\src\Misc\ClpCryptoLibTypes.pas',
   ClpCryptoProObjectIdentifiers in '..\..\CryptoLib\src\Asn1\CryptoPro\ClpCryptoProObjectIdentifiers.pas',
-  ClpCustomNamedCurves in '..\..\CryptoLib\src\Crypto\EC\ClpCustomNamedCurves.pas',
-  ClpECUtilities in '..\..\CryptoLib\src\Crypto\EC\ClpECUtilities.pas',
   ClpDateTimeUtilities in '..\..\CryptoLib\src\GeneralUtilities\ClpDateTimeUtilities.pas',
   ClpDefaultDigestCalculator in '..\..\CryptoLib\src\Crypto\Operators\ClpDefaultDigestCalculator.pas',
   ClpDefaultDigestResult in '..\..\CryptoLib\src\Crypto\Operators\ClpDefaultDigestResult.pas',
@@ -270,7 +268,7 @@ uses
   ClpISecP256R1Custom in '..\..\CryptoLib\src\Interfaces\Math\EC\Custom\Sec\ClpISecP256R1Custom.pas',
   ClpISecP384R1Custom in '..\..\CryptoLib\src\Interfaces\Math\EC\Custom\Sec\ClpISecP384R1Custom.pas',
   ClpISecP521R1Custom in '..\..\CryptoLib\src\Interfaces\Math\EC\Custom\Sec\ClpISecP521R1Custom.pas',
-  ClpISecT283Custom in '..\..\CryptoLib\src\Interfaces\Math\EC\Custom\Sec\ClpISecT283Custom.pas',
+  ClpISecT283K1Custom in '..\..\CryptoLib\src\Interfaces\Math\EC\Custom\Sec\ClpISecT283K1Custom.pas',
   ClpISecureRandom in '..\..\CryptoLib\src\Interfaces\Crypto\Randoms\ClpISecureRandom.pas',
   ClpISignatureFactory in '..\..\CryptoLib\src\Interfaces\Crypto\Operators\ClpISignatureFactory.pas',
   ClpISigner in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\ClpISigner.pas',
@@ -366,7 +364,7 @@ uses
   ClpSecP256R1Custom in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Custom.pas',
   ClpSecP384R1Custom in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP384R1Custom.pas',
   ClpSecP521R1Custom in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP521R1Custom.pas',
-  ClpSecT283Custom in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283Custom.pas',
+  ClpSecT283K1Custom in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Custom.pas',
   ClpSecureRandom in '..\..\CryptoLib\src\Crypto\Randoms\ClpSecureRandom.pas',
   ClpSetWeakRef in '..\..\CryptoLib\src\Misc\ClpSetWeakRef.pas',
   ClpWeakRef in '..\..\CryptoLib\src\Misc\ClpWeakRef.pas',
@@ -587,7 +585,9 @@ uses
   ClpECLookupTables in '..\..\CryptoLib\src\Math\EC\ClpECLookupTables.pas',
   ClpECCore in '..\..\CryptoLib\src\Math\EC\ClpECCore.pas',
   ClpEndoUtilities in '..\..\CryptoLib\src\Math\EC\Endo\ClpEndoUtilities.pas',
-  ClpWNafUtilities in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpWNafUtilities.pas';
+  ClpWNafUtilities in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpWNafUtilities.pas',
+  ClpCustomNamedCurves in '..\..\CryptoLib\src\Crypto\EC\ClpCustomNamedCurves.pas',
+  ClpECUtilities in '..\..\CryptoLib\src\Crypto\EC\ClpECUtilities.pas';
 
 begin
 

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

@@ -33,7 +33,6 @@ uses
   ClpCryptoLibTypes,
   ClpBigInteger,
   ClpECCurve,
-  ClpECCompUtilities,
   ClpSecP256K1Custom,
   ClpISecP256K1Custom,
   ClpSecP256R1Custom,
@@ -42,10 +41,11 @@ uses
   ClpISecP384R1Custom,
   ClpSecP521R1Custom,
   ClpISecP521R1Custom,
-  ClpSecT283Custom,
-  ClpISecT283Custom,
+  ClpSecT283K1Custom,
+  ClpISecT283K1Custom,
   ClpIECCore,
   ClpIAsn1Objects,
+  ClpWnafUtilities,
   ClpScalarSplitParameters,
   ClpIScalarSplitParameters,
   ClpGlvTypeBEndomorphism,

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

@@ -24,6 +24,7 @@ interface
 uses
   ClpBigInteger,
   ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type
@@ -44,13 +45,10 @@ type
   ISecP256K1Curve = Interface(IAbstractFpCurve)
     ['{BBE4D704-8562-4C17-9149-CA33CFE7611F}']
 
-    function GetQ: TBigInteger;
-    property Q: TBigInteger read GetQ;
-
   end;
 
 type
-  ISecP256K1LookupTable = Interface(IAbstractECLookupTable)
+  ISecP256K1LookupTable = Interface(IECLookupTable)
     ['{0E204483-F303-49FD-AF66-0F30CF855CA9}']
   end;
 

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

@@ -24,6 +24,7 @@ interface
 uses
   ClpBigInteger,
   ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type
@@ -44,13 +45,10 @@ type
   ISecP256R1Curve = Interface(IAbstractFpCurve)
     ['{D6B64687-91B2-4281-B099-3B3DCFB330DB}']
 
-    function GetQ: TBigInteger;
-    property Q: TBigInteger read GetQ;
-
   end;
 
 type
-  ISecP256R1LookupTable = Interface(IAbstractECLookupTable)
+  ISecP256R1LookupTable = Interface(IECLookupTable)
     ['{87BF97BA-18D2-4248-ABEB-8E429998E9D9}']
   end;
 

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

@@ -24,6 +24,7 @@ interface
 uses
   ClpBigInteger,
   ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type
@@ -44,13 +45,10 @@ type
   ISecP384R1Curve = Interface(IAbstractFpCurve)
     ['{50639F3D-E15C-4C3C-A7AA-7A8ACA243341}']
 
-    function GetQ: TBigInteger;
-    property Q: TBigInteger read GetQ;
-
   end;
 
 type
-  ISecP384R1LookupTable = Interface(IAbstractECLookupTable)
+  ISecP384R1LookupTable = Interface(IECLookupTable)
     ['{F1354F0B-577F-402C-A363-7761CF82DA43}']
   end;
 

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

@@ -24,6 +24,7 @@ interface
 uses
   ClpBigInteger,
   ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type
@@ -44,13 +45,10 @@ type
   ISecP521R1Curve = Interface(IAbstractFpCurve)
     ['{B2AACD7E-6EF2-45E2-8126-FB87D6DB65B1}']
 
-    function GetQ: TBigInteger;
-    property Q: TBigInteger read GetQ;
-
   end;
 
 type
-  ISecP521R1LookupTable = Interface(IAbstractECLookupTable)
+  ISecP521R1LookupTable = Interface(IECLookupTable)
     ['{3A647191-94A9-483D-9AC5-57FEFDBA3060}']
   end;
 

+ 10 - 8
CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecT283Custom.pas → CryptoLib/src/Interfaces/Math/EC/Custom/Sec/ClpISecT283K1Custom.pas

@@ -15,7 +15,7 @@
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 
-unit ClpISecT283Custom;
+unit ClpISecT283K1Custom;
 
 {$I ..\..\..\..\..\Include\CryptoLib.inc}
 
@@ -23,6 +23,7 @@ interface
 
 uses
   ClpIECCore,
+  ClpIECFieldElement,
   ClpCryptoLibTypes;
 
 type
@@ -36,11 +37,11 @@ type
     property Representation: Int32 read GetRepresentation;
 
     function GetK1: Int32;
-    property k1: Int32 read GetK1;
+    property K1: Int32 read GetK1;
     function GetK2: Int32;
-    property k2: Int32 read GetK2;
+    property K2: Int32 read GetK2;
     function GetK3: Int32;
-    property k3: Int32 read GetK3;
+    property K3: Int32 read GetK3;
 
     function GetX: TCryptoLibUInt64Array;
     property X: TCryptoLibUInt64Array read GetX;
@@ -60,21 +61,22 @@ type
     property M: Int32 read GetM;
 
     function GetK1: Int32;
-    property k1: Int32 read GetK1;
+      property K1: Int32 read GetK1;
 
     function GetK2: Int32;
-    property k2: Int32 read GetK2;
+    property K2: Int32 read GetK2;
 
     function GetK3: Int32;
-    property k3: Int32 read GetK3;
+    property K3: Int32 read GetK3;
 
     function GetIsTrinomial: Boolean;
+
     property IsTrinomial: Boolean read GetIsTrinomial;
 
   end;
 
 type
-  ISecT283K1LookupTable = Interface(IAbstractECLookupTable)
+  ISecT283K1LookupTable = Interface(IECLookupTable)
     ['{3AF41553-A108-46D6-9CCC-AB1814A0A247}']
   end;
 

+ 11 - 8
CryptoLib/src/Math/EC/ClpECPoint.pas

@@ -79,6 +79,9 @@ type
     function RawYCoord: IECFieldElement; inline;
     function RawZCoords: TCryptoLibGenericArray<IECFieldElement>; inline;
     procedure CheckNormalized; virtual;
+
+    function Detach: IECPoint; virtual; abstract;  // called from GetDetachedPoint on normalized point
+    function GetCompressionYTilde: Boolean; virtual; abstract;
   public
     constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement); overload;
     constructor Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
@@ -86,7 +89,9 @@ type
     destructor Destroy; override;
 
     function GetCurve: IECCurve; virtual;
+    property Curve: IECCurve read GetCurve;
     function GetIsInfinity: Boolean; virtual;
+    property IsInfinity: Boolean read GetIsInfinity;
     function GetXCoord: IECFieldElement; virtual;
     function GetYCoord: IECFieldElement; virtual;
     property XCoord: IECFieldElement read GetXCoord;
@@ -116,6 +121,8 @@ type
 
     function GetAffineXCoord: IECFieldElement; virtual;
     function GetAffineYCoord: IECFieldElement; virtual;
+    property AffineXCoord: IECFieldElement read GetAffineXCoord;
+    property AffineYCoord: IECFieldElement read GetAffineYCoord;
     function Add(const AB: IECPoint): IECPoint; virtual; abstract;
     function Subtract(const AB: IECPoint): IECPoint; virtual; abstract;
     function Negate: IECPoint; virtual; abstract;
@@ -125,19 +132,15 @@ type
     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;
+
+    function Equals(const AOther: IECPoint): Boolean;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+    function ToString: String; override;
   end;
 
   TECPointBase = class abstract(TECPoint, IECPointBase)

+ 703 - 837
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas

@@ -22,1177 +22,1043 @@ unit ClpSecP256K1Custom;
 interface
 
 uses
+  SysUtils,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpNat256,
+  ClpNat,
   ClpMod,
+  ClpPack,
   ClpEncoders,
-  ClpNat,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpArrayUtilities,
   ClpBitOperations,
-  ClpNat256,
   ClpECCurve,
-  ClpBigInteger,
-  ClpArrayUtilities,
-  ClpCryptoLibTypes,
   ClpECCurveConstants,
+  ClpECFieldElement,
+  ClpECPoint,
+  ClpECLookupTables,
+  ClpFiniteFields,
   ClpIECCore,
   ClpIECFieldElement,
-  ClpISecP256K1Custom;
+  ClpISecP256K1Custom,
+  ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidValueForSecP256K1FieldElement =
-    'Value Invalid for SecP256K1FieldElement "%s"';
-  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
+  SInvalidSecP256K1FieldElement = 'value invalid for SecP256K1FieldElement';
 
 type
-  // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
   TSecP256K1Field = class sealed(TObject)
-
   strict private
   const
     P7 = UInt32($FFFFFFFF);
     PExt15 = UInt32($FFFFFFFF);
     PInv33 = UInt32($3D1);
-
-    class var
-
-      FP, FPExt, FPExtInv: TCryptoLibUInt32Array;
-
-    class function GetP: TCryptoLibUInt32Array; static; inline;
-
-    class procedure Boot(); static;
-    class constructor SecP256K1Field();
-
+  class var
+    FP, FPExt, FPExtInv: TCryptoLibUInt32Array;
+  class procedure Boot; static;
+  class constructor Create;
   public
-    class procedure Add(const x, y, z: TCryptoLibUInt32Array); static; inline;
-    class procedure AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure AddOne(const x, z: TCryptoLibUInt32Array); static; inline;
-    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt32Array;
-      static; inline;
-    class procedure Half(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Multiply(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure MultiplyAddToExt(const x, y, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Negate(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce(const xx, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce32(x: UInt32; const z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Square(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure SquareN(const x: TCryptoLibUInt32Array; n: Int32;
-      const z: TCryptoLibUInt32Array); static; inline;
-    class procedure Subtract(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure SubtractExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Twice(const x, z: TCryptoLibUInt32Array); static; inline;
-
-    class property P: TCryptoLibUInt32Array read GetP;
+    class procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure AddExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure AddOne(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array; static;
+    class procedure Half(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Inv(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Int32; static;
+    class procedure Multiply(const AX, AY, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure MultiplyAddToExt(const AX, AY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure Negate(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce(const AXX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce32(AX: UInt32; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Square(const AX, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure Subtract(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure SubtractExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure Twice(const AX, AZ: TCryptoLibUInt32Array); static;
+
+    class property P: TCryptoLibUInt32Array read FP;
   end;
 
 type
-  TSecP256K1FieldElement = class(TAbstractFpFieldElement,
-    ISecP256K1FieldElement)
-
+  TSecP256K1FieldElement = class sealed(TAbstractFpFieldElement,
+    IAbstractFpFieldElement, IECFieldElement, ISecP256K1FieldElement)
   strict private
-
-    function Equals(const AOther: ISecP256K1FieldElement): Boolean;
-      reintroduce; overload;
-
-    class function GetQ: TBigInteger; static; inline;
-
+  class var
+    FQ: TBigInteger;
+  class procedure Boot; static;
+  class constructor Create;
   strict protected
-  var
-    Fx: TCryptoLibUInt32Array;
-
-    function GetFieldName: string; override;
-    function GetFieldSize: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
+    FX: TCryptoLibUInt32Array;
     function GetX: TCryptoLibUInt32Array; inline;
-    property x: TCryptoLibUInt32Array read GetX;
-
   public
+    class function GetQ: TBigInteger; static;
+    class property Q: TBigInteger read GetQ;
+    constructor Create(const AX: TBigInteger); overload;
     constructor Create(); overload;
-    constructor Create(const x: TBigInteger); overload;
-    constructor Create(const x: TCryptoLibUInt32Array); overload;
+    constructor Create(const AX: TCryptoLibUInt32Array); overload;
 
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+    function ToBigInteger: TBigInteger; 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
-    /// returns the right value - if <br />none exists it returns null.
-    /// </summary>
-    function Sqrt(): IECFieldElement; 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 Divide(const AB: IECFieldElement): IECFieldElement; override;
+    function Negate: IECFieldElement; override;
+    function Square: IECFieldElement; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: IECFieldElement; override;
 
-    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
+    function Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    property IsZero: Boolean read GetIsZero;
-    property IsOne: Boolean read GetIsOne;
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    class property Q: TBigInteger read GetQ;
+    property X: TCryptoLibUInt32Array read GetX;
   end;
 
 type
-  TSecP256K1Point = class sealed(TAbstractFpPoint, ISecP256K1Point)
-
+  TSecP256K1Point = class sealed(TAbstractFpPoint, IAbstractFpPoint, IECPoint,
+    ISecP256K1Point)
   strict protected
-    function Detach(): IECPoint; override;
-
+    function Detach: IECPoint; override;
   public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="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 that encodes with or without point compresion.
-    /// </summary>
-    /// <param name="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;
-
-    function Add(const b: IECPoint): IECPoint; override;
-    function Negate(): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function ThreeTimes(): IECPoint; override;
-
+    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 Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function ThreeTimes: IECPoint; override;
+    function Negate: IECPoint; override;
   end;
 
 type
-  TSecP256K1Curve = class sealed(TAbstractFpCurve, ISecP256K1Curve)
-
+  TSecP256K1Curve = class sealed(TAbstractFpCurve, IAbstractFpCurve, IECCurve,
+    ISecP256K1Curve)
+  strict private
+  const
+    SECP256K1_DEFAULT_COORDS = TECCurveConstants.COORD_JACOBIAN;
+    SECP256K1_FE_INTS = 8;
   strict private
-
   type
-    TSecP256K1LookupTable = class sealed(TAbstractECLookupTable,
+    TSecP256K1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable,
       ISecP256K1LookupTable)
-
     strict private
-    var
-      Fm_outer: ISecP256K1Curve;
-      Fm_table: TCryptoLibUInt32Array;
-      Fm_size: Int32;
-
-      function CreatePoint(const x, y: TCryptoLibUInt32Array): IECPoint;
-
-    strict protected
-
-      function GetSize: Int32; override;
-
+      FOuter: ISecP256K1Curve;
+      FTable: TCryptoLibUInt32Array;
+      FSize: Int32;
+      function CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
     public
-
-      constructor Create(const outer: ISecP256K1Curve;
-        const table: TCryptoLibUInt32Array; size: Int32);
-
-      function Lookup(index: Int32): IECPoint; override;
-      function LookupVar(index: Int32): IECPoint; override;
-
+      constructor Create(const AOuter: ISecP256K1Curve;
+        const ATable: TCryptoLibUInt32Array; ASize: Int32);
+      function GetSize: Int32; override;
+      function Lookup(AIndex: Int32): IECPoint; override;
+      function LookupVar(AIndex: Int32): IECPoint; override;
     end;
-
-  const
-    SECP256K1_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_JACOBIAN);
-    SECP256K1_FE_INTS = Int32(8);
-
+  class var
+    FQ: TBigInteger;
+    FSecP256K1AffineZs: TCryptoLibGenericArray<IECFieldElement>;
+  class procedure Boot; static;
+  class constructor Create;
   var
-    Fq: TBigInteger;
-
+    FInfinity: TSecP256K1Point;
   strict protected
-  var
-    Fm_infinity: ISecP256K1Point;
+    function GetQ: TBigInteger;
+  public
+    constructor Create;
+    destructor Destroy; override;
 
-    function GetQ: TBigInteger; virtual;
+    function CloneCurve: IECCurve; override;
     function GetFieldSize: Int32; override;
     function GetInfinity: IECPoint; 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();
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property Q: TBigInteger read GetQ;
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; override;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32): IECLookupTable; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; override;
+
+    class property Q: TBigInteger read FQ;
+    class property SecP256K1AffineZs: TCryptoLibGenericArray<IECFieldElement> read FSecP256K1AffineZs;
   end;
 
 implementation
 
 { TSecP256K1Field }
 
-class constructor TSecP256K1Field.SecP256K1Field;
+class procedure TSecP256K1Field.Boot;
 begin
-  TSecP256K1Field.Boot;
+  FP := TCryptoLibUInt32Array.Create($FFFFFC2F, $FFFFFFFE, $FFFFFFFF, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF);
+  FPExt := TCryptoLibUInt32Array.Create($000E90A1, $000007A2, $00000001, $00000000,
+    $00000000, $00000000, $00000000, $00000000, $FFFFF85E, $FFFFFFFD, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF);
+  FPExtInv := TCryptoLibUInt32Array.Create($FFF16F5F, $FFFFF85D, $FFFFFFFE, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $000007A1, $00000002);
 end;
 
-class function TSecP256K1Field.GetP: TCryptoLibUInt32Array;
+class constructor TSecP256K1Field.Create;
 begin
-  result := FP;
+  Boot;
 end;
 
-class procedure TSecP256K1Field.Add(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Add(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat256.Add(x, y, z);
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    TNat.Add33To(8, PInv33, z);
-  end;
+  LC := TNat256.Add(AX, AY, AZ);
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    TNat.Add33To(8, PInv33, AZ);
 end;
 
-class procedure TSecP256K1Field.AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.AddExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Add(16, xx, yy, zz);
-  if ((c <> 0) or ((zz[15] = PExt15) and (TNat.Gte(16, zz, FPExt)))) then
-  begin
-    if (TNat.AddTo(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
-    begin
-      TNat.IncAt(16, zz, System.Length(FPExtInv));
-    end;
-  end;
+  LC := TNat.Add(16, AXX, AYY, AZZ);
+  if (LC <> 0) or ((AZZ[15] = PExt15) and TNat.Gte(16, AZZ, FPExt)) then
+    if TNat.AddTo(System.Length(FPExtInv), FPExtInv, AZZ) <> 0 then
+      TNat.IncAt(16, AZZ, System.Length(FPExtInv));
 end;
 
-class procedure TSecP256K1Field.AddOne(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.AddOne(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Inc(8, x, z);
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    TNat.Add33To(8, PInv33, z);
-  end;
+  LC := TNat.Inc(8, AX, AZ);
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    TNat.Add33To(8, PInv33, AZ);
 end;
 
-class procedure TSecP256K1Field.Boot;
+class function TSecP256K1Field.FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array;
+var
+  LZ: TCryptoLibUInt32Array;
 begin
-  FP := TCryptoLibUInt32Array.Create($FFFFFC2F, $FFFFFFFE, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF);
-  FPExt := TCryptoLibUInt32Array.Create($000E90A1, $000007A2, $00000001,
-    $00000000, $00000000, $00000000, $00000000, $00000000, $FFFFF85E, $FFFFFFFD,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF);
-  FPExtInv := TCryptoLibUInt32Array.Create($FFF16F5F, $FFFFF85D, $FFFFFFFE,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $000007A1,
-    $00000002);
+  LZ := TNat.FromBigInteger(256, AX);
+  if (LZ[7] = P7) and TNat256.Gte(LZ, FP) then
+    TNat256.SubFrom(FP, LZ, 0);
+  Result := LZ;
 end;
 
-class function TSecP256K1Field.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
+class procedure TSecP256K1Field.Half(const AX, AZ: TCryptoLibUInt32Array);
 var
-  z: TCryptoLibUInt32Array;
+  LC: UInt32;
 begin
-  z := TNat.FromBigInteger(256, x);
-  if ((z[7] = P7) and (TNat256.Gte(z, FP))) then
+  if (AX[0] and 1) = 0 then
+    TNat.ShiftDownBit(8, AX, 0, AZ)
+  else
   begin
-    TNat256.SubFrom(FP, z, 0);
+    LC := TNat256.Add(AX, FP, AZ);
+    TNat.ShiftDownBit(8, AZ, LC);
   end;
-  result := z;
 end;
 
-class procedure TSecP256K1Field.Half(const x, z: TCryptoLibUInt32Array);
-var
-  c: UInt32;
+class procedure TSecP256K1Field.Inv(const AX, AZ: TCryptoLibUInt32Array);
 begin
-  if ((x[0] and 1) = 0) then
-  begin
-    TNat.ShiftDownBit(8, x, 0, z);
-  end
-  else
-  begin
-    c := TNat256.Add(x, FP, z);
-    TNat.ShiftDownBit(8, z, c);
-  end;
+  TMod.CheckedModOddInverse(FP, AX, AZ);
 end;
 
-class procedure TSecP256K1Field.Reduce(const xx, z: TCryptoLibUInt32Array);
+class function TSecP256K1Field.IsZero(const AX: TCryptoLibUInt32Array): Int32;
 var
-  cc: UInt64;
-  c: UInt32;
-begin
-  cc := TNat256.Mul33Add(PInv33, xx, 8, xx, 0, z, 0);
-  c := TNat256.Mul33DWordAdd(PInv33, cc, z, 0);
-{$IFDEF DEBUG}
-  System.Assert((c = 0) or (c = 1));
-{$ENDIF DEBUG}
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    TNat.Add33To(8, PInv33, z);
-  end;
+  LD: UInt32;
+  LI: Int32;
+begin
+  LD := 0;
+  for LI := 0 to 7 do
+    LD := LD or AX[LI];
+  LD := (LD shr 1) or (LD and 1);
+  Result := TBitOperations.Asr32(Int32(LD) - 1, 31);
 end;
 
-class procedure TSecP256K1Field.Multiply(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Multiply(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LTT: TCryptoLibUInt32Array;
 begin
-  tt := TNat256.CreateExt();
-  TNat256.Mul(x, y, tt);
-  Reduce(tt, z);
+  LTT := TNat256.CreateExt();
+  TNat256.Mul(AX, AY, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP256K1Field.MultiplyAddToExt(const x, y,
-  zz: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array);
+begin
+  TNat256.Mul(AX, AY, ATT);
+  Reduce(ATT, AZ);
+end;
+
+class procedure TSecP256K1Field.MultiplyAddToExt(const AX, AY, AZZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat256.MulAddTo(x, y, zz);
-  if ((c <> 0) or ((zz[15] = PExt15) and (TNat.Gte(16, zz, FPExt)))) then
-  begin
-    if (TNat.AddTo(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
-    begin
-      TNat.IncAt(16, zz, System.Length(FPExtInv));
-    end;
-  end;
+  LC := TNat256.MulAddTo(AX, AY, AZZ);
+  if (LC <> 0) or ((AZZ[15] = PExt15) and TNat.Gte(16, AZZ, FPExt)) then
+    if TNat.AddTo(System.Length(FPExtInv), FPExtInv, AZZ) <> 0 then
+      TNat.IncAt(16, AZZ, System.Length(FPExtInv));
 end;
 
-class procedure TSecP256K1Field.Negate(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Negate(const AX, AZ: TCryptoLibUInt32Array);
 begin
-  if (TNat256.IsZero(x)) then
-  begin
-    TNat256.Zero(z);
-  end
+  if IsZero(AX) <> 0 then
+    TNat256.Sub(FP, FP, AZ)
   else
-  begin
-    TNat256.Sub(FP, x, z);
-  end;
+    TNat256.Sub(FP, AX, AZ);
 end;
 
-class procedure TSecP256K1Field.Reduce32(x: UInt32;
-  const z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
+var
+  LBB: TCryptoLibByteArray;
 begin
-  if (((x <> 0) and (TNat256.Mul33WordAdd(PInv33, x, z, 0) <> 0)) or
-    ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    TNat.Add33To(8, PInv33, z);
-  end;
+  System.SetLength(LBB, 8 * 4);
+  repeat
+    AR.NextBytes(LBB);
+    TPack.LE_To_UInt32(LBB, 0, AZ, 0, 8);
+  until TNat.LessThan(8, AZ, FP) <> 0;
 end;
 
-class procedure TSecP256K1Field.Square(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
+begin
+  repeat
+    Random(AR, AZ);
+  until IsZero(AZ) <> 0;
+end;
+
+class procedure TSecP256K1Field.Reduce(const AXX, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LCc: UInt64;
+  LC: UInt32;
 begin
-  tt := TNat256.CreateExt();
-  TNat256.Square(x, tt);
-  Reduce(tt, z);
+  LCc := TNat256.Mul33Add(PInv33, AXX, 8, AXX, 0, AZ, 0);
+  LC := TNat256.Mul33DWordAdd(PInv33, LCc, AZ, 0);
+  {$IFDEF DEBUG}
+  System.Assert((LC = 0) or (LC = 1));
+  {$ENDIF DEBUG}
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    TNat.Add33To(8, PInv33, AZ);
 end;
 
-class procedure TSecP256K1Field.SquareN(const x: TCryptoLibUInt32Array;
-  n: Int32; const z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Reduce32(AX: UInt32; const AZ: TCryptoLibUInt32Array);
+begin
+  if ((AX <> 0) and (TNat256.Mul33WordAdd(PInv33, AX, AZ, 0) <> 0)) or
+    ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    TNat.Add33To(8, PInv33, AZ);
+end;
+
+class procedure TSecP256K1Field.Square(const AX, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LTT: TCryptoLibUInt32Array;
+begin
+  LTT := TNat256.CreateExt();
+  TNat256.Square(AX, LTT);
+  Reduce(LTT, AZ);
+end;
+
+class procedure TSecP256K1Field.Square(const AX, AZ, ATT: TCryptoLibUInt32Array);
 begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  tt := TNat256.CreateExt();
-  TNat256.Square(x, tt);
-  Reduce(tt, z);
+  TNat256.Square(AX, ATT);
+  Reduce(ATT, AZ);
+end;
 
-  System.Dec(n);
-  while (n > 0) do
+class procedure TSecP256K1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ: TCryptoLibUInt32Array);
+var
+  LTT: TCryptoLibUInt32Array;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AN > 0);
+  {$ENDIF DEBUG}
+  LTT := TNat256.CreateExt();
+  TNat256.Square(AX, LTT);
+  Reduce(LTT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    TNat256.Square(z, tt);
-    Reduce(tt, z);
-    System.Dec(n);
+    TNat256.Square(AZ, LTT);
+    Reduce(LTT, AZ);
+    Dec(AN);
   end;
 end;
 
-class procedure TSecP256K1Field.Subtract(const x, y, z: TCryptoLibUInt32Array);
-var
-  c: Int32;
+class procedure TSecP256K1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ, ATT: TCryptoLibUInt32Array);
 begin
-  c := TNat256.Sub(x, y, z);
-  if (c <> 0) then
+  {$IFDEF DEBUG}
+  System.Assert(AN > 0);
+  {$ENDIF DEBUG}
+  TNat256.Square(AX, ATT);
+  Reduce(ATT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    TNat.Sub33From(8, PInv33, z);
+    TNat256.Square(AZ, ATT);
+    Reduce(ATT, AZ);
+    Dec(AN);
   end;
 end;
 
-class procedure TSecP256K1Field.SubtractExt(const xx, yy,
-  zz: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.Subtract(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  c: Int32;
+  LC: Int32;
 begin
-  c := TNat.Sub(16, xx, yy, zz);
-  if (c <> 0) then
-  begin
-    if (TNat.SubFrom(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
-    begin
-      TNat.DecAt(16, zz, System.Length(FPExtInv));
-    end;
-  end;
+  LC := TNat256.Sub(AX, AY, AZ);
+  if LC <> 0 then
+    TNat.Sub33From(8, PInv33, AZ);
 end;
 
-class procedure TSecP256K1Field.Twice(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256K1Field.SubtractExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: Int32;
 begin
-  c := TNat.ShiftUpBit(8, x, 0, z);
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    TNat.Add33To(8, PInv33, z);
-  end;
+  LC := TNat.Sub(16, AXX, AYY, AZZ);
+  if LC <> 0 then
+    if TNat.SubFrom(System.Length(FPExtInv), FPExtInv, AZZ) <> 0 then
+      TNat.DecAt(16, AZZ, System.Length(FPExtInv));
+end;
+
+class procedure TSecP256K1Field.Twice(const AX, AZ: TCryptoLibUInt32Array);
+var
+  LC: UInt32;
+begin
+  LC := TNat.ShiftUpBit(8, AX, 0, AZ);
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    TNat.Add33To(8, PInv33, AZ);
 end;
 
 { TSecP256K1FieldElement }
 
-class function TSecP256K1FieldElement.GetQ: TBigInteger;
+class procedure TSecP256K1FieldElement.Boot;
 begin
-  result := TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'));
+  FQ := TBigInteger.Create(1, THex.Decode('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'));
 end;
 
-function TSecP256K1FieldElement.GetX: TCryptoLibUInt32Array;
+class constructor TSecP256K1FieldElement.Create;
 begin
-  result := Fx;
+  Boot;
 end;
 
-constructor TSecP256K1FieldElement.Create;
+constructor TSecP256K1FieldElement.Create(const AX: TBigInteger);
 begin
-  Inherited Create();
-  Fx := TNat256.Create();
+  Inherited Create;
+  if (not AX.IsInitialized) or (AX.SignValue < 0) or (AX.CompareTo(FQ) >= 0) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidSecP256K1FieldElement);
+  FX := TSecP256K1Field.FromBigInteger(AX);
 end;
 
-constructor TSecP256K1FieldElement.Create(const x: TBigInteger);
+constructor TSecP256K1FieldElement.Create();
 begin
-  if ((not(x.IsInitialized)) or (x.SignValue < 0) or (x.CompareTo(Q) >= 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt
-      (@SInvalidValueForSecP256K1FieldElement, ['x']);
-  end;
-  Inherited Create();
-  Fx := TSecP256K1Field.FromBigInteger(x);
+  Inherited Create;
+  FX := TNat256.Create();
 end;
 
-constructor TSecP256K1FieldElement.Create(const x: TCryptoLibUInt32Array);
+constructor TSecP256K1FieldElement.Create(const AX: TCryptoLibUInt32Array);
 begin
-  Inherited Create();
-  Fx := x;
+  Inherited Create;
+  FX := AX;
 end;
 
-function TSecP256K1FieldElement.GetFieldName: string;
+function TSecP256K1FieldElement.GetX: TCryptoLibUInt32Array;
 begin
-  result := 'SecP256K1Field';
+  Result := FX;
 end;
 
-function TSecP256K1FieldElement.GetFieldSize: Int32;
+function TSecP256K1FieldElement.GetFieldName: String;
 begin
-  result := Q.BitLength;
+  Result := 'SecP256K1Field';
 end;
 
-function TSecP256K1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+function TSecP256K1FieldElement.GetFieldSize: Int32;
 begin
-  result := Q.GetHashCode() xor TArrayUtilities.GetArrayHashCode(Fx, 0, 8);
+  Result := FQ.BitLength;
 end;
 
 function TSecP256K1FieldElement.GetIsOne: Boolean;
 begin
-  result := TNat256.IsOne(Fx);
+  Result := TNat256.IsOne(FX);
 end;
 
 function TSecP256K1FieldElement.GetIsZero: Boolean;
 begin
-  result := TNat256.IsZero(Fx);
+  Result := TNat256.IsZero(FX);
 end;
 
-function TSecP256K1FieldElement.Invert: IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
+function TSecP256K1FieldElement.ToBigInteger: TBigInteger;
 begin
-  z := TNat256.Create();
-  TMod.CheckedModOddInverse(TSecP256K1Field.P, Fx, z);
-  result := TSecP256K1FieldElement.Create(z);
+  Result := TNat256.ToBigInteger(FX);
 end;
 
-function TSecP256K1FieldElement.Multiply(const b: IECFieldElement)
-  : IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
+function TSecP256K1FieldElement.TestBitZero: Boolean;
 begin
-  z := TNat256.Create();
-  TSecP256K1Field.Multiply(Fx, (b as ISecP256K1FieldElement).x, z);
-  result := TSecP256K1FieldElement.Create(z);
+  Result := TNat256.GetBit(FX, 0) = 1;
 end;
 
-function TSecP256K1FieldElement.Negate: IECFieldElement;
+function TSecP256K1FieldElement.Add(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256K1Field.Negate(Fx, z);
-  result := TSecP256K1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256K1Field.Add(FX, (AB as ISecP256K1FieldElement).X, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.Sqrt: IECFieldElement;
+function TSecP256K1FieldElement.AddOne: IECFieldElement;
 var
-  x1, x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1,
-    t2: TCryptoLibUInt32Array;
-begin
-  { *
-    * Raise this element to the exponent 2^254 - 2^30 - 2^7 - 2^6 - 2^5 - 2^4 - 2^2
-    *
-    * Breaking up the exponent's binary representation into "repunits", we get:
-    * ( 223 1s ) ( 1 0s ) ( 22 1s ) ( 4 0s ) ( 2 1s ) ( 2 0s)
-    *
-    * Therefore we need an addition chain containing 2, 22, 223 (the lengths of the repunits)
-    * We use: 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
-    * }
-
-  x1 := Fx;
-  if ((TNat256.IsZero(x1)) or (TNat256.IsOne(x1))) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  x2 := TNat256.Create();
-  TSecP256K1Field.Square(x1, x2);
-  TSecP256K1Field.Multiply(x2, x1, x2);
-  x3 := TNat256.Create();
-  TSecP256K1Field.Square(x2, x3);
-  TSecP256K1Field.Multiply(x3, x1, x3);
-  x6 := TNat256.Create();
-  TSecP256K1Field.SquareN(x3, 3, x6);
-  TSecP256K1Field.Multiply(x6, x3, x6);
-  x9 := x6;
-  TSecP256K1Field.SquareN(x6, 3, x9);
-  TSecP256K1Field.Multiply(x9, x3, x9);
-  x11 := x9;
-  TSecP256K1Field.SquareN(x9, 2, x11);
-  TSecP256K1Field.Multiply(x11, x2, x11);
-  x22 := TNat256.Create();
-  TSecP256K1Field.SquareN(x11, 11, x22);
-  TSecP256K1Field.Multiply(x22, x11, x22);
-  x44 := x11;
-  TSecP256K1Field.SquareN(x22, 22, x44);
-  TSecP256K1Field.Multiply(x44, x22, x44);
-  x88 := TNat256.Create();
-  TSecP256K1Field.SquareN(x44, 44, x88);
-  TSecP256K1Field.Multiply(x88, x44, x88);
-  x176 := TNat256.Create();
-  TSecP256K1Field.SquareN(x88, 88, x176);
-  TSecP256K1Field.Multiply(x176, x88, x176);
-  x220 := x88;
-  TSecP256K1Field.SquareN(x176, 44, x220);
-  TSecP256K1Field.Multiply(x220, x44, x220);
-  x223 := x44;
-  TSecP256K1Field.SquareN(x220, 3, x223);
-  TSecP256K1Field.Multiply(x223, x3, x223);
-
-  t1 := x223;
-  TSecP256K1Field.SquareN(t1, 23, t1);
-  TSecP256K1Field.Multiply(t1, x22, t1);
-  TSecP256K1Field.SquareN(t1, 6, t1);
-  TSecP256K1Field.Multiply(t1, x2, t1);
-  TSecP256K1Field.SquareN(t1, 2, t1);
-
-  t2 := x2;
-  TSecP256K1Field.Square(t1, t2);
-
-  if TNat256.Eq(x1, t2) then
-  begin
-    result := TSecP256K1FieldElement.Create(t1);
-  end
-  else
-  begin
-    result := Nil;
-  end;
+  LZ: TCryptoLibUInt32Array;
+begin
+  LZ := TNat256.Create();
+  TSecP256K1Field.AddOne(FX, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.Square: IECFieldElement;
+function TSecP256K1FieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256K1Field.Square(Fx, z);
-  result := TSecP256K1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256K1Field.Subtract(FX, (AB as ISecP256K1FieldElement).X, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.Subtract(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP256K1FieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256K1Field.Subtract(Fx, (b as ISecP256K1FieldElement).x, z);
-  result := TSecP256K1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256K1Field.Multiply(FX, (AB as ISecP256K1FieldElement).X, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.TestBitZero: Boolean;
+function TSecP256K1FieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
+var
+  LZ: TCryptoLibUInt32Array;
 begin
-  result := TNat256.GetBit(Fx, 0) = 1;
+  LZ := TNat256.Create();
+  TSecP256K1Field.Inv((AB as ISecP256K1FieldElement).X, LZ);
+  TSecP256K1Field.Multiply(LZ, FX, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.ToBigInteger: TBigInteger;
+function TSecP256K1FieldElement.Negate: IECFieldElement;
+var
+  LZ: TCryptoLibUInt32Array;
 begin
-  result := TNat256.ToBigInteger(Fx);
+  LZ := TNat256.Create();
+  TSecP256K1Field.Negate(FX, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.Add(const b: IECFieldElement): IECFieldElement;
+function TSecP256K1FieldElement.Square: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256K1Field.Add(Fx, (b as ISecP256K1FieldElement).x, z);
-  result := TSecP256K1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256K1Field.Square(FX, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.AddOne: IECFieldElement;
+function TSecP256K1FieldElement.Invert: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256K1Field.AddOne(Fx, z);
-  result := TSecP256K1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256K1Field.Inv(FX, LZ);
+  Result := TSecP256K1FieldElement.Create(LZ);
 end;
 
-function TSecP256K1FieldElement.Divide(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP256K1FieldElement.Sqrt: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TMod.CheckedModOddInverse(TSecP256K1Field.P, (b as ISecP256K1FieldElement).x, z);
-  TSecP256K1Field.Multiply(z, Fx, z);
-  result := TSecP256K1FieldElement.Create(z);
+  LX1, LTT0, LX2, LX3, LX6, LX9, LX11, LX22, LX44, LX88, LX176, LX220, LX223: TCryptoLibUInt32Array;
+  LT1, LT2: TCryptoLibUInt32Array;
+begin
+  LX1 := FX;
+  if TNat256.IsZero(LX1) or TNat256.IsOne(LX1) then
+    Exit(Self as IECFieldElement);
+
+  LTT0 := TNat256.CreateExt();
+
+  LX2 := TNat256.Create();
+  TSecP256K1Field.Square(LX1, LX2, LTT0);
+  TSecP256K1Field.Multiply(LX2, LX1, LX2, LTT0);
+  LX3 := TNat256.Create();
+  TSecP256K1Field.Square(LX2, LX3, LTT0);
+  TSecP256K1Field.Multiply(LX3, LX1, LX3, LTT0);
+  LX6 := TNat256.Create();
+  TSecP256K1Field.SquareN(LX3, 3, LX6, LTT0);
+  TSecP256K1Field.Multiply(LX6, LX3, LX6, LTT0);
+  LX9 := LX6;
+  TSecP256K1Field.SquareN(LX6, 3, LX9, LTT0);
+  TSecP256K1Field.Multiply(LX9, LX3, LX9, LTT0);
+  LX11 := LX9;
+  TSecP256K1Field.SquareN(LX9, 2, LX11, LTT0);
+  TSecP256K1Field.Multiply(LX11, LX2, LX11, LTT0);
+  LX22 := TNat256.Create();
+  TSecP256K1Field.SquareN(LX11, 11, LX22, LTT0);
+  TSecP256K1Field.Multiply(LX22, LX11, LX22, LTT0);
+  LX44 := LX11;
+  TSecP256K1Field.SquareN(LX22, 22, LX44, LTT0);
+  TSecP256K1Field.Multiply(LX44, LX22, LX44, LTT0);
+  LX88 := TNat256.Create();
+  TSecP256K1Field.SquareN(LX44, 44, LX88, LTT0);
+  TSecP256K1Field.Multiply(LX88, LX44, LX88, LTT0);
+  LX176 := TNat256.Create();
+  TSecP256K1Field.SquareN(LX88, 88, LX176, LTT0);
+  TSecP256K1Field.Multiply(LX176, LX88, LX176, LTT0);
+  LX220 := LX88;
+  TSecP256K1Field.SquareN(LX176, 44, LX220, LTT0);
+  TSecP256K1Field.Multiply(LX220, LX44, LX220, LTT0);
+  LX223 := LX44;
+  TSecP256K1Field.SquareN(LX220, 3, LX223, LTT0);
+  TSecP256K1Field.Multiply(LX223, LX3, LX223, LTT0);
+
+  LT1 := LX223;
+  TSecP256K1Field.SquareN(LT1, 23, LT1, LTT0);
+  TSecP256K1Field.Multiply(LT1, LX22, LT1, LTT0);
+  TSecP256K1Field.SquareN(LT1, 6, LT1, LTT0);
+  TSecP256K1Field.Multiply(LT1, LX2, LT1, LTT0);
+  TSecP256K1Field.SquareN(LT1, 2, LT1, LTT0);
+
+  LT2 := LX2;
+  TSecP256K1Field.Square(LT1, LT2, LTT0);
+
+  if TNat256.Eq(LX1, LT2) then
+    Result := TSecP256K1FieldElement.Create(LT1)
+  else
+    Result := nil;
 end;
 
-function TSecP256K1FieldElement.Equals(const AOther: ISecP256K1FieldElement): Boolean;
+function TSecP256K1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
 begin
-  if (Self as ISecP256K1FieldElement) = AOther then
+  if (Self as IECFieldElement) = AOther then
     Exit(True);
   if AOther = nil then
     Exit(False);
-  Result := TNat256.Eq(Fx, AOther.x);
+  Result := TNat256.Eq(FX, (AOther as ISecP256K1FieldElement).X);
 end;
 
-function TSecP256K1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
-var
-  LSec: ISecP256K1FieldElement;
+function TSecP256K1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
 begin
-  if AOther = nil then
-    Exit(False);
-  if Supports(AOther, ISecP256K1FieldElement, LSec) then
-    Result := Equals(LSec)
-  else
-    Result := ToBigInteger.Equals(AOther.ToBigInteger);
+  Result := FQ.GetHashCode() xor TArrayUtilities.GetArrayHashCode(FX, 0, 8);
 end;
 
 { TSecP256K1Point }
 
-constructor TSecP256K1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
+constructor TSecP256K1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
 begin
-  Create(curve, x, y, false);
+  Inherited Create(ACurve, AX, AY);
 end;
 
-constructor TSecP256K1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
+constructor TSecP256K1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
 begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SOneOfECFieldElementIsNil);
-  end;
+  Inherited Create(ACurve, AX, AY, AZs);
 end;
 
-constructor TSecP256K1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
+function TSecP256K1Point.Detach: IECPoint;
 begin
-  Inherited Create(curve, x, y, zs, withCompression);
+  Result := TSecP256K1Point.Create(nil, AffineXCoord, AffineYCoord);
 end;
 
-function TSecP256K1Point.Add(const b: IECPoint): IECPoint;
+function TSecP256K1Point.Add(const AB: IECPoint): IECPoint;
 var
-  Lcurve: IECCurve;
-  x1, Y1, x2, Y2, Z1, Z2, x3, Y3, Z3: ISecP256K1FieldElement;
-  c: UInt32;
-  tt1, t2, t3, t4, U2, S2, U1, S1, H, R, HSquared, G, V: TCryptoLibUInt32Array;
-  Z1IsOne, Z2IsOne: Boolean;
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-begin
-  if (IsInfinity) then
+  LCurve: IECCurve;
+  LX1, LY1, LX2, LY2, LZ1, LZ2: ISecP256K1FieldElement;
+  LTT0, LTT1: TCryptoLibUInt32Array;
+  LT2, LT3, LT4: TCryptoLibUInt32Array;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  LU2, LS2, LU1, LS1: TCryptoLibUInt32Array;
+  LH, LR, LHSquared, LG, LV: TCryptoLibUInt32Array;
+  LC: UInt32;
+  LX3, LY3, LZ3: ISecP256K1FieldElement;
+  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 := Curve;
+  LX1 := RawXCoord as ISecP256K1FieldElement;
+  LY1 := RawYCoord as ISecP256K1FieldElement;
+  LX2 := AB.RawXCoord as ISecP256K1FieldElement;
+  LY2 := AB.RawYCoord as ISecP256K1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP256K1FieldElement;
+  LZ2 := AB.GetZCoord(0) as ISecP256K1FieldElement;
+
+  LTT0 := TNat256.CreateExt();
+  LTT1 := TNat256.CreateExt();
+  LT2 := TNat256.Create();
+  LT3 := TNat256.Create();
+  LT4 := TNat256.Create();
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
   begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
+    LU2 := LX2.X;
+    LS2 := LY2.X;
+  end
+  else
   begin
-    result := Self as IECPoint;
-    Exit;
+    LS2 := LT3;
+    TSecP256K1Field.Square(LZ1.X, LS2, LTT0);
+    LU2 := LT2;
+    TSecP256K1Field.Multiply(LS2, LX2.X, LU2, LTT0);
+    TSecP256K1Field.Multiply(LS2, LZ1.X, LS2, LTT0);
+    TSecP256K1Field.Multiply(LS2, LY2.X, LS2, LTT0);
   end;
-  if ((Self as IECPoint) = b) then
+
+  LZ2IsOne := LZ2.IsOne;
+  if LZ2IsOne then
+  begin
+    LU1 := LX1.X;
+    LS1 := LY1.X;
+  end
+  else
   begin
-    result := Twice();
-    Exit;
+    LS1 := LT4;
+    TSecP256K1Field.Square(LZ2.X, LS1, LTT0);
+    LU1 := LTT1;
+    TSecP256K1Field.Multiply(LS1, LX1.X, LU1, LTT0);
+    TSecP256K1Field.Multiply(LS1, LZ2.X, LS1, LTT0);
+    TSecP256K1Field.Multiply(LS1, LY1.X, LS1, LTT0);
   end;
 
-  Lcurve := curve;
+  LH := TNat256.Create();
+  TSecP256K1Field.Subtract(LU1, LU2, LH);
 
-  x1 := RawXCoord as ISecP256K1FieldElement;
-  Y1 := RawYCoord as ISecP256K1FieldElement;
-  x2 := b.RawXCoord as ISecP256K1FieldElement;
-  Y2 := b.RawYCoord as ISecP256K1FieldElement;
+  LR := LT2;
+  TSecP256K1Field.Subtract(LS1, LS2, LR);
 
-  Z1 := RawZCoords[0] as ISecP256K1FieldElement;
-  Z2 := b.RawZCoords[0] as ISecP256K1FieldElement;
+  if TNat256.IsZero(LH) then
+  begin
+    if TNat256.IsZero(LR) then
+      Exit(Twice());
+    Exit(LCurve.Infinity);
+  end;
 
-  tt1 := TNat256.CreateExt();
-  t2 := TNat256.Create();
-  t3 := TNat256.Create();
-  t4 := TNat256.Create();
+  LHSquared := LT3;
+  TSecP256K1Field.Square(LH, LHSquared, LTT0);
 
-  Z1IsOne := Z1.IsOne;
+  LG := TNat256.Create();
+  TSecP256K1Field.Multiply(LHSquared, LH, LG, LTT0);
 
-  if (Z1IsOne) then
-  begin
-    U2 := x2.x;
-    S2 := Y2.x;
-  end
-  else
-  begin
-    S2 := t3;
-    TSecP256K1Field.Square(Z1.x, S2);
+  LV := LT3;
+  TSecP256K1Field.Multiply(LHSquared, LU1, LV, LTT0);
 
-    U2 := t2;
-    TSecP256K1Field.Multiply(S2, x2.x, U2);
+  TSecP256K1Field.Negate(LG, LG);
+  TNat256.Mul(LS1, LG, LTT1);
 
-    TSecP256K1Field.Multiply(S2, Z1.x, S2);
-    TSecP256K1Field.Multiply(S2, Y2.x, S2);
-  end;
+  LC := TNat256.AddBothTo(LV, LV, LG);
+  TSecP256K1Field.Reduce32(LC, LG);
 
-  Z2IsOne := Z2.IsOne;
-  if (Z2IsOne) then
-  begin
-    U1 := x1.x;
-    S1 := Y1.x;
-  end
-  else
-  begin
-    S1 := t4;
-    TSecP256K1Field.Square(Z2.x, S1);
+  LX3 := TSecP256K1FieldElement.Create(LT4);
+  TSecP256K1Field.Square(LR, LX3.X, LTT0);
+  TSecP256K1Field.Subtract(LX3.X, LG, LX3.X);
 
-    U1 := tt1;
-    TSecP256K1Field.Multiply(S1, x1.x, U1);
+  LY3 := TSecP256K1FieldElement.Create(LG);
+  TSecP256K1Field.Subtract(LV, LX3.X, LY3.X);
+  TSecP256K1Field.MultiplyAddToExt(LY3.X, LR, LTT1);
+  TSecP256K1Field.Reduce(LTT1, LY3.X);
 
-    TSecP256K1Field.Multiply(S1, Z2.x, S1);
-    TSecP256K1Field.Multiply(S1, Y1.x, S1);
-  end;
+  LZ3 := TSecP256K1FieldElement.Create(LH);
+  if not LZ1IsOne then
+    TSecP256K1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
+  if not LZ2IsOne then
+    TSecP256K1Field.Multiply(LZ3.X, LZ2.X, LZ3.X, LTT0);
 
-  H := TNat256.Create();
-  TSecP256K1Field.Subtract(U1, U2, H);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP256K1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
 
-  R := t2;
-  TSecP256K1Field.Subtract(S1, S2, R);
+function TSecP256K1Point.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LY1, LX1, LZ1: ISecP256K1FieldElement;
+  LTT0: TCryptoLibUInt32Array;
+  LY1Squared, LT, LM, LS: TCryptoLibUInt32Array;
+  LT1: TCryptoLibUInt32Array;
+  LC: UInt32;
+  LX3, LY3, LZ3: ISecP256K1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(Self as IECPoint);
 
-  // Check if b = Self or b = -Self
-  if (TNat256.IsZero(H)) then
-  begin
-    if (TNat256.IsZero(R)) then
-    begin
-      // Self = b, i.e. Self must be doubled
-      result := Twice();
-      Exit;
-    end;
+  LCurve := Curve;
+  LY1 := RawYCoord as ISecP256K1FieldElement;
+  if LY1.IsZero then
+    Exit(LCurve.Infinity);
 
-    // Self = -b, i.e. the result is the point at infinity
-    result := Lcurve.Infinity;
-    Exit;
-  end;
+  LX1 := RawXCoord as ISecP256K1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP256K1FieldElement;
 
-  HSquared := t3;
-  TSecP256K1Field.Square(H, HSquared);
+  LTT0 := TNat256.CreateExt();
 
-  G := TNat256.Create();
-  TSecP256K1Field.Multiply(HSquared, H, G);
+  LY1Squared := TNat256.Create();
+  TSecP256K1Field.Square(LY1.X, LY1Squared, LTT0);
 
-  V := t3;
-  TSecP256K1Field.Multiply(HSquared, U1, V);
+  LT := TNat256.Create();
+  TSecP256K1Field.Square(LY1Squared, LT, LTT0);
 
-  TSecP256K1Field.Negate(G, G);
-  TNat256.Mul(S1, G, tt1);
+  LM := TNat256.Create();
+  TSecP256K1Field.Square(LX1.X, LM, LTT0);
+  LC := TNat256.AddBothTo(LM, LM, LM);
+  TSecP256K1Field.Reduce32(LC, LM);
 
-  c := TNat256.AddBothTo(V, V, G);
-  TSecP256K1Field.Reduce32(c, G);
+  LS := LY1Squared;
+  TSecP256K1Field.Multiply(LY1Squared, LX1.X, LS, LTT0);
+  LC := TNat.ShiftUpBits(8, LS, 2, 0, LS);
+  TSecP256K1Field.Reduce32(LC, LS);
 
-  x3 := TSecP256K1FieldElement.Create(t4);
-  TSecP256K1Field.Square(R, x3.x);
-  TSecP256K1Field.Subtract(x3.x, G, x3.x);
+  LT1 := TNat256.Create();
+  LC := TNat.ShiftUpBits(8, LT, 3, 0, LT1);
+  TSecP256K1Field.Reduce32(LC, LT1);
 
-  Y3 := TSecP256K1FieldElement.Create(G);
-  TSecP256K1Field.Subtract(V, x3.x, Y3.x);
-  TSecP256K1Field.MultiplyAddToExt(Y3.x, R, tt1);
-  TSecP256K1Field.Reduce(tt1, Y3.x);
+  LX3 := TSecP256K1FieldElement.Create(LT);
+  TSecP256K1Field.Square(LM, LX3.X, LTT0);
+  TSecP256K1Field.Subtract(LX3.X, LS, LX3.X);
+  TSecP256K1Field.Subtract(LX3.X, LS, LX3.X);
 
-  Z3 := TSecP256K1FieldElement.Create(H);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
-  end;
-  if (not(Z2IsOne)) then
-  begin
-    TSecP256K1Field.Multiply(Z3.x, Z2.x, Z3.x);
-  end;
+  LY3 := TSecP256K1FieldElement.Create(LS);
+  TSecP256K1Field.Subtract(LS, LX3.X, LY3.X);
+  TSecP256K1Field.Multiply(LY3.X, LM, LY3.X, LTT0);
+  TSecP256K1Field.Subtract(LY3.X, LT1, LY3.X);
 
-  zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
+  LZ3 := TSecP256K1FieldElement.Create(LM);
+  TSecP256K1Field.Twice(LY1.X, LZ3.X);
+  if not LZ1.IsOne then
+    TSecP256K1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
 
-  result := TSecP256K1Point.Create(Lcurve, x3, Y3, zs, IsCompressed)
-    as IECPoint;
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP256K1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
 end;
 
-function TSecP256K1Point.Detach: IECPoint;
+function TSecP256K1Point.TwicePlus(const AB: IECPoint): IECPoint;
+begin
+  if (Self as IECPoint) = AB then
+    Exit(ThreeTimes());
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Twice());
+  if RawYCoord.IsZero then
+    Exit(AB);
+  Result := Twice().Add(AB);
+end;
+
+function TSecP256K1Point.ThreeTimes: IECPoint;
 begin
-  result := TSecP256K1Point.Create(Nil, AffineXCoord, AffineYCoord) as IECPoint;
+  if IsInfinity or RawYCoord.IsZero then
+    Exit(Self as IECPoint);
+  Result := Twice().Add(Self as IECPoint);
 end;
 
 function TSecP256K1Point.Negate: IECPoint;
 begin
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  if IsInfinity then
+    Exit(Self as IECPoint);
+  Result := TSecP256K1Point.Create(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords);
+end;
 
-  result := TSecP256K1Point.Create(curve, RawXCoord, RawYCoord.Negate(),
-    RawZCoords, IsCompressed) as IECPoint;
+{ TSecP256K1Curve.TSecP256K1LookupTable }
+
+constructor TSecP256K1Curve.TSecP256K1LookupTable.Create(const AOuter: ISecP256K1Curve;
+  const ATable: TCryptoLibUInt32Array; ASize: Int32);
+begin
+  Inherited Create;
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
 end;
 
-function TSecP256K1Point.ThreeTimes: IECPoint;
+function TSecP256K1Curve.TSecP256K1LookupTable.GetSize: Int32;
 begin
-  if ((IsInfinity) or (RawYCoord.IsZero)) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  Result := FSize;
+end;
 
-  // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
-  result := Twice().Add(Self as IECPoint);
+function TSecP256K1Curve.TSecP256K1LookupTable.CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
+begin
+  Result := FOuter.CreateRawPoint(TSecP256K1FieldElement.Create(AX) as IECFieldElement,
+    TSecP256K1FieldElement.Create(AY) as IECFieldElement, TSecP256K1Curve.SecP256K1AffineZs);
 end;
 
-function TSecP256K1Point.Twice: IECPoint;
+function TSecP256K1Curve.TSecP256K1LookupTable.Lookup(AIndex: Int32): IECPoint;
 var
-  Lcurve: IECCurve;
-  Y1, x1, Z1, x3, Y3, Z3: ISecP256K1FieldElement;
-  c: UInt32;
-  Y1Squared, T, M, S, t1: TCryptoLibUInt32Array;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LI, LJ: Int32;
+  LMask: UInt32;
 begin
+  LX := TNat256.Create();
+  LY := TNat256.Create();
+  LPos := 0;
 
-  if (IsInfinity) then
+  for LI := 0 to System.Pred(FSize) do
   begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  Lcurve := curve;
-
-  Y1 := RawYCoord as ISecP256K1FieldElement;
-  if (Y1.IsZero) then
-  begin
-    result := Lcurve.Infinity;
-    Exit;
-  end;
-
-  x1 := RawXCoord as ISecP256K1FieldElement;
-  Z1 := RawZCoords[0] as ISecP256K1FieldElement;
+    LMask := UInt32(TBitOperations.Asr32(((LI xor AIndex) - 1), 31));
 
-  Y1Squared := TNat256.Create();
-  TSecP256K1Field.Square(Y1.x, Y1Squared);
-
-  T := TNat256.Create();
-  TSecP256K1Field.Square(Y1Squared, T);
-
-  M := TNat256.Create();
-  TSecP256K1Field.Square(x1.x, M);
-  c := TNat256.AddBothTo(M, M, M);
-  TSecP256K1Field.Reduce32(c, M);
-
-  S := Y1Squared;
-  TSecP256K1Field.Multiply(Y1Squared, x1.x, S);
-  c := TNat.ShiftUpBits(8, S, 2, 0);
-  TSecP256K1Field.Reduce32(c, S);
-
-  t1 := TNat256.Create();
-  c := TNat.ShiftUpBits(8, T, 3, 0, t1);
-  TSecP256K1Field.Reduce32(c, t1);
-
-  x3 := TSecP256K1FieldElement.Create(T);
-  TSecP256K1Field.Square(M, x3.x);
-  TSecP256K1Field.Subtract(x3.x, S, x3.x);
-  TSecP256K1Field.Subtract(x3.x, S, x3.x);
-
-  Y3 := TSecP256K1FieldElement.Create(S);
-  TSecP256K1Field.Subtract(S, x3.x, Y3.x);
-  TSecP256K1Field.Multiply(Y3.x, M, Y3.x);
-  TSecP256K1Field.Subtract(Y3.x, t1, Y3.x);
+    for LJ := 0 to System.Pred(SECP256K1_FE_INTS) do
+    begin
+      LX[LJ] := LX[LJ] xor (FTable[LPos + LJ] and LMask);
+      LY[LJ] := LY[LJ] xor (FTable[LPos + SECP256K1_FE_INTS + LJ] and LMask);
+    end;
 
-  Z3 := TSecP256K1FieldElement.Create(M);
-  TSecP256K1Field.Twice(Y1.x, Z3.x);
-  if (not(Z1.IsOne)) then
-  begin
-    TSecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+    LPos := LPos + (SECP256K1_FE_INTS * 2);
   end;
 
-  result := TSecP256K1Point.Create(Lcurve, x3, Y3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed)
-    as IECPoint;
+  Result := CreatePoint(LX, LY);
 end;
 
-function TSecP256K1Point.TwicePlus(const b: IECPoint): IECPoint;
+function TSecP256K1Curve.TSecP256K1LookupTable.LookupVar(AIndex: Int32): IECPoint;
 var
-  Y1: IECFieldElement;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LJ: 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;
+  LX := TNat256.Create();
+  LY := TNat256.Create();
+  LPos := AIndex * SECP256K1_FE_INTS * 2;
 
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
+  for LJ := 0 to System.Pred(SECP256K1_FE_INTS) do
   begin
-    result := b;
-    Exit;
+    LX[LJ] := FTable[LPos + LJ];
+    LY[LJ] := FTable[LPos + SECP256K1_FE_INTS + LJ];
   end;
 
-  result := Twice().Add(b);
+  Result := CreatePoint(LX, LY);
 end;
 
 { TSecP256K1Curve }
 
-constructor TSecP256K1Curve.Create;
+class procedure TSecP256K1Curve.Boot;
 begin
-  Fq := TSecP256K1FieldElement.Q;
-  Inherited Create(Fq);
-  Fm_infinity := TSecP256K1Point.Create(Self as IECCurve, Nil, Nil);
-  Fm_a := FromBigInteger(TBigInteger.Zero);
-  Fm_b := FromBigInteger(TBigInteger.ValueOf(7));
-  Fm_order := TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'));
-  Fm_cofactor := TBigInteger.One;
-  Fm_coord := SECP256K1_DEFAULT_COORDS;
+  FQ := TSecP256K1FieldElement.Q;
+  FSecP256K1AffineZs := TCryptoLibGenericArray<IECFieldElement>.Create(
+    TSecP256K1FieldElement.Create(TBigInteger.One) as IECFieldElement);
 end;
 
-function TSecP256K1Curve.CloneCurve: IECCurve;
+class constructor TSecP256K1Curve.Create;
 begin
-  result := TSecP256K1Curve.Create();
+  Boot;
 end;
 
-function TSecP256K1Curve.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  table: TCryptoLibUInt32Array;
-  pos, i: Int32;
-  P: IECPoint;
+constructor TSecP256K1Curve.Create;
 begin
-  System.SetLength(table, len * SECP256K1_FE_INTS * 2);
-
-  pos := 0;
-  for i := 0 to System.Pred(len) do
-  begin
-    P := points[off + i];
-    TNat256.Copy((P.RawXCoord as ISecP256K1FieldElement).x, 0, table, pos);
-    pos := pos + SECP256K1_FE_INTS;
-    TNat256.Copy((P.RawYCoord as ISecP256K1FieldElement).x, 0, table, pos);
-    pos := pos + SECP256K1_FE_INTS;
-  end;
-
-  result := TSecP256K1LookupTable.Create(Self as ISecP256K1Curve, table, len);
+  Inherited Create(TSecP256K1Curve.Q, True);
+  FInfinity := TSecP256K1Point.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(TBigInteger.Zero);
+  FB := FromBigInteger(TBigInteger.Seven);
+  FOrder := TBigInteger.Create(1, THex.Decode('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'));
+  FCofactor := TBigInteger.One;
+  FCoord := SECP256K1_DEFAULT_COORDS;
 end;
 
-function TSecP256K1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
+destructor TSecP256K1Curve.Destroy;
 begin
-  result := TSecP256K1Point.Create(Self as IECCurve, x, y, withCompression);
+  FInfinity := nil;
+  inherited Destroy;
 end;
 
-function TSecP256K1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
+function TSecP256K1Curve.GetQ: TBigInteger;
 begin
-  result := TSecP256K1Point.Create(Self as IECCurve, x, y, zs, withCompression);
+  Result := TSecP256K1Curve.Q;
 end;
 
-function TSecP256K1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
+function TSecP256K1Curve.CloneCurve: IECCurve;
 begin
-  result := TSecP256K1FieldElement.Create(x);
+  Result := TSecP256K1Curve.Create;
 end;
 
 function TSecP256K1Curve.GetFieldSize: Int32;
 begin
-  result := Fq.BitLength;
+  Result := TSecP256K1Curve.Q.BitLength;
 end;
 
 function TSecP256K1Curve.GetInfinity: IECPoint;
 begin
-  result := Fm_infinity;
+  Result := FInfinity;
 end;
 
-function TSecP256K1Curve.GetQ: TBigInteger;
+function TSecP256K1Curve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
 begin
-  result := Fq;
+  Result := TSecP256K1FieldElement.Create(AX);
 end;
 
-function TSecP256K1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
+function TSecP256K1Curve.CreateRawPoint(const AX, AY: IECFieldElement): IECPoint;
 begin
-  case coord of
-    TECCurveConstants.COORD_JACOBIAN:
-      result := true
-  else
-    result := false;
-  end;
+  Result := TSecP256K1Point.Create(Self as IECCurve, AX, AY);
 end;
 
-{ TSecP256K1Curve.TSecP256K1LookupTable }
-
-constructor TSecP256K1Curve.TSecP256K1LookupTable.Create
-  (const outer: ISecP256K1Curve; const table: TCryptoLibUInt32Array;
-  size: Int32);
+function TSecP256K1Curve.CreateRawPoint(const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
 begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := size;
+  Result := TSecP256K1Point.Create(Self as IECCurve, AX, AY, AZs);
 end;
 
-function TSecP256K1Curve.TSecP256K1LookupTable.CreatePoint(const x,
-  y: TCryptoLibUInt32Array): IECPoint;
+function TSecP256K1Curve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
 var
-  XFieldElement, YFieldElement: ISecP256K1FieldElement;
-  SECP256K1_AFFINE_ZS: TCryptoLibGenericArray<IECFieldElement>;
+  LTable: TCryptoLibUInt32Array;
+  LPos, LI: Int32;
+  LP: IECPoint;
 begin
-  SECP256K1_AFFINE_ZS := TCryptoLibGenericArray<IECFieldElement>.Create
-    (TSecP256K1FieldElement.Create(TBigInteger.One) as ISecP256K1FieldElement);
-
-  XFieldElement := TSecP256K1FieldElement.Create(x);
-  YFieldElement := TSecP256K1FieldElement.Create(y);
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement,
-    SECP256K1_AFFINE_ZS, false);
+  System.SetLength(LTable, ALen * SECP256K1_FE_INTS * 2);
+  LPos := 0;
+  for LI := 0 to System.Pred(ALen) do
+  begin
+    LP := APoints[AOff + LI];
+    TNat256.Copy((LP.RawXCoord as ISecP256K1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP256K1_FE_INTS;
+    TNat256.Copy((LP.RawYCoord as ISecP256K1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP256K1_FE_INTS;
+  end;
+  Result := TSecP256K1LookupTable.Create(Self as ISecP256K1Curve, LTable, ALen);
 end;
 
-function TSecP256K1Curve.TSecP256K1LookupTable.GetSize: Int32;
+function TSecP256K1Curve.RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LX: TCryptoLibUInt32Array;
 begin
-  result := Fm_size;
+  LX := TNat256.Create();
+  TSecP256K1Field.Random(ARandom, LX);
+  Result := TSecP256K1FieldElement.Create(LX);
 end;
 
-function TSecP256K1Curve.TSecP256K1LookupTable.Lookup(index: Int32): IECPoint;
+function TSecP256K1Curve.RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
 var
-  x, y: TCryptoLibUInt32Array;
-  pos, i, J: Int32;
-  MASK: UInt32;
+  LX: TCryptoLibUInt32Array;
 begin
-  x := TNat256.Create();
-  y := TNat256.Create();
-  pos := 0;
-
-  for i := 0 to System.Pred(Fm_size) do
-  begin
-    MASK := UInt32(TBitOperations.Asr32((i xor index) - 1, 31));
-
-    for J := 0 to System.Pred(SECP256K1_FE_INTS) do
-    begin
-      x[J] := x[J] xor (Fm_table[pos + J] and MASK);
-      y[J] := y[J] xor (Fm_table[pos + SECP256K1_FE_INTS + J] and MASK);
-    end;
-
-    pos := pos + (SECP256K1_FE_INTS * 2);
-  end;
-
-  result := CreatePoint(x, y);
+  LX := TNat256.Create();
+  TSecP256K1Field.RandomMult(ARandom, LX);
+  Result := TSecP256K1FieldElement.Create(LX);
 end;
 
-function TSecP256K1Curve.TSecP256K1LookupTable.LookupVar(index: Int32)
-  : IECPoint;
-var
-  x, y: TCryptoLibUInt32Array;
-  pos, J: Int32;
+function TSecP256K1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
 begin
-  x := TNat256.Create();
-  y := TNat256.Create();
-  pos := index * SECP256K1_FE_INTS * 2;
-
-  for J := 0 to System.Pred(SECP256K1_FE_INTS) do
-  begin
-    x[J] := Fm_table[pos + J];
-    y[J] := Fm_table[pos + SECP256K1_FE_INTS + J];
+  case ACoord of
+    TECCurveConstants.COORD_JACOBIAN:
+      Result := True;
+  else
+    Result := False;
   end;
+end;
 
-  result := CreatePoint(x, y);
+class function TSecP256K1FieldElement.GetQ: TBigInteger;
+begin
+  Result := FQ;
 end;
 
 end.

+ 834 - 960
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas

@@ -22,1320 +22,1194 @@ unit ClpSecP256R1Custom;
 interface
 
 uses
+  SysUtils,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpNat256,
+  ClpNat,
   ClpMod,
+  ClpPack,
   ClpEncoders,
-  ClpNat,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpArrayUtilities,
   ClpBitOperations,
-  ClpNat256,
   ClpECCurve,
-  ClpBigInteger,
-  ClpArrayUtilities,
-  ClpCryptoLibTypes,
   ClpECCurveConstants,
+  ClpECFieldElement,
+  ClpECPoint,
+  ClpECLookupTables,
+  ClpFiniteFields,
   ClpIECCore,
   ClpIECFieldElement,
-  ClpISecP256R1Custom;
+  ClpISecP256R1Custom,
+  ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidValueForSecP256R1FieldElement =
-    'Value Invalid for SecP256R1FieldElement "%s"';
-  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
+  SInvalidSecP256R1FieldElement = 'value invalid for SecP256R1FieldElement';
 
 type
-  // 2^256 - 2^224 + 2^192 + 2^96 - 1
   TSecP256R1Field = class sealed(TObject)
-
   strict private
   const
     P7 = UInt32($FFFFFFFF);
     PExt15 = UInt32($FFFFFFFE);
-
-    class var
-
-      FP, FPExt: TCryptoLibUInt32Array;
-
-    class function GetP: TCryptoLibUInt32Array; static; inline;
-
-    class procedure AddPInvTo(const z: TCryptoLibUInt32Array); static;
-    class procedure SubPInvFrom(const z: TCryptoLibUInt32Array); static;
-
-    class procedure Boot(); static;
-    class constructor SecP256R1Field();
-
+  class var
+    FP, FPExt: TCryptoLibUInt32Array;
+  class procedure Boot; static;
+  class procedure AddPInvTo(const AZ: TCryptoLibUInt32Array); static;
+  class procedure SubPInvFrom(const AZ: TCryptoLibUInt32Array); static;
+  class constructor Create;
   public
-    class procedure Add(const x, y, z: TCryptoLibUInt32Array); static; inline;
-    class procedure AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure AddOne(const x, z: TCryptoLibUInt32Array); static; inline;
-    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt32Array;
-      static; inline;
-    class procedure Half(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Multiply(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure MultiplyAddToExt(const x, y, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Negate(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce(const xx, z: TCryptoLibUInt32Array); static;
-    class procedure Reduce32(x: UInt32; const z: TCryptoLibUInt32Array); static;
-    class procedure Square(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure SquareN(const x: TCryptoLibUInt32Array; n: Int32;
-      const z: TCryptoLibUInt32Array); static; inline;
-    class procedure Subtract(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure SubtractExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Twice(const x, z: TCryptoLibUInt32Array); static; inline;
-
-    class property P: TCryptoLibUInt32Array read GetP;
+    class procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure AddExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure AddOne(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array; static;
+    class procedure Half(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Inv(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Int32; static;
+    class procedure Multiply(const AX, AY, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure MultiplyAddToExt(const AX, AY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure Negate(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce(const AXX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce32(AX: UInt32; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Square(const AX, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure Subtract(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure SubtractExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure Twice(const AX, AZ: TCryptoLibUInt32Array); static;
+
+    class property P: TCryptoLibUInt32Array read FP;
   end;
 
 type
-  TSecP256R1FieldElement = class(TAbstractFpFieldElement,
-    ISecP256R1FieldElement)
-
+  TSecP256R1FieldElement = class sealed(TAbstractFpFieldElement,
+    IAbstractFpFieldElement, IECFieldElement, ISecP256R1FieldElement)
   strict private
-
-    function Equals(const AOther: ISecP256R1FieldElement): Boolean;
-      reintroduce; overload;
-
-    class function GetQ: TBigInteger; static; inline;
-
+  class var
+    FQ: TBigInteger;
+  class procedure Boot; static;
+  class constructor Create;
   strict protected
-  var
-    Fx: TCryptoLibUInt32Array;
-
-    function GetFieldName: string; override;
-    function GetFieldSize: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
+    FX: TCryptoLibUInt32Array;
     function GetX: TCryptoLibUInt32Array; inline;
-    property x: TCryptoLibUInt32Array read GetX;
-
   public
+    class function GetQ: TBigInteger; static;
+    class property Q: TBigInteger read GetQ;
+    constructor Create(const AX: TBigInteger); overload;
     constructor Create(); overload;
-    constructor Create(const x: TBigInteger); overload;
-    constructor Create(const x: TCryptoLibUInt32Array); overload;
+    constructor Create(const AX: TCryptoLibUInt32Array); overload;
 
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+    function ToBigInteger: TBigInteger; 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 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 Divide(const AB: IECFieldElement): IECFieldElement; override;
+    function Negate: IECFieldElement; override;
+    function Square: IECFieldElement; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: 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 Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
-    function Invert(): IECFieldElement; override;
-
-    /// <summary>
-    /// return a sqrt root - the routine verifies that the calculation
-    /// returns the right value - if <br />none exists it returns null.
-    /// </summary>
-    function Sqrt(): IECFieldElement; override;
-
-    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    property IsZero: Boolean read GetIsZero;
-    property IsOne: Boolean read GetIsOne;
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    class property Q: TBigInteger read GetQ;
+    property X: TCryptoLibUInt32Array read GetX;
   end;
 
 type
-  TSecP256R1Point = class sealed(TAbstractFpPoint, ISecP256R1Point)
-
+  TSecP256R1Point = class sealed(TAbstractFpPoint, IAbstractFpPoint, IECPoint,
+    ISecP256R1Point)
   strict protected
-    function Detach(): IECPoint; override;
-
+    function Detach: IECPoint; override;
   public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="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 that encodes with or without point compresion.
-    /// </summary>
-    /// <param name="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;
-
-    function Add(const b: IECPoint): IECPoint; override;
-    function Negate(): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function ThreeTimes(): IECPoint; override;
-
+    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 Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function ThreeTimes: IECPoint; override;
+    function Negate: IECPoint; override;
   end;
 
 type
-  TSecP256R1Curve = class sealed(TAbstractFpCurve, ISecP256R1Curve)
-
+  TSecP256R1Curve = class sealed(TAbstractFpCurve, IAbstractFpCurve, IECCurve,
+    ISecP256R1Curve)
+  strict private
+  const
+    SECP256R1_DEFAULT_COORDS = TECCurveConstants.COORD_JACOBIAN;
+    SECP256R1_FE_INTS = 8;
   strict private
-
   type
-    TSecP256R1LookupTable = class sealed(TAbstractECLookupTable,
+    TSecP256R1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable,
       ISecP256R1LookupTable)
-
     strict private
-    var
-      Fm_outer: ISecP256R1Curve;
-      Fm_table: TCryptoLibUInt32Array;
-      Fm_size: Int32;
-
-      function CreatePoint(const x, y: TCryptoLibUInt32Array): IECPoint;
-
-    strict protected
-
-      function GetSize: Int32; override;
-
+      FOuter: ISecP256R1Curve;
+      FTable: TCryptoLibUInt32Array;
+      FSize: Int32;
+      function CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
     public
-
-      constructor Create(const outer: ISecP256R1Curve;
-        const table: TCryptoLibUInt32Array; size: Int32);
-
-      function Lookup(index: Int32): IECPoint; override;
-      function LookupVar(index: Int32): IECPoint; override;
-
+      constructor Create(const AOuter: ISecP256R1Curve;
+        const ATable: TCryptoLibUInt32Array; ASize: Int32);
+      function GetSize: Int32; override;
+      function Lookup(AIndex: Int32): IECPoint; override;
+      function LookupVar(AIndex: Int32): IECPoint; override;
     end;
-
-  const
-    SECP256R1_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_JACOBIAN);
-    SECP256R1_FE_INTS = Int32(8);
-
+  class var
+    FQ: TBigInteger;
+    FSecP256R1AffineZs: TCryptoLibGenericArray<IECFieldElement>;
+  class procedure Boot; static;
+  class constructor Create;
   var
-    Fq: TBigInteger;
-
+    FInfinity: TSecP256R1Point;
   strict protected
-  var
-    Fm_infinity: ISecP256R1Point;
+    function GetQ: TBigInteger;
+  public
+    constructor Create;
+    destructor Destroy; override;
 
-    function GetQ: TBigInteger; virtual;
+    function CloneCurve: IECCurve; override;
     function GetFieldSize: Int32; override;
     function GetInfinity: IECPoint; 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();
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property Q: TBigInteger read GetQ;
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; override;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32): IECLookupTable; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; override;
+
+    class property Q: TBigInteger read FQ;
+    class property SecP256R1AffineZs: TCryptoLibGenericArray<IECFieldElement> read FSecP256R1AffineZs;
   end;
 
 implementation
 
 { TSecP256R1Field }
 
-class constructor TSecP256R1Field.SecP256R1Field;
+class procedure TSecP256R1Field.Boot;
 begin
-  TSecP256R1Field.Boot;
+  FP := TCryptoLibUInt32Array.Create($FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $00000000,
+    $00000000, $00000000, $00000001, $FFFFFFFF);
+  FPExt := TCryptoLibUInt32Array.Create($00000001, $00000000, $00000000, $FFFFFFFE,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFE, $00000001, $FFFFFFFE, $00000001, $FFFFFFFE,
+    $00000001, $00000001, $FFFFFFFE, $00000002, $FFFFFFFE);
 end;
 
-class function TSecP256R1Field.GetP: TCryptoLibUInt32Array;
+class constructor TSecP256R1Field.Create;
 begin
-  result := FP;
+  Boot;
 end;
 
-class procedure TSecP256R1Field.Add(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.AddPInvTo(const AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: Int64;
 begin
-  c := TNat256.Add(x, y, z);
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
+  LC := Int64(AZ[0]) + 1;
+  AZ[0] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
   begin
-    AddPInvTo(z);
+    LC := LC + Int64(AZ[1]);
+    AZ[1] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
+    LC := LC + Int64(AZ[2]);
+    AZ[2] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
   end;
+  LC := LC + (Int64(AZ[3]) - 1);
+  AZ[3] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
+  begin
+    LC := LC + Int64(AZ[4]);
+    AZ[4] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
+    LC := LC + Int64(AZ[5]);
+    AZ[5] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
+  end;
+  LC := LC + (Int64(AZ[6]) - 1);
+  AZ[6] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[7]) + 1);
+  AZ[7] := UInt32(LC);
 end;
 
-class procedure TSecP256R1Field.AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.SubPInvFrom(const AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: Int64;
 begin
-  c := TNat.Add(16, xx, yy, zz);
-  if ((c <> 0) or ((zz[15] >= PExt15) and (TNat.Gte(16, zz, FPExt)))) then
+  LC := Int64(AZ[0]) - 1;
+  AZ[0] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
+  begin
+    LC := LC + Int64(AZ[1]);
+    AZ[1] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
+    LC := LC + Int64(AZ[2]);
+    AZ[2] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
+  end;
+  LC := LC + (Int64(AZ[3]) + 1);
+  AZ[3] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
   begin
-    TNat.SubFrom(16, FPExt, zz);
+    LC := LC + Int64(AZ[4]);
+    AZ[4] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
+    LC := LC + Int64(AZ[5]);
+    AZ[5] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
   end;
+  LC := LC + (Int64(AZ[6]) + 1);
+  AZ[6] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[7]) - 1);
+  AZ[7] := UInt32(LC);
 end;
 
-class procedure TSecP256R1Field.AddOne(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Add(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Inc(8, x, z);
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    AddPInvTo(z);
-  end;
+  LC := TNat256.Add(AX, AY, AZ);
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-class procedure TSecP256R1Field.AddPInvTo(const z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.AddExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array);
 var
-  c: Int64;
+  LC: UInt32;
 begin
-  c := Int64(z[0]) + 1;
-  z[0] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
-  begin
-    c := c + Int64(z[1]);
-    z[1] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-    c := c + Int64(z[2]);
-    z[2] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-  end;
-  c := c + (Int64(z[3]) - 1);
-  z[3] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
-  begin
-    c := c + Int64(z[4]);
-    z[4] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-    c := c + Int64(z[5]);
-    z[5] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-  end;
-  c := c + (Int64(z[6]) - 1);
-  z[6] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  c := c + (Int64(z[7]) + 1);
-  z[7] := UInt32(c);
-  // c := TBitUtilities.Asr64(c, 32);
+  LC := TNat.Add(16, AXX, AYY, AZZ);
+  if (LC <> 0) or ((AZZ[15] >= PExt15) and TNat.Gte(16, AZZ, FPExt)) then
+    TNat.SubFrom(16, FPExt, AZZ);
 end;
 
-class procedure TSecP256R1Field.Boot;
+class procedure TSecP256R1Field.AddOne(const AX, AZ: TCryptoLibUInt32Array);
+var
+  LC: UInt32;
 begin
-  FP := TCryptoLibUInt32Array.Create($FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $00000000,
-    $00000000, $00000000, $00000001, $FFFFFFFF);
-  FPExt := TCryptoLibUInt32Array.Create($00000001, $00000000, $00000000,
-    $FFFFFFFE, $FFFFFFFF, $FFFFFFFF, $FFFFFFFE, $00000001, $FFFFFFFE, $00000001,
-    $FFFFFFFE, $00000001, $00000001, $FFFFFFFE, $00000002, $FFFFFFFE);
+  LC := TNat.Inc(8, AX, AZ);
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-class function TSecP256R1Field.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
+class function TSecP256R1Field.FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.FromBigInteger(256, x);
-  if ((z[7] = P7) and (TNat256.Gte(z, FP))) then
-  begin
-    TNat256.SubFrom(FP, z, 0);
-  end;
-  result := z;
+  LZ := TNat.FromBigInteger(256, AX);
+  if (LZ[7] = P7) and TNat256.Gte(LZ, FP) then
+    TNat256.SubFrom(FP, LZ, 0);
+  Result := LZ;
 end;
 
-class procedure TSecP256R1Field.Half(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Half(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  if ((x[0] and 1) = 0) then
-  begin
-    TNat.ShiftDownBit(8, x, 0, z);
-  end
+  if (AX[0] and 1) = 0 then
+    TNat.ShiftDownBit(8, AX, 0, AZ)
   else
   begin
-    c := TNat256.Add(x, FP, z);
-    TNat.ShiftDownBit(8, z, c);
+    LC := TNat256.Add(AX, FP, AZ);
+    TNat.ShiftDownBit(8, AZ, LC);
   end;
 end;
 
-class procedure TSecP256R1Field.Reduce(const xx, z: TCryptoLibUInt32Array);
-const
-  n = Int64(6);
+class procedure TSecP256R1Field.Inv(const AX, AZ: TCryptoLibUInt32Array);
+begin
+  TMod.CheckedModOddInverse(FP, AX, AZ);
+end;
+
+class function TSecP256R1Field.IsZero(const AX: TCryptoLibUInt32Array): Int32;
 var
-  cc, xx08, xx09, xx10, xx11, xx12, xx13, xx14, xx15, t0, t1, t2, t3, t4, t5,
-    t6, t7: Int64;
-begin
-
-  xx08 := xx[8];
-  xx09 := xx[9];
-  xx10 := xx[10];
-  xx11 := xx[11];
-  xx12 := xx[12];
-  xx13 := xx[13];
-  xx14 := xx[14];
-  xx15 := xx[15];
-
-  xx08 := xx08 - n;
-
-  t0 := xx08 + xx09;
-  t1 := xx09 + xx10;
-  t2 := xx10 + xx11 - xx15;
-  t3 := xx11 + xx12;
-  t4 := xx12 + xx13;
-  t5 := xx13 + xx14;
-  t6 := xx14 + xx15;
-  t7 := t5 - t0;
-
-  cc := 0;
-
-  cc := cc + (Int64(xx[0]) - t3 - t7);
-  z[0] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[1]) + t1 - t4 - t6);
-  z[1] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[2]) + t2 - t5);
-  z[2] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[3]) + (t3 shl 1) + t7 - t6);
-  z[3] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[4]) + (t4 shl 1) + xx14 - t1);
-  z[4] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[5]) + (t5 shl 1) - t2);
-  z[5] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[6]) + (t6 shl 1) + t7);
-  z[6] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[7]) + (xx15 shl 1) + xx08 - t2 - t4);
-  z[7] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + n;
-
-{$IFDEF DEBUG}
-  System.Assert((cc >= 0));
-{$ENDIF DEBUG}
-  Reduce32(UInt32(cc), z);
-end;
-
-class procedure TSecP256R1Field.Multiply(const x, y, z: TCryptoLibUInt32Array);
+  LD: UInt32;
+  LI: Int32;
+begin
+  LD := 0;
+  for LI := 0 to 7 do
+    LD := LD or AX[LI];
+  LD := (LD shr 1) or (LD and 1);
+  Result := TBitOperations.Asr32(Int32(LD) - 1, 31);
+end;
+
+class procedure TSecP256R1Field.Multiply(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LTT: TCryptoLibUInt32Array;
 begin
-  tt := TNat256.CreateExt();
-  TNat256.Mul(x, y, tt);
-  Reduce(tt, z);
+  LTT := TNat256.CreateExt();
+  TNat256.Mul(AX, AY, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP256R1Field.MultiplyAddToExt(const x, y,
-  zz: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array);
+begin
+  TNat256.Mul(AX, AY, ATT);
+  Reduce(ATT, AZ);
+end;
+
+class procedure TSecP256R1Field.MultiplyAddToExt(const AX, AY, AZZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat256.MulAddTo(x, y, zz);
-  if ((c <> 0) or ((zz[15] >= PExt15) and (TNat.Gte(16, zz, FPExt)))) then
-  begin
-    TNat.SubFrom(16, FPExt, zz);
-  end;
+  LC := TNat256.MulAddTo(AX, AY, AZZ);
+  if (LC <> 0) or ((AZZ[15] >= PExt15) and TNat.Gte(16, AZZ, FPExt)) then
+    TNat.SubFrom(16, FPExt, AZZ);
 end;
 
-class procedure TSecP256R1Field.Negate(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Negate(const AX, AZ: TCryptoLibUInt32Array);
 begin
-  if (TNat256.IsZero(x)) then
-  begin
-    TNat256.Zero(z);
-  end
+  if IsZero(AX) <> 0 then
+    TNat256.Sub(FP, FP, AZ)
   else
-  begin
-    TNat256.Sub(FP, x, z);
-  end;
+    TNat256.Sub(FP, AX, AZ);
 end;
 
-class procedure TSecP256R1Field.Reduce32(x: UInt32;
-  const z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
 var
-  cc, xx08: Int64;
+  LBB: TCryptoLibByteArray;
 begin
-  cc := 0;
+  System.SetLength(LBB, 8 * 4);
+  repeat
+    AR.NextBytes(LBB);
+    TPack.LE_To_UInt32(LBB, 0, AZ, 0, 8);
+  until TNat.LessThan(8, AZ, FP) <> 0;
+end;
 
-  if (x <> 0) then
+class procedure TSecP256R1Field.RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
+begin
+  repeat
+    Random(AR, AZ);
+  until IsZero(AZ) <> 0;
+end;
+
+class procedure TSecP256R1Field.Reduce(const AXX, AZ: TCryptoLibUInt32Array);
+var
+  LXX08, LXX09, LXX10, LXX11, LXX12, LXX13, LXX14, LXX15: Int64;
+  LT0, LT1, LT2, LT3, LT4, LT5, LT6, LT7: Int64;
+  LCc: Int64;
+  LN: Int64;
+begin
+  LN := 6;
+  LXX08 := Int64(UInt32(AXX[8])) - LN;
+  LXX09 := Int64(UInt32(AXX[9]));
+  LXX10 := Int64(UInt32(AXX[10]));
+  LXX11 := Int64(UInt32(AXX[11]));
+  LXX12 := Int64(UInt32(AXX[12]));
+  LXX13 := Int64(UInt32(AXX[13]));
+  LXX14 := Int64(UInt32(AXX[14]));
+  LXX15 := Int64(UInt32(AXX[15]));
+
+  LT0 := LXX08 + LXX09;
+  LT1 := LXX09 + LXX10;
+  LT2 := LXX10 + LXX11 - LXX15;
+  LT3 := LXX11 + LXX12;
+  LT4 := LXX12 + LXX13;
+  LT5 := LXX13 + LXX14;
+  LT6 := LXX14 + LXX15;
+  LT7 := LT5 - LT0;
+
+  LCc := 0;
+  LCc := LCc + (Int64(AXX[0]) - LT3 - LT7);
+  AZ[0] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[1]) + LT1 - LT4 - LT6);
+  AZ[1] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[2]) + LT2 - LT5);
+  AZ[2] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[3]) + (LT3 shl 1) + LT7 - LT6);
+  AZ[3] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[4]) + (LT4 shl 1) + LXX14 - LT1);
+  AZ[4] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[5]) + (LT5 shl 1) - LT2);
+  AZ[5] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[6]) + (LT6 shl 1) + LT7);
+  AZ[6] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[7]) + (LXX15 shl 1) + LXX08 - LT2 - LT4);
+  AZ[7] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + LN;
+
+  {$IFDEF DEBUG}
+  Assert(LCc >= 0);
+  {$ENDIF DEBUG}
+
+  Reduce32(UInt32(LCc), AZ);
+end;
+
+class procedure TSecP256R1Field.Reduce32(AX: UInt32; const AZ: TCryptoLibUInt32Array);
+var
+  LCc: Int64;
+  LXX08: Int64;
+begin
+  LCc := 0;
+
+  if AX <> 0 then
   begin
-    xx08 := x;
+    LXX08 := Int64(AX);
 
-    cc := cc + (Int64(z[0]) + xx08);
-    z[0] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-    if (cc <> 0) then
+    LCc := LCc + (Int64(AZ[0]) + LXX08);
+    AZ[0] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+    if LCc <> 0 then
     begin
-      cc := cc + Int64(z[1]);
-      z[1] := UInt32(cc);
-      cc := TBitOperations.Asr64(cc, 32);
-      cc := cc + Int64(z[2]);
-      z[2] := UInt32(cc);
-      cc := TBitOperations.Asr64(cc, 32);
+      LCc := LCc + Int64(AZ[1]);
+      AZ[1] := UInt32(LCc);
+      LCc := TBitOperations.Asr64(LCc, 32);
+      LCc := LCc + Int64(AZ[2]);
+      AZ[2] := UInt32(LCc);
+      LCc := TBitOperations.Asr64(LCc, 32);
     end;
-    cc := cc + (Int64(z[3]) - xx08);
-    z[3] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-    if (cc <> 0) then
+    LCc := LCc + (Int64(AZ[3]) - LXX08);
+    AZ[3] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+    if LCc <> 0 then
     begin
-      cc := cc + Int64(z[4]);
-      z[4] := UInt32(cc);
-      cc := TBitOperations.Asr64(cc, 32);
-      cc := cc + Int64(z[5]);
-      z[5] := UInt32(cc);
-      cc := TBitOperations.Asr64(cc, 32);
+      LCc := LCc + Int64(AZ[4]);
+      AZ[4] := UInt32(LCc);
+      LCc := TBitOperations.Asr64(LCc, 32);
+      LCc := LCc + Int64(AZ[5]);
+      AZ[5] := UInt32(LCc);
+      LCc := TBitOperations.Asr64(LCc, 32);
     end;
-    cc := cc + (Int64(z[6]) - xx08);
-    z[6] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-    cc := cc + (Int64(z[7]) + xx08);
-    z[7] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-
-{$IFDEF DEBUG}
-    System.Assert((cc = 0) or (cc = 1));
-{$ENDIF DEBUG}
+    LCc := LCc + (Int64(AZ[6]) - LXX08);
+    AZ[6] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+    LCc := LCc + (Int64(AZ[7]) + LXX08);
+    AZ[7] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+
+    {$IFDEF DEBUG}
+    Assert((LCc = 0) or (LCc = 1));
+    {$ENDIF DEBUG}
   end;
 
-  if ((cc <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    AddPInvTo(z);
-  end;
+  if (LCc <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-class procedure TSecP256R1Field.Square(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Square(const AX, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LTT: TCryptoLibUInt32Array;
 begin
-  tt := TNat256.CreateExt();
-  TNat256.Square(x, tt);
-  Reduce(tt, z);
+  LTT := TNat256.CreateExt();
+  TNat256.Square(AX, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP256R1Field.SquareN(const x: TCryptoLibUInt32Array;
-  n: Int32; const z: TCryptoLibUInt32Array);
-var
-  tt: TCryptoLibUInt32Array;
+class procedure TSecP256R1Field.Square(const AX, AZ, ATT: TCryptoLibUInt32Array);
 begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  tt := TNat256.CreateExt();
-  TNat256.Square(x, tt);
-  Reduce(tt, z);
+  TNat256.Square(AX, ATT);
+  Reduce(ATT, AZ);
+end;
 
-  System.Dec(n);
-  while (n > 0) do
+class procedure TSecP256R1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ: TCryptoLibUInt32Array);
+var
+  LTT: TCryptoLibUInt32Array;
+begin
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  LTT := TNat256.CreateExt();
+  TNat256.Square(AX, LTT);
+  Reduce(LTT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    TNat256.Square(z, tt);
-    Reduce(tt, z);
-    System.Dec(n);
+    TNat256.Square(AZ, LTT);
+    Reduce(LTT, AZ);
+    Dec(AN);
   end;
 end;
 
-class procedure TSecP256R1Field.SubPInvFrom(const z: TCryptoLibUInt32Array);
-var
-  c: Int64;
+class procedure TSecP256R1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ, ATT: TCryptoLibUInt32Array);
 begin
-  c := Int64(z[0]) - 1;
-  z[0] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
-  begin
-    c := c + Int64(z[1]);
-    z[1] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-    c := c + Int64(z[2]);
-    z[2] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-  end;
-  c := c + (Int64(z[3]) + 1);
-  z[3] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  TNat256.Square(AX, ATT);
+  Reduce(ATT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    c := c + Int64(z[4]);
-    z[4] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-    c := c + Int64(z[5]);
-    z[5] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
+    TNat256.Square(AZ, ATT);
+    Reduce(ATT, AZ);
+    Dec(AN);
   end;
-  c := c + (Int64(z[6]) + 1);
-  z[6] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  c := c + (Int64(z[7]) - 1);
-  z[7] := UInt32(c);
-  // c := TBitUtilities.Asr64(c, 32);
 end;
 
-class procedure TSecP256R1Field.Subtract(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Subtract(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  c: Int32;
+  LC: Int32;
 begin
-  c := TNat256.Sub(x, y, z);
-  if (c <> 0) then
-  begin
-    SubPInvFrom(z);
-  end;
+  LC := TNat256.Sub(AX, AY, AZ);
+  if LC <> 0 then
+    SubPInvFrom(AZ);
 end;
 
-class procedure TSecP256R1Field.SubtractExt(const xx, yy,
-  zz: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.SubtractExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array);
 var
-  c: Int32;
+  LC: Int32;
 begin
-  c := TNat.Sub(16, xx, yy, zz);
-  if (c <> 0) then
-  begin
-    TNat.AddTo(16, FPExt, zz);
-  end;
+  LC := TNat.Sub(16, AXX, AYY, AZZ);
+  if LC <> 0 then
+    TNat.AddTo(16, FPExt, AZZ);
 end;
 
-class procedure TSecP256R1Field.Twice(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP256R1Field.Twice(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.ShiftUpBit(8, x, 0, z);
-  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
-  begin
-    AddPInvTo(z);
-  end;
+  LC := TNat.ShiftUpBit(8, AX, 0, AZ);
+  if (LC <> 0) or ((AZ[7] = P7) and TNat256.Gte(AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
 { TSecP256R1FieldElement }
 
-class function TSecP256R1FieldElement.GetQ: TBigInteger;
+class procedure TSecP256R1FieldElement.Boot;
 begin
-  result := TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF'));
+  FQ := TBigInteger.Create(1, THex.Decode('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF'));
 end;
 
-function TSecP256R1FieldElement.GetX: TCryptoLibUInt32Array;
+class constructor TSecP256R1FieldElement.Create;
 begin
-  result := Fx;
+  Boot;
 end;
 
-constructor TSecP256R1FieldElement.Create;
+class function TSecP256R1FieldElement.GetQ: TBigInteger;
 begin
-  Inherited Create();
-  Fx := TNat256.Create();
+  Result := FQ;
 end;
 
-constructor TSecP256R1FieldElement.Create(const x: TBigInteger);
+constructor TSecP256R1FieldElement.Create(const AX: TBigInteger);
 begin
-  if ((not(x.IsInitialized)) or (x.SignValue < 0) or (x.CompareTo(Q) >= 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt
-      (@SInvalidValueForSecP256R1FieldElement, ['x']);
-  end;
-  Inherited Create();
-  Fx := TSecP256R1Field.FromBigInteger(x);
+  Inherited Create;
+  if (not AX.IsInitialized) or (AX.SignValue < 0) or (AX.CompareTo(FQ) >= 0) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidSecP256R1FieldElement);
+  FX := TSecP256R1Field.FromBigInteger(AX);
 end;
 
-constructor TSecP256R1FieldElement.Create(const x: TCryptoLibUInt32Array);
+constructor TSecP256R1FieldElement.Create();
 begin
-  Inherited Create();
-  Fx := x;
+  Inherited Create;
+  FX := TNat256.Create();
 end;
 
-function TSecP256R1FieldElement.GetFieldName: string;
+constructor TSecP256R1FieldElement.Create(const AX: TCryptoLibUInt32Array);
 begin
-  result := 'SecP256R1Field';
+  Inherited Create;
+  FX := AX;
 end;
 
-function TSecP256R1FieldElement.GetFieldSize: Int32;
+function TSecP256R1FieldElement.GetX: TCryptoLibUInt32Array;
 begin
-  result := Q.BitLength;
+  Result := FX;
 end;
 
-function TSecP256R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+function TSecP256R1FieldElement.GetFieldName: String;
 begin
-  result := Q.GetHashCode() xor TArrayUtilities.GetArrayHashCode(Fx, 0, 8);
+  Result := 'SecP256R1Field';
+end;
+
+function TSecP256R1FieldElement.GetFieldSize: Int32;
+begin
+  Result := FQ.BitLength;
 end;
 
 function TSecP256R1FieldElement.GetIsOne: Boolean;
 begin
-  result := TNat256.IsOne(Fx);
+  Result := TNat256.IsOne(FX);
 end;
 
 function TSecP256R1FieldElement.GetIsZero: Boolean;
 begin
-  result := TNat256.IsZero(Fx);
+  Result := TNat256.IsZero(FX);
 end;
 
-function TSecP256R1FieldElement.Invert: IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
+function TSecP256R1FieldElement.ToBigInteger: TBigInteger;
 begin
-  z := TNat256.Create();
-  TMod.CheckedModOddInverse(TSecP256R1Field.P, Fx, z);
-  result := TSecP256R1FieldElement.Create(z);
+  Result := TNat256.ToBigInteger(FX);
 end;
 
-function TSecP256R1FieldElement.Multiply(const b: IECFieldElement)
-  : IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
+function TSecP256R1FieldElement.TestBitZero: Boolean;
 begin
-  z := TNat256.Create();
-  TSecP256R1Field.Multiply(Fx, (b as ISecP256R1FieldElement).x, z);
-  result := TSecP256R1FieldElement.Create(z);
+  Result := TNat256.GetBit(FX, 0) = 1;
 end;
 
-function TSecP256R1FieldElement.Negate: IECFieldElement;
+function TSecP256R1FieldElement.Add(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256R1Field.Negate(Fx, z);
-  result := TSecP256R1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256R1Field.Add(FX, (AB as ISecP256R1FieldElement).X, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.Sqrt: IECFieldElement;
+function TSecP256R1FieldElement.AddOne: IECFieldElement;
 var
-  x1, t1, t2: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  // Raise this element to the exponent 2^254 - 2^222 + 2^190 + 2^94
-
-  x1 := Fx;
-  if ((TNat256.IsZero(x1)) or (TNat256.IsOne(x1))) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  t1 := TNat256.Create();
-  t2 := TNat256.Create();
-
-  TSecP256R1Field.Square(x1, t1);
-  TSecP256R1Field.Multiply(t1, x1, t1);
-
-  TSecP256R1Field.SquareN(t1, 2, t2);
-  TSecP256R1Field.Multiply(t2, t1, t2);
-
-  TSecP256R1Field.SquareN(t2, 4, t1);
-  TSecP256R1Field.Multiply(t1, t2, t1);
-
-  TSecP256R1Field.SquareN(t1, 8, t2);
-  TSecP256R1Field.Multiply(t2, t1, t2);
-
-  TSecP256R1Field.SquareN(t2, 16, t1);
-  TSecP256R1Field.Multiply(t1, t2, t1);
-
-  TSecP256R1Field.SquareN(t1, 32, t1);
-  TSecP256R1Field.Multiply(t1, x1, t1);
-
-  TSecP256R1Field.SquareN(t1, 96, t1);
-  TSecP256R1Field.Multiply(t1, x1, t1);
-
-  TSecP256R1Field.SquareN(t1, 94, t1);
-  TSecP256R1Field.Multiply(t1, t1, t2);
-
-  if TNat256.Eq(x1, t2) then
-  begin
-    result := TSecP256R1FieldElement.Create(t1);
-  end
-  else
-  begin
-    result := Nil;
-  end;
+  LZ := TNat256.Create();
+  TSecP256R1Field.AddOne(FX, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.Square: IECFieldElement;
+function TSecP256R1FieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256R1Field.Square(Fx, z);
-  result := TSecP256R1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256R1Field.Subtract(FX, (AB as ISecP256R1FieldElement).X, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.Subtract(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP256R1FieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256R1Field.Subtract(Fx, (b as ISecP256R1FieldElement).x, z);
-  result := TSecP256R1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256R1Field.Multiply(FX, (AB as ISecP256R1FieldElement).X, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.TestBitZero: Boolean;
+function TSecP256R1FieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
+var
+  LZ: TCryptoLibUInt32Array;
 begin
-  result := TNat256.GetBit(Fx, 0) = 1;
+  LZ := TNat256.Create();
+  TSecP256R1Field.Inv((AB as ISecP256R1FieldElement).X, LZ);
+  TSecP256R1Field.Multiply(LZ, FX, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.ToBigInteger: TBigInteger;
+function TSecP256R1FieldElement.Negate: IECFieldElement;
+var
+  LZ: TCryptoLibUInt32Array;
 begin
-  result := TNat256.ToBigInteger(Fx);
+  LZ := TNat256.Create();
+  TSecP256R1Field.Negate(FX, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.Add(const b: IECFieldElement): IECFieldElement;
+function TSecP256R1FieldElement.Square: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256R1Field.Add(Fx, (b as ISecP256R1FieldElement).x, z);
-  result := TSecP256R1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256R1Field.Square(FX, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.AddOne: IECFieldElement;
+function TSecP256R1FieldElement.Invert: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TSecP256R1Field.AddOne(Fx, z);
-  result := TSecP256R1FieldElement.Create(z);
+  LZ := TNat256.Create();
+  TSecP256R1Field.Inv(FX, LZ);
+  Result := TSecP256R1FieldElement.Create(LZ);
 end;
 
-function TSecP256R1FieldElement.Divide(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP256R1FieldElement.Sqrt: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LX1, LTT0, LT1, LT2: TCryptoLibUInt32Array;
 begin
-  z := TNat256.Create();
-  TMod.CheckedModOddInverse(TSecP256R1Field.P, (b as ISecP256R1FieldElement).x, z);
-  TSecP256R1Field.Multiply(z, Fx, z);
-  result := TSecP256R1FieldElement.Create(z);
+  LX1 := FX;
+  if TNat256.IsZero(LX1) or TNat256.IsOne(LX1) then
+    Exit(Self as IECFieldElement);
+
+  LTT0 := TNat256.CreateExt();
+  LT1 := TNat256.Create();
+  LT2 := TNat256.Create();
+
+  TSecP256R1Field.Square(LX1, LT1, LTT0);
+  TSecP256R1Field.Multiply(LT1, LX1, LT1, LTT0);
+
+  TSecP256R1Field.SquareN(LT1, 2, LT2, LTT0);
+  TSecP256R1Field.Multiply(LT2, LT1, LT2, LTT0);
+
+  TSecP256R1Field.SquareN(LT2, 4, LT1, LTT0);
+  TSecP256R1Field.Multiply(LT1, LT2, LT1, LTT0);
+
+  TSecP256R1Field.SquareN(LT1, 8, LT2, LTT0);
+  TSecP256R1Field.Multiply(LT2, LT1, LT2, LTT0);
+
+  TSecP256R1Field.SquareN(LT2, 16, LT1, LTT0);
+  TSecP256R1Field.Multiply(LT1, LT2, LT1, LTT0);
+
+  TSecP256R1Field.SquareN(LT1, 32, LT1, LTT0);
+  TSecP256R1Field.Multiply(LT1, LX1, LT1, LTT0);
+
+  TSecP256R1Field.SquareN(LT1, 96, LT1, LTT0);
+  TSecP256R1Field.Multiply(LT1, LX1, LT1, LTT0);
+
+  TSecP256R1Field.SquareN(LT1, 94, LT1, LTT0);
+  TSecP256R1Field.Multiply(LT1, LT1, LT2, LTT0);
+
+  if TNat256.Eq(LX1, LT2) then
+    Result := TSecP256R1FieldElement.Create(LT1)
+  else
+    Result := nil;
 end;
 
-function TSecP256R1FieldElement.Equals(const AOther: ISecP256R1FieldElement): Boolean;
+function TSecP256R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
 begin
-  if (Self as ISecP256R1FieldElement) = AOther then
+  if (Self as IECFieldElement) = AOther then
     Exit(True);
   if AOther = nil then
     Exit(False);
-  Result := TNat256.Eq(Fx, AOther.x);
+  Result := TNat256.Eq(FX, (AOther as ISecP256R1FieldElement).X);
 end;
 
-function TSecP256R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
-var
-  LSec: ISecP256R1FieldElement;
+function TSecP256R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
 begin
-  if AOther = nil then
-    Exit(False);
-  if Supports(AOther, ISecP256R1FieldElement, LSec) then
-    Result := Equals(LSec)
-  else
-    Result := ToBigInteger.Equals(AOther.ToBigInteger);
+  Result := FQ.GetHashCode() xor TArrayUtilities.GetArrayHashCode(FX, 0, 8);
 end;
 
 { TSecP256R1Point }
 
-constructor TSecP256R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
+constructor TSecP256R1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
 begin
-  Create(curve, x, y, false);
+  Inherited Create(ACurve, AX, AY);
 end;
 
-constructor TSecP256R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
+constructor TSecP256R1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
 begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SOneOfECFieldElementIsNil);
-  end;
+  Inherited Create(ACurve, AX, AY, AZs);
 end;
 
-constructor TSecP256R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
+function TSecP256R1Point.Detach: IECPoint;
 begin
-  Inherited Create(curve, x, y, zs, withCompression);
+  Result := TSecP256R1Point.Create(nil, AffineXCoord, AffineYCoord);
 end;
 
-function TSecP256R1Point.Add(const b: IECPoint): IECPoint;
+function TSecP256R1Point.Add(const AB: IECPoint): IECPoint;
 var
-  Lcurve: IECCurve;
-  x1, Y1, X2, Y2, Z1, Z2, X3, Y3, Z3: ISecP256R1FieldElement;
-  c: UInt32;
-  tt1, t2, t3, t4, U2, S2, U1, S1, H, R, HSquared, G, V: TCryptoLibUInt32Array;
-  Z1IsOne, Z2IsOne: Boolean;
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-begin
-  if (IsInfinity) then
+  LCurve: IECCurve;
+  LX1, LY1, LX2, LY2, LZ1, LZ2: ISecP256R1FieldElement;
+  LTT0, LTT1: TCryptoLibUInt32Array;
+  LT2, LT3, LT4: TCryptoLibUInt32Array;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  LU2, LS2, LU1, LS1: TCryptoLibUInt32Array;
+  LH, LR, LHSquared, LG, LV: TCryptoLibUInt32Array;
+  LC: UInt32;
+  LX3, LY3, LZ3: ISecP256R1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Self as IECPoint);
+  if (Self as IECPoint) = AB then
+    Exit(Twice());
+
+  LCurve := Curve;
+  LX1 := RawXCoord as ISecP256R1FieldElement;
+  LY1 := RawYCoord as ISecP256R1FieldElement;
+  LX2 := AB.RawXCoord as ISecP256R1FieldElement;
+  LY2 := AB.RawYCoord as ISecP256R1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP256R1FieldElement;
+  LZ2 := AB.GetZCoord(0) as ISecP256R1FieldElement;
+
+  LTT0 := TNat256.CreateExt();
+  LTT1 := TNat256.CreateExt();
+  LT2 := TNat256.Create();
+  LT3 := TNat256.Create();
+  LT4 := TNat256.Create();
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
   begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
+    LU2 := LX2.X;
+    LS2 := LY2.X;
+  end
+  else
   begin
-    result := Self as IECPoint;
-    Exit;
+    LS2 := LT3;
+    TSecP256R1Field.Square(LZ1.X, LS2, LTT0);
+    LU2 := LT2;
+    TSecP256R1Field.Multiply(LS2, LX2.X, LU2, LTT0);
+    TSecP256R1Field.Multiply(LS2, LZ1.X, LS2, LTT0);
+    TSecP256R1Field.Multiply(LS2, LY2.X, LS2, LTT0);
   end;
-  if ((Self as IECPoint) = b) then
+
+  LZ2IsOne := LZ2.IsOne;
+  if LZ2IsOne then
+  begin
+    LU1 := LX1.X;
+    LS1 := LY1.X;
+  end
+  else
   begin
-    result := Twice();
-    Exit;
+    LS1 := LT4;
+    TSecP256R1Field.Square(LZ2.X, LS1, LTT0);
+    LU1 := LTT1;
+    TSecP256R1Field.Multiply(LS1, LX1.X, LU1, LTT0);
+    TSecP256R1Field.Multiply(LS1, LZ2.X, LS1, LTT0);
+    TSecP256R1Field.Multiply(LS1, LY1.X, LS1, LTT0);
   end;
 
-  Lcurve := curve;
+  LH := TNat256.Create();
+  TSecP256R1Field.Subtract(LU1, LU2, LH);
 
-  x1 := RawXCoord as ISecP256R1FieldElement;
-  Y1 := RawYCoord as ISecP256R1FieldElement;
-  X2 := b.RawXCoord as ISecP256R1FieldElement;
-  Y2 := b.RawYCoord as ISecP256R1FieldElement;
+  LR := LT2;
+  TSecP256R1Field.Subtract(LS1, LS2, LR);
 
-  Z1 := RawZCoords[0] as ISecP256R1FieldElement;
-  Z2 := b.RawZCoords[0] as ISecP256R1FieldElement;
+  if TNat256.IsZero(LH) then
+  begin
+    if TNat256.IsZero(LR) then
+      Exit(Twice());
+    Exit(LCurve.Infinity);
+  end;
 
-  tt1 := TNat256.CreateExt();
-  t2 := TNat256.Create();
-  t3 := TNat256.Create();
-  t4 := TNat256.Create();
+  LHSquared := LT3;
+  TSecP256R1Field.Square(LH, LHSquared, LTT0);
 
-  Z1IsOne := Z1.IsOne;
+  LG := TNat256.Create();
+  TSecP256R1Field.Multiply(LHSquared, LH, LG, LTT0);
 
-  if (Z1IsOne) then
-  begin
-    U2 := X2.x;
-    S2 := Y2.x;
-  end
-  else
-  begin
-    S2 := t3;
-    TSecP256R1Field.Square(Z1.x, S2);
-
-    U2 := t2;
-    TSecP256R1Field.Multiply(S2, X2.x, U2);
+  LV := LT3;
+  TSecP256R1Field.Multiply(LHSquared, LU1, LV, LTT0);
 
-    TSecP256R1Field.Multiply(S2, Z1.x, S2);
-    TSecP256R1Field.Multiply(S2, Y2.x, S2);
-  end;
+  TSecP256R1Field.Negate(LG, LG);
+  TNat256.Mul(LS1, LG, LTT1);
 
-  Z2IsOne := Z2.IsOne;
-  if (Z2IsOne) then
-  begin
-    U1 := x1.x;
-    S1 := Y1.x;
-  end
-  else
-  begin
-    S1 := t4;
-    TSecP256R1Field.Square(Z2.x, S1);
+  LC := TNat256.AddBothTo(LV, LV, LG);
+  TSecP256R1Field.Reduce32(LC, LG);
 
-    U1 := tt1;
-    TSecP256R1Field.Multiply(S1, x1.x, U1);
+  LX3 := TSecP256R1FieldElement.Create(LT4);
+  TSecP256R1Field.Square(LR, LX3.X, LTT0);
+  TSecP256R1Field.Subtract(LX3.X, LG, LX3.X);
 
-    TSecP256R1Field.Multiply(S1, Z2.x, S1);
-    TSecP256R1Field.Multiply(S1, Y1.x, S1);
-  end;
+  LY3 := TSecP256R1FieldElement.Create(LG);
+  TSecP256R1Field.Subtract(LV, LX3.X, LY3.X);
+  TSecP256R1Field.MultiplyAddToExt(LY3.X, LR, LTT1);
+  TSecP256R1Field.Reduce(LTT1, LY3.X);
 
-  H := TNat256.Create();
-  TSecP256R1Field.Subtract(U1, U2, H);
+  LZ3 := TSecP256R1FieldElement.Create(LH);
+  if not LZ1IsOne then
+    TSecP256R1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
+  if not LZ2IsOne then
+    TSecP256R1Field.Multiply(LZ3.X, LZ2.X, LZ3.X, LTT0);
 
-  R := t2;
-  TSecP256R1Field.Subtract(S1, S2, R);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP256R1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
 
-  // Check if b = Self or b = -Self
-  if (TNat256.IsZero(H)) then
+function TSecP256R1Point.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LY1, LX1, LZ1: ISecP256R1FieldElement;
+  LTT0: TCryptoLibUInt32Array;
+  LY1Squared, LT, LT1, LT2: TCryptoLibUInt32Array;
+  LZ1Squared, LM, LS: TCryptoLibUInt32Array;
+  LZ1IsOne: Boolean;
+  LC: UInt32;
+  LX3, LY3, LZ3: ISecP256R1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(Self as IECPoint);
+
+  LCurve := Curve;
+  LY1 := RawYCoord as ISecP256R1FieldElement;
+  if LY1.IsZero then
+    Exit(LCurve.Infinity);
+
+  LX1 := RawXCoord as ISecP256R1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP256R1FieldElement;
+
+  LTT0 := TNat256.CreateExt();
+  LT1 := TNat256.Create();
+  LT2 := TNat256.Create();
+
+  LY1Squared := TNat256.Create();
+  TSecP256R1Field.Square(LY1.X, LY1Squared, LTT0);
+
+  LT := TNat256.Create();
+  TSecP256R1Field.Square(LY1Squared, LT, LTT0);
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
+    LZ1Squared := LZ1.X
+  else
   begin
-    if (TNat256.IsZero(R)) then
-    begin
-      // Self = b, i.e. Self must be doubled
-      result := Twice();
-      Exit;
-    end;
-
-    // Self = -b, i.e. the result is the point at infinity
-    result := Lcurve.Infinity;
-    Exit;
+    LZ1Squared := LT2;
+    TSecP256R1Field.Square(LZ1.X, LZ1Squared, LTT0);
   end;
 
-  HSquared := t3;
-  TSecP256R1Field.Square(H, HSquared);
+  TSecP256R1Field.Subtract(LX1.X, LZ1Squared, LT1);
 
-  G := TNat256.Create();
-  TSecP256R1Field.Multiply(HSquared, H, G);
+  LM := LT2;
+  TSecP256R1Field.Add(LX1.X, LZ1Squared, LM);
+  TSecP256R1Field.Multiply(LM, LT1, LM, LTT0);
+  LC := TNat256.AddBothTo(LM, LM, LM);
+  TSecP256R1Field.Reduce32(LC, LM);
 
-  V := t3;
-  TSecP256R1Field.Multiply(HSquared, U1, V);
+  LS := LY1Squared;
+  TSecP256R1Field.Multiply(LY1Squared, LX1.X, LS, LTT0);
+  LC := TNat.ShiftUpBits(8, LS, 2, 0, LS);
+  TSecP256R1Field.Reduce32(LC, LS);
 
-  TSecP256R1Field.Negate(G, G);
-  TNat256.Mul(S1, G, tt1);
+  LC := TNat.ShiftUpBits(8, LT, 3, 0, LT1);
+  TSecP256R1Field.Reduce32(LC, LT1);
 
-  c := TNat256.AddBothTo(V, V, G);
-  TSecP256R1Field.Reduce32(c, G);
+  LX3 := TSecP256R1FieldElement.Create(LT);
+  TSecP256R1Field.Square(LM, LX3.X, LTT0);
+  TSecP256R1Field.Subtract(LX3.X, LS, LX3.X);
+  TSecP256R1Field.Subtract(LX3.X, LS, LX3.X);
 
-  X3 := TSecP256R1FieldElement.Create(t4);
-  TSecP256R1Field.Square(R, X3.x);
-  TSecP256R1Field.Subtract(X3.x, G, X3.x);
+  LY3 := TSecP256R1FieldElement.Create(LS);
+  TSecP256R1Field.Subtract(LS, LX3.X, LY3.X);
+  TSecP256R1Field.Multiply(LY3.X, LM, LY3.X, LTT0);
+  TSecP256R1Field.Subtract(LY3.X, LT1, LY3.X);
 
-  Y3 := TSecP256R1FieldElement.Create(G);
-  TSecP256R1Field.Subtract(V, X3.x, Y3.x);
-  TSecP256R1Field.MultiplyAddToExt(Y3.x, R, tt1);
-  TSecP256R1Field.Reduce(tt1, Y3.x);
+  LZ3 := TSecP256R1FieldElement.Create(LM);
+  TSecP256R1Field.Twice(LY1.X, LZ3.X);
+  if not LZ1IsOne then
+    TSecP256R1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
 
-  Z3 := TSecP256R1FieldElement.Create(H);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
-  end;
-  if (not(Z2IsOne)) then
-  begin
-    TSecP256R1Field.Multiply(Z3.x, Z2.x, Z3.x);
-  end;
-
-  zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP256R1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
 
-  result := TSecP256R1Point.Create(Lcurve, X3, Y3, zs, IsCompressed)
-    as IECPoint;
+function TSecP256R1Point.TwicePlus(const AB: IECPoint): IECPoint;
+begin
+  if (Self as IECPoint) = AB then
+    Exit(ThreeTimes());
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Twice());
+  if RawYCoord.IsZero then
+    Exit(AB);
+  Result := Twice().Add(AB);
 end;
 
-function TSecP256R1Point.Detach: IECPoint;
+function TSecP256R1Point.ThreeTimes: IECPoint;
 begin
-  result := TSecP256R1Point.Create(Nil, AffineXCoord, AffineYCoord) as IECPoint;
+  if IsInfinity or RawYCoord.IsZero then
+    Exit(Self as IECPoint);
+  Result := Twice().Add(Self as IECPoint);
 end;
 
 function TSecP256R1Point.Negate: IECPoint;
 begin
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  if IsInfinity then
+    Exit(Self as IECPoint);
+  Result := TSecP256R1Point.Create(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords);
+end;
+
+{ TSecP256R1Curve.TSecP256R1LookupTable }
 
-  result := TSecP256R1Point.Create(curve, RawXCoord, RawYCoord.Negate(),
-    RawZCoords, IsCompressed) as IECPoint;
+constructor TSecP256R1Curve.TSecP256R1LookupTable.Create(const AOuter: ISecP256R1Curve;
+  const ATable: TCryptoLibUInt32Array; ASize: Int32);
+begin
+  Inherited Create;
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
 end;
 
-function TSecP256R1Point.ThreeTimes: IECPoint;
+function TSecP256R1Curve.TSecP256R1LookupTable.GetSize: Int32;
 begin
-  if ((IsInfinity) or (RawYCoord.IsZero)) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  Result := FSize;
+end;
 
-  // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
-  result := Twice().Add(Self as IECPoint);
+function TSecP256R1Curve.TSecP256R1LookupTable.CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
+begin
+  Result := FOuter.CreateRawPoint(TSecP256R1FieldElement.Create(AX) as IECFieldElement,
+    TSecP256R1FieldElement.Create(AY) as IECFieldElement, TSecP256R1Curve.SecP256R1AffineZs);
 end;
 
-function TSecP256R1Point.Twice: IECPoint;
+function TSecP256R1Curve.TSecP256R1LookupTable.Lookup(AIndex: Int32): IECPoint;
 var
-  Lcurve: IECCurve;
-  Y1, x1, Z1, X3, Y3, Z3: ISecP256R1FieldElement;
-  c: UInt32;
-  Y1Squared, Z1Squared, t1, t2, T, M, S: TCryptoLibUInt32Array;
-  Z1IsOne: Boolean;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LI, LJ: Int32;
+  LMask: UInt32;
 begin
+  LX := TNat256.Create();
+  LY := TNat256.Create();
+  LPos := 0;
 
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  Lcurve := curve;
-
-  Y1 := RawYCoord as ISecP256R1FieldElement;
-  if (Y1.IsZero) then
-  begin
-    result := Lcurve.Infinity;
-    Exit;
-  end;
-
-  x1 := RawXCoord as ISecP256R1FieldElement;
-  Z1 := RawZCoords[0] as ISecP256R1FieldElement;
-
-  t1 := TNat256.Create();
-  t2 := TNat256.Create();
-
-  Y1Squared := TNat256.Create();
-  TSecP256R1Field.Square(Y1.x, Y1Squared);
-
-  T := TNat256.Create();
-  TSecP256R1Field.Square(Y1Squared, T);
-
-  Z1IsOne := Z1.IsOne;
-
-  Z1Squared := Z1.x;
-  if (not(Z1IsOne)) then
+  for LI := 0 to System.Pred(FSize) do
   begin
-    Z1Squared := t2;
-    TSecP256R1Field.Square(Z1.x, Z1Squared);
-  end;
-
-  TSecP256R1Field.Subtract(x1.x, Z1Squared, t1);
-
-  M := t2;
-  TSecP256R1Field.Add(x1.x, Z1Squared, M);
-  TSecP256R1Field.Multiply(M, t1, M);
-  c := TNat256.AddBothTo(M, M, M);
-  TSecP256R1Field.Reduce32(c, M);
+    LMask := UInt32(TBitOperations.Asr32(((LI xor AIndex) - 1), 31));
 
-  S := Y1Squared;
-  TSecP256R1Field.Multiply(Y1Squared, x1.x, S);
-  c := TNat.ShiftUpBits(8, S, 2, 0);
-  TSecP256R1Field.Reduce32(c, S);
-
-  c := TNat.ShiftUpBits(8, T, 3, 0, t1);
-  TSecP256R1Field.Reduce32(c, t1);
-
-  X3 := TSecP256R1FieldElement.Create(T);
-  TSecP256R1Field.Square(M, X3.x);
-  TSecP256R1Field.Subtract(X3.x, S, X3.x);
-  TSecP256R1Field.Subtract(X3.x, S, X3.x);
-
-  Y3 := TSecP256R1FieldElement.Create(S);
-  TSecP256R1Field.Subtract(S, X3.x, Y3.x);
-  TSecP256R1Field.Multiply(Y3.x, M, Y3.x);
-  TSecP256R1Field.Subtract(Y3.x, t1, Y3.x);
+    for LJ := 0 to System.Pred(SECP256R1_FE_INTS) do
+    begin
+      LX[LJ] := LX[LJ] xor (FTable[LPos + LJ] and LMask);
+      LY[LJ] := LY[LJ] xor (FTable[LPos + SECP256R1_FE_INTS + LJ] and LMask);
+    end;
 
-  Z3 := TSecP256R1FieldElement.Create(M);
-  TSecP256R1Field.Twice(Y1.x, Z3.x);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+    LPos := LPos + (SECP256R1_FE_INTS * 2);
   end;
 
-  result := TSecP256R1Point.Create(Lcurve, X3, Y3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed)
-    as IECPoint;
+  Result := CreatePoint(LX, LY);
 end;
 
-function TSecP256R1Point.TwicePlus(const b: IECPoint): IECPoint;
+function TSecP256R1Curve.TSecP256R1LookupTable.LookupVar(AIndex: Int32): IECPoint;
 var
-  Y1: IECFieldElement;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LJ: 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;
+  LX := TNat256.Create();
+  LY := TNat256.Create();
+  LPos := AIndex * SECP256R1_FE_INTS * 2;
 
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
+  for LJ := 0 to System.Pred(SECP256R1_FE_INTS) do
   begin
-    result := b;
-    Exit;
+    LX[LJ] := FTable[LPos + LJ];
+    LY[LJ] := FTable[LPos + SECP256R1_FE_INTS + LJ];
   end;
 
-  result := Twice().Add(b);
+  Result := CreatePoint(LX, LY);
 end;
 
 { TSecP256R1Curve }
 
-constructor TSecP256R1Curve.Create;
+class procedure TSecP256R1Curve.Boot;
 begin
-  Fq := TSecP256R1FieldElement.Q;
-  Inherited Create(Fq);
-  Fm_infinity := TSecP256R1Point.Create(Self as IECCurve, Nil, Nil);
-  Fm_a := FromBigInteger(TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC')));
-  Fm_b := FromBigInteger(TBigInteger.Create(1,
-    THex.Decode
-    ('5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B')));
-  Fm_order := TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551'));
-  Fm_cofactor := TBigInteger.One;
-  Fm_coord := SECP256R1_DEFAULT_COORDS;
+  FQ := TSecP256R1FieldElement.Q;
+  FSecP256R1AffineZs := TCryptoLibGenericArray<IECFieldElement>.Create(
+    TSecP256R1FieldElement.Create(TBigInteger.One) as IECFieldElement);
 end;
 
-function TSecP256R1Curve.CloneCurve: IECCurve;
+class constructor TSecP256R1Curve.Create;
 begin
-  result := TSecP256R1Curve.Create();
+  Boot;
 end;
 
-function TSecP256R1Curve.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  table: TCryptoLibUInt32Array;
-  pos, i: Int32;
-  P: IECPoint;
+constructor TSecP256R1Curve.Create;
 begin
-  System.SetLength(table, len * SECP256R1_FE_INTS * 2);
-
-  pos := 0;
-  for i := 0 to System.Pred(len) do
-  begin
-    P := points[off + i];
-    TNat256.Copy((P.RawXCoord as ISecP256R1FieldElement).x, 0, table, pos);
-    pos := pos + SECP256R1_FE_INTS;
-    TNat256.Copy((P.RawYCoord as ISecP256R1FieldElement).x, 0, table, pos);
-    pos := pos + SECP256R1_FE_INTS;
-  end;
-
-  result := TSecP256R1LookupTable.Create(Self as ISecP256R1Curve, table, len);
+  Inherited Create(TSecP256R1Curve.Q, True);
+  FInfinity := TSecP256R1Point.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(TBigInteger.Create(1, THex.Decode('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC')));
+  FB := FromBigInteger(TBigInteger.Create(1, THex.Decode('5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B')));
+  FOrder := TBigInteger.Create(1, THex.Decode('FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551'));
+  FCofactor := TBigInteger.One;
+  FCoord := SECP256R1_DEFAULT_COORDS;
 end;
 
-function TSecP256R1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
+destructor TSecP256R1Curve.Destroy;
 begin
-  result := TSecP256R1Point.Create(Self as IECCurve, x, y, withCompression);
+  FInfinity := nil;
+  inherited Destroy;
 end;
 
-function TSecP256R1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
+function TSecP256R1Curve.GetQ: TBigInteger;
 begin
-  result := TSecP256R1Point.Create(Self as IECCurve, x, y, zs, withCompression);
+  Result := TSecP256R1Curve.Q;
 end;
 
-function TSecP256R1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
+function TSecP256R1Curve.CloneCurve: IECCurve;
 begin
-  result := TSecP256R1FieldElement.Create(x);
+  Result := TSecP256R1Curve.Create;
 end;
 
 function TSecP256R1Curve.GetFieldSize: Int32;
 begin
-  result := Fq.BitLength;
+  Result := TSecP256R1Curve.Q.BitLength;
 end;
 
 function TSecP256R1Curve.GetInfinity: IECPoint;
 begin
-  result := Fm_infinity;
+  Result := FInfinity;
 end;
 
-function TSecP256R1Curve.GetQ: TBigInteger;
+function TSecP256R1Curve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
 begin
-  result := Fq;
+  Result := TSecP256R1FieldElement.Create(AX);
 end;
 
-function TSecP256R1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
+function TSecP256R1Curve.CreateRawPoint(const AX, AY: IECFieldElement): IECPoint;
 begin
-  case coord of
-    TECCurveConstants.COORD_JACOBIAN:
-      result := true
-  else
-    result := false;
-  end;
+  Result := TSecP256R1Point.Create(Self as IECCurve, AX, AY);
 end;
 
-{ TSecP256R1Curve.TSecP256R1LookupTable }
-
-constructor TSecP256R1Curve.TSecP256R1LookupTable.Create
-  (const outer: ISecP256R1Curve; const table: TCryptoLibUInt32Array;
-  size: Int32);
+function TSecP256R1Curve.CreateRawPoint(const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
 begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := size;
+  Result := TSecP256R1Point.Create(Self as IECCurve, AX, AY, AZs);
 end;
 
-function TSecP256R1Curve.TSecP256R1LookupTable.CreatePoint(const x,
-  y: TCryptoLibUInt32Array): IECPoint;
+function TSecP256R1Curve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
 var
-  XFieldElement, YFieldElement: ISecP256R1FieldElement;
-  SECP256R1_AFFINE_ZS: TCryptoLibGenericArray<IECFieldElement>;
+  LTable: TCryptoLibUInt32Array;
+  LPos, LI: Int32;
+  LP: IECPoint;
 begin
-  SECP256R1_AFFINE_ZS := TCryptoLibGenericArray<IECFieldElement>.Create
-    (TSecP256R1FieldElement.Create(TBigInteger.One) as ISecP256R1FieldElement);
-
-  XFieldElement := TSecP256R1FieldElement.Create(x);
-  YFieldElement := TSecP256R1FieldElement.Create(y);
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement,
-    SECP256R1_AFFINE_ZS, false);
+  System.SetLength(LTable, ALen * SECP256R1_FE_INTS * 2);
+  LPos := 0;
+  for LI := 0 to System.Pred(ALen) do
+  begin
+    LP := APoints[AOff + LI];
+    TNat256.Copy((LP.RawXCoord as ISecP256R1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP256R1_FE_INTS;
+    TNat256.Copy((LP.RawYCoord as ISecP256R1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP256R1_FE_INTS;
+  end;
+  Result := TSecP256R1LookupTable.Create(Self as ISecP256R1Curve, LTable, ALen);
 end;
 
-function TSecP256R1Curve.TSecP256R1LookupTable.GetSize: Int32;
+function TSecP256R1Curve.RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LX: TCryptoLibUInt32Array;
 begin
-  result := Fm_size;
+  LX := TNat256.Create();
+  TSecP256R1Field.Random(ARandom, LX);
+  Result := TSecP256R1FieldElement.Create(LX);
 end;
 
-function TSecP256R1Curve.TSecP256R1LookupTable.Lookup(index: Int32): IECPoint;
+function TSecP256R1Curve.RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
 var
-  x, y: TCryptoLibUInt32Array;
-  pos, i, J: Int32;
-  MASK: UInt32;
+  LX: TCryptoLibUInt32Array;
 begin
-  x := TNat256.Create();
-  y := TNat256.Create();
-  pos := 0;
-
-  for i := 0 to System.Pred(Fm_size) do
-  begin
-    MASK := UInt32(TBitOperations.Asr32((i xor index) - 1, 31));
-
-    for J := 0 to System.Pred(SECP256R1_FE_INTS) do
-    begin
-      x[J] := x[J] xor (Fm_table[pos + J] and MASK);
-      y[J] := y[J] xor (Fm_table[pos + SECP256R1_FE_INTS + J] and MASK);
-    end;
-
-    pos := pos + (SECP256R1_FE_INTS * 2);
-  end;
-
-  result := CreatePoint(x, y);
+  LX := TNat256.Create();
+  TSecP256R1Field.RandomMult(ARandom, LX);
+  Result := TSecP256R1FieldElement.Create(LX);
 end;
 
-function TSecP256R1Curve.TSecP256R1LookupTable.LookupVar(index: Int32)
-  : IECPoint;
-var
-  x, y: TCryptoLibUInt32Array;
-  pos, J: Int32;
+function TSecP256R1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
 begin
-  x := TNat256.Create();
-  y := TNat256.Create();
-  pos := index * SECP256R1_FE_INTS * 2;
-
-  for J := 0 to System.Pred(SECP256R1_FE_INTS) do
-  begin
-    x[J] := Fm_table[pos + J];
-    y[J] := Fm_table[pos + SECP256R1_FE_INTS + J];
+  case ACoord of
+    TECCurveConstants.COORD_JACOBIAN:
+      Result := True;
+  else
+    Result := False;
   end;
-
-  result := CreatePoint(x, y);
 end;
 
 end.

+ 850 - 981
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas

@@ -22,1328 +22,1197 @@ unit ClpSecP384R1Custom;
 interface
 
 uses
+  SysUtils,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpNat384,
+  ClpNat,
   ClpMod,
+  ClpPack,
   ClpEncoders,
-  ClpNat,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpArrayUtilities,
   ClpBitOperations,
-  ClpNat384,
   ClpECCurve,
-  ClpBigInteger,
-  ClpArrayUtilities,
-  ClpCryptoLibTypes,
   ClpECCurveConstants,
+  ClpECFieldElement,
+  ClpECPoint,
+  ClpECLookupTables,
+  ClpFiniteFields,
   ClpIECCore,
   ClpIECFieldElement,
-  ClpISecP384R1Custom;
+  ClpISecP384R1Custom,
+  ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidValueForSecP384R1FieldElement =
-    'Value Invalid for SecP384R1FieldElement "%s"';
-  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
+  SInvalidSecP384R1FieldElement = 'value invalid for SecP384R1FieldElement';
 
 type
-  // 2^384 - 2^128 - 2^96 + 2^32 - 1
   TSecP384R1Field = class sealed(TObject)
-
   strict private
   const
     P11 = UInt32($FFFFFFFF);
     PExt23 = UInt32($FFFFFFFF);
-
-    class var
-
-      FP, FPExt, FPExtInv: TCryptoLibUInt32Array;
-
-    class function GetP: TCryptoLibUInt32Array; static; inline;
-
-    class procedure AddPInvTo(const z: TCryptoLibUInt32Array); static;
-    class procedure SubPInvFrom(const z: TCryptoLibUInt32Array); static;
-
-    class procedure Boot(); static;
-    class constructor SecP384R1Field();
-
+  class var
+    FP, FPExt, FPExtInv: TCryptoLibUInt32Array;
+  class procedure Boot; static;
+  class procedure AddPInvTo(const AZ: TCryptoLibUInt32Array); static;
+  class procedure SubPInvFrom(const AZ: TCryptoLibUInt32Array); static;
+  class constructor Create;
   public
-    class procedure Add(const x, y, z: TCryptoLibUInt32Array); static; inline;
-    class procedure AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure AddOne(const x, z: TCryptoLibUInt32Array); static; inline;
-    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt32Array;
-      static; inline;
-    class procedure Half(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Multiply(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Negate(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce(const xx, z: TCryptoLibUInt32Array); static;
-    class procedure Reduce32(x: UInt32; const z: TCryptoLibUInt32Array); static;
-    class procedure Square(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure SquareN(const x: TCryptoLibUInt32Array; n: Int32;
-      const z: TCryptoLibUInt32Array); static; inline;
-    class procedure Subtract(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure SubtractExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Twice(const x, z: TCryptoLibUInt32Array); static; inline;
-
-    class property P: TCryptoLibUInt32Array read GetP;
+    class procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure AddExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure AddOne(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array; static;
+    class procedure Half(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Inv(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Int32; static;
+    class procedure Multiply(const AX, AY, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure Negate(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce(const AXX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce32(AX: UInt32; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Square(const AX, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure Subtract(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure SubtractExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array); static;
+    class procedure Twice(const AX, AZ: TCryptoLibUInt32Array); static;
+
+    class property P: TCryptoLibUInt32Array read FP;
   end;
 
 type
-  TSecP384R1FieldElement = class(TAbstractFpFieldElement,
-    ISecP384R1FieldElement)
-
+  TSecP384R1FieldElement = class sealed(TAbstractFpFieldElement,
+    IAbstractFpFieldElement, IECFieldElement, ISecP384R1FieldElement)
   strict private
-
-    function Equals(const AOther: ISecP384R1FieldElement): Boolean;
-      reintroduce; overload;
-
-    class function GetQ: TBigInteger; static; inline;
-
+  class var
+    FQ: TBigInteger;
+  class procedure Boot; static;
+  class constructor Create;
   strict protected
-  var
-    Fx: TCryptoLibUInt32Array;
-
-    function GetFieldName: string; override;
-    function GetFieldSize: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
+    FX: TCryptoLibUInt32Array;
     function GetX: TCryptoLibUInt32Array; inline;
-    property x: TCryptoLibUInt32Array read GetX;
-
   public
+    class function GetQ: TBigInteger; static;
+    class property Q: TBigInteger read GetQ;
+    constructor Create(const AX: TBigInteger); overload;
     constructor Create(); overload;
-    constructor Create(const x: TBigInteger); overload;
-    constructor Create(const x: TCryptoLibUInt32Array); overload;
+    constructor Create(const AX: TCryptoLibUInt32Array); overload;
 
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+    function ToBigInteger: TBigInteger; 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 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 Divide(const AB: IECFieldElement): IECFieldElement; override;
+    function Negate: IECFieldElement; override;
+    function Square: IECFieldElement; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: 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 Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
-    function Invert(): IECFieldElement; override;
-
-    /// <summary>
-    /// return a sqrt root - the routine verifies that the calculation
-    /// returns the right value - if <br />none exists it returns null.
-    /// </summary>
-    function Sqrt(): IECFieldElement; override;
-
-    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    property IsZero: Boolean read GetIsZero;
-    property IsOne: Boolean read GetIsOne;
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    class property Q: TBigInteger read GetQ;
+    property X: TCryptoLibUInt32Array read GetX;
   end;
 
 type
-  TSecP384R1Point = class sealed(TAbstractFpPoint, ISecP384R1Point)
-
+  TSecP384R1Point = class sealed(TAbstractFpPoint, IAbstractFpPoint, IECPoint,
+    ISecP384R1Point)
   strict protected
-    function Detach(): IECPoint; override;
-
+    function Detach: IECPoint; override;
   public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="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 that encodes with or without point compresion.
-    /// </summary>
-    /// <param name="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;
-
-    function Add(const b: IECPoint): IECPoint; override;
-    function Negate(): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function ThreeTimes(): IECPoint; override;
-
+    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 Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function ThreeTimes: IECPoint; override;
+    function Negate: IECPoint; override;
   end;
 
 type
-  TSecP384R1Curve = class sealed(TAbstractFpCurve, ISecP384R1Curve)
-
+  TSecP384R1Curve = class sealed(TAbstractFpCurve, IAbstractFpCurve, IECCurve,
+    ISecP384R1Curve)
+  strict private
+  const
+    SECP384R1_DEFAULT_COORDS = TECCurveConstants.COORD_JACOBIAN;
+    SECP384R1_FE_INTS = 12;
   strict private
-
   type
-    TSecP384R1LookupTable = class sealed(TAbstractECLookupTable,
+    TSecP384R1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable,
       ISecP384R1LookupTable)
-
     strict private
-    var
-      Fm_outer: ISecP384R1Curve;
-      Fm_table: TCryptoLibUInt32Array;
-      Fm_size: Int32;
-
-      function CreatePoint(const x, y: TCryptoLibUInt32Array): IECPoint;
-
-    strict protected
-
-      function GetSize: Int32; override;
-
+      FOuter: ISecP384R1Curve;
+      FTable: TCryptoLibUInt32Array;
+      FSize: Int32;
+      function CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
     public
-
-      constructor Create(const outer: ISecP384R1Curve;
-        const table: TCryptoLibUInt32Array; size: Int32);
-
-      function Lookup(index: Int32): IECPoint; override;
-      function LookupVar(index: Int32): IECPoint; override;
-
+      constructor Create(const AOuter: ISecP384R1Curve;
+        const ATable: TCryptoLibUInt32Array; ASize: Int32);
+      function GetSize: Int32; override;
+      function Lookup(AIndex: Int32): IECPoint; override;
+      function LookupVar(AIndex: Int32): IECPoint; override;
     end;
-
-  const
-    SECP384R1_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_JACOBIAN);
-    SECP384R1_FE_INTS = Int32(12);
-
+  class var
+    FQ: TBigInteger;
+    FSecP384R1AffineZs: TCryptoLibGenericArray<IECFieldElement>;
+  class procedure Boot; static;
+  class constructor Create;
   var
-    Fq: TBigInteger;
-
+    FInfinity: TSecP384R1Point;
   strict protected
-  var
-    Fm_infinity: ISecP384R1Point;
+    function GetQ: TBigInteger;
+  public
+    constructor Create;
+    destructor Destroy; override;
 
-    function GetQ: TBigInteger; virtual;
+    function CloneCurve: IECCurve; override;
     function GetFieldSize: Int32; override;
     function GetInfinity: IECPoint; 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();
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property Q: TBigInteger read GetQ;
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; override;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32): IECLookupTable; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; override;
+
+    class property Q: TBigInteger read FQ;
+    class property SecP384R1AffineZs: TCryptoLibGenericArray<IECFieldElement> read FSecP384R1AffineZs;
   end;
 
 implementation
 
 { TSecP384R1Field }
 
-class constructor TSecP384R1Field.SecP384R1Field;
+class procedure TSecP384R1Field.Boot;
 begin
-  TSecP384R1Field.Boot;
+  FP := TCryptoLibUInt32Array.Create($FFFFFFFF, $00000000, $00000000, $FFFFFFFF,
+    $FFFFFFFE, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF);
+  FPExt := TCryptoLibUInt32Array.Create($00000001, $FFFFFFFE, $00000000, $00000002,
+    $00000000, $FFFFFFFE, $00000000, $00000002, $00000001, $00000000, $00000000, $00000000,
+    $FFFFFFFE, $00000001, $00000000, $FFFFFFFE, $FFFFFFFD, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF);
+  FPExtInv := TCryptoLibUInt32Array.Create($FFFFFFFF, $00000001, $FFFFFFFF, $FFFFFFFD,
+    $FFFFFFFF, $00000001, $FFFFFFFF, $FFFFFFFD, $FFFFFFFE, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
+    $00000001, $FFFFFFFE, $FFFFFFFF, $00000001, $00000002);
 end;
 
-class function TSecP384R1Field.GetP: TCryptoLibUInt32Array;
+class constructor TSecP384R1Field.Create;
 begin
-  result := FP;
+  Boot;
 end;
 
-class procedure TSecP384R1Field.AddPInvTo(const z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.AddPInvTo(const AZ: TCryptoLibUInt32Array);
 var
-  c: Int64;
-begin
-  c := Int64(z[0]) + 1;
-  z[0] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  c := c + (Int64(z[1]) - 1);
-  z[1] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
-  begin
-    c := c + Int64(z[2]);
-    z[2] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-  end;
-  c := c + (Int64(z[3]) + 1);
-  z[3] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  c := c + (Int64(z[4]) + 1);
-  z[4] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
+  LC: Int64;
+begin
+  LC := Int64(AZ[0]) + 1;
+  AZ[0] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[1]) - 1);
+  AZ[1] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
   begin
-    TNat.IncAt(12, z, 5);
+    LC := LC + Int64(AZ[2]);
+    AZ[2] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
   end;
+  LC := LC + (Int64(AZ[3]) + 1);
+  AZ[3] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[4]) + 1);
+  AZ[4] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
+    TNat.IncAt(12, AZ, 5);
 end;
 
-class procedure TSecP384R1Field.Boot;
-begin
-  FP := TCryptoLibUInt32Array.Create($FFFFFFFF, $00000000, $00000000, $FFFFFFFF,
-    $FFFFFFFE, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF);
-  FPExt := TCryptoLibUInt32Array.Create($00000001, $FFFFFFFE, $00000000,
-    $00000002, $00000000, $FFFFFFFE, $00000000, $00000002, $00000001, $00000000,
-    $00000000, $00000000, $FFFFFFFE, $00000001, $00000000, $FFFFFFFE, $FFFFFFFD,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF);
-  FPExtInv := TCryptoLibUInt32Array.Create($FFFFFFFF, $00000001, $FFFFFFFF,
-    $FFFFFFFD, $FFFFFFFF, $00000001, $FFFFFFFF, $FFFFFFFD, $FFFFFFFE, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $00000001, $FFFFFFFE, $FFFFFFFF, $00000001,
-    $00000002);
-end;
-
-class procedure TSecP384R1Field.SubPInvFrom(const z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.SubPInvFrom(const AZ: TCryptoLibUInt32Array);
 var
-  c: Int64;
-begin
-  c := Int64(z[0]) - 1;
-  z[0] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  c := c + (Int64(z[1]) + 1);
-  z[1] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
-  begin
-    c := c + Int64(z[2]);
-    z[2] := UInt32(c);
-    c := TBitOperations.Asr64(c, 32);
-  end;
-  c := c + (Int64(z[3]) - 1);
-  z[3] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  c := c + (Int64(z[4]) - 1);
-  z[4] := UInt32(c);
-  c := TBitOperations.Asr64(c, 32);
-  if (c <> 0) then
+  LC: Int64;
+begin
+  LC := Int64(AZ[0]) - 1;
+  AZ[0] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[1]) + 1);
+  AZ[1] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
   begin
-    TNat.DecAt(12, z, 5);
+    LC := LC + Int64(AZ[2]);
+    AZ[2] := UInt32(LC);
+    LC := TBitOperations.Asr64(LC, 32);
   end;
+  LC := LC + (Int64(AZ[3]) - 1);
+  AZ[3] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  LC := LC + (Int64(AZ[4]) - 1);
+  AZ[4] := UInt32(LC);
+  LC := TBitOperations.Asr64(LC, 32);
+  if LC <> 0 then
+    TNat.DecAt(12, AZ, 5);
 end;
 
-class procedure TSecP384R1Field.Add(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.Add(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Add(12, x, y, z);
-  if ((c <> 0) or ((z[11] = P11) and (TNat.Gte(12, z, FP)))) then
-  begin
-    AddPInvTo(z);
-  end;
+  LC := TNat.Add(12, AX, AY, AZ);
+  if (LC <> 0) or ((AZ[11] = P11) and TNat.Gte(12, AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-class procedure TSecP384R1Field.AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.AddExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Add(24, xx, yy, zz);
-  if ((c <> 0) or ((zz[23] = PExt23) and (TNat.Gte(24, zz, FPExt)))) then
-  begin
-    if (TNat.AddTo(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
-    begin
-      TNat.IncAt(24, zz, System.Length(FPExtInv));
-    end;
-  end;
+  LC := TNat.Add(24, AXX, AYY, AZZ);
+  if (LC <> 0) or ((AZZ[23] = PExt23) and TNat.Gte(24, AZZ, FPExt)) then
+    if TNat.AddTo(System.Length(FPExtInv), FPExtInv, AZZ) <> 0 then
+      TNat.IncAt(24, AZZ, System.Length(FPExtInv));
 end;
 
-class procedure TSecP384R1Field.AddOne(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.AddOne(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Inc(12, x, z);
-  if ((c <> 0) or ((z[11] = P11) and (TNat.Gte(12, z, FP)))) then
-  begin
-    AddPInvTo(z);
-  end;
+  LC := TNat.Inc(12, AX, AZ);
+  if (LC <> 0) or ((AZ[11] = P11) and TNat.Gte(12, AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-class function TSecP384R1Field.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
+class function TSecP384R1Field.FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.FromBigInteger(384, x);
-  if ((z[11] = P11) and (TNat.Gte(12, z, FP))) then
-  begin
-    TNat.SubFrom(12, FP, z);
-  end;
-  result := z;
+  LZ := TNat.FromBigInteger(384, AX);
+  if (LZ[11] = P11) and TNat.Gte(12, LZ, FP) then
+    TNat.SubFrom(12, FP, LZ);
+  Result := LZ;
 end;
 
-class procedure TSecP384R1Field.Half(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.Half(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  if ((x[0] and 1) = 0) then
-  begin
-    TNat.ShiftDownBit(12, x, 0, z);
-  end
+  if (AX[0] and 1) = 0 then
+    TNat.ShiftDownBit(12, AX, 0, AZ)
   else
   begin
-    c := TNat.Add(12, x, FP, z);
-    TNat.ShiftDownBit(12, z, c);
+    LC := TNat.Add(12, AX, FP, AZ);
+    TNat.ShiftDownBit(12, AZ, LC);
   end;
 end;
 
-class procedure TSecP384R1Field.Reduce32(x: UInt32;
-  const z: TCryptoLibUInt32Array);
-var
-  cc, xx12: Int64;
+class procedure TSecP384R1Field.Inv(const AX, AZ: TCryptoLibUInt32Array);
 begin
-  cc := 0;
-
-  if (x <> 0) then
-  begin
-    xx12 := x;
-
-    cc := cc + (Int64(z[0]) + xx12);
-    z[0] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-    cc := cc + (Int64(z[1]) - xx12);
-    z[1] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-    if (cc <> 0) then
-    begin
-      cc := cc + Int64(z[2]);
-      z[2] := UInt32(cc);
-      cc := TBitOperations.Asr64(cc, 32);
-    end;
-    cc := cc + (Int64(z[3]) + xx12);
-    z[3] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-    cc := cc + (Int64(z[4]) + xx12);
-    z[4] := UInt32(cc);
-    cc := TBitOperations.Asr64(cc, 32);
-
-{$IFDEF DEBUG}
-    System.Assert((cc = 0) or (cc = 1));
-{$ENDIF DEBUG}
-  end;
-
-  if (((cc <> 0) and (TNat.IncAt(12, z, 5) <> 0)) or
-    ((z[11] = P11) and (TNat.Gte(12, z, FP)))) then
-  begin
-    AddPInvTo(z);
-  end;
+  TMod.CheckedModOddInverse(FP, AX, AZ);
 end;
 
-class procedure TSecP384R1Field.Reduce(const xx, z: TCryptoLibUInt32Array);
-const
-  n: Int64 = 1;
+class function TSecP384R1Field.IsZero(const AX: TCryptoLibUInt32Array): Int32;
 var
-  cc, xx16, xx17, xx18, xx19, xx20, xx21, xx22, xx23, t0, t1, t2, t3, t4, t5,
-    t6, t7: Int64;
-
-begin
-  xx16 := xx[16];
-  xx17 := xx[17];
-  xx18 := xx[18];
-  xx19 := xx[19];
-  xx20 := xx[20];
-  xx21 := xx[21];
-  xx22 := xx[22];
-  xx23 := xx[23];
-
-  t0 := Int64(xx[12]) + xx20 - n;
-  t1 := Int64(xx[13]) + xx22;
-  t2 := Int64(xx[14]) + xx22 + xx23;
-  t3 := Int64(xx[15]) + xx23;
-  t4 := xx17 + xx21;
-  t5 := xx21 - xx23;
-  t6 := xx22 - xx23;
-  t7 := t0 + t5;
-
-  cc := 0;
-  cc := cc + (Int64(xx[0]) + t7);
-  z[0] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[1]) + xx23 - t0 + t1);
-  z[1] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[2]) - xx21 - t1 + t2);
-  z[2] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[3]) - t2 + t3 + t7);
-  z[3] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[4]) + xx16 + xx21 + t1 - t3 + t7);
-  z[4] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[5]) - xx16 + t1 + t2 + t4);
-  z[5] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[6]) + xx18 - xx17 + t2 + t3);
-  z[6] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[7]) + xx16 + xx19 - xx18 + t3);
-  z[7] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[8]) + xx16 + xx17 + xx20 - xx19);
-  z[8] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[9]) + xx18 - xx20 + t4);
-  z[9] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[10]) + xx18 + xx19 - t5 + t6);
-  z[10] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (Int64(xx[11]) + xx19 + xx20 - t6);
-  z[11] := UInt32(cc);
-  cc := TBitOperations.Asr64(cc, 32);
-  cc := cc + (n);
-
-{$IFDEF DEBUG}
-  System.Assert(cc >= 0);
-{$ENDIF DEBUG}
-  Reduce32(UInt32(cc), z);
-end;
-
-class procedure TSecP384R1Field.Multiply(const x, y, z: TCryptoLibUInt32Array);
+  LD: UInt32;
+  LI: Int32;
+begin
+  LD := 0;
+  for LI := 0 to 11 do
+    LD := LD or AX[LI];
+  LD := (LD shr 1) or (LD and 1);
+  Result := TBitOperations.Asr32(Int32(LD) - 1, 31);
+end;
+
+class procedure TSecP384R1Field.Multiply(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LTT: TCryptoLibUInt32Array;
 begin
-  tt := TNat.Create(24);
-  TNat384.Mul(x, y, tt);
-  Reduce(tt, z);
+  LTT := TNat.Create(24);
+  TNat384.Mul(AX, AY, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP384R1Field.Negate(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array);
 begin
-  if (TNat.IsZero(12, x)) then
-  begin
-    TNat.Zero(12, z);
-  end
+  TNat384.Mul(AX, AY, ATT);
+  Reduce(ATT, AZ);
+end;
+
+class procedure TSecP384R1Field.Negate(const AX, AZ: TCryptoLibUInt32Array);
+begin
+  if IsZero(AX) <> 0 then
+    TNat.Sub(12, FP, FP, AZ)
   else
-  begin
-    TNat.Sub(12, FP, x, z);
-  end;
+    TNat.Sub(12, FP, AX, AZ);
 end;
 
-class procedure TSecP384R1Field.Square(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LBB: TCryptoLibByteArray;
+begin
+  System.SetLength(LBB, 12 * 4);
+  repeat
+    AR.NextBytes(LBB);
+    TPack.LE_To_UInt32(LBB, 0, AZ, 0, 12);
+  until TNat.LessThan(12, AZ, FP) <> 0;
+end;
+
+class procedure TSecP384R1Field.RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
 begin
-  tt := TNat.Create(24);
-  TNat384.Square(x, tt);
-  Reduce(tt, z);
+  repeat
+    Random(AR, AZ);
+  until IsZero(AZ) <> 0;
 end;
 
-class procedure TSecP384R1Field.SquareN(const x: TCryptoLibUInt32Array;
-  n: Int32; const z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.Reduce(const AXX, AZ: TCryptoLibUInt32Array);
+var
+  LXX16, LXX17, LXX18, LXX19, LXX20, LXX21, LXX22, LXX23: Int64;
+  LT0, LT1, LT2, LT3, LT4, LT5, LT6, LT7: Int64;
+  LCc: Int64;
+  LN: Int64;
+begin
+  LN := 1;
+  LXX16 := Int64(UInt32(AXX[16]));
+  LXX17 := Int64(UInt32(AXX[17]));
+  LXX18 := Int64(UInt32(AXX[18]));
+  LXX19 := Int64(UInt32(AXX[19]));
+  LXX20 := Int64(UInt32(AXX[20]));
+  LXX21 := Int64(UInt32(AXX[21]));
+  LXX22 := Int64(UInt32(AXX[22]));
+  LXX23 := Int64(UInt32(AXX[23]));
+
+  LT0 := Int64(AXX[12]) + LXX20 - LN;
+  LT1 := Int64(AXX[13]) + LXX22;
+  LT2 := Int64(AXX[14]) + LXX22 + LXX23;
+  LT3 := Int64(AXX[15]) + LXX23;
+  LT4 := LXX17 + LXX21;
+  LT5 := LXX21 - LXX23;
+  LT6 := LXX22 - LXX23;
+  LT7 := LT0 + LT5;
+
+  LCc := 0;
+  LCc := LCc + (Int64(AXX[0]) + LT7);
+  AZ[0] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[1]) + LXX23 - LT0 + LT1);
+  AZ[1] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[2]) - LXX21 - LT1 + LT2);
+  AZ[2] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[3]) - LT2 + LT3 + LT7);
+  AZ[3] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[4]) + LXX16 + LXX21 + LT1 - LT3 + LT7);
+  AZ[4] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[5]) - LXX16 + LT1 + LT2 + LT4);
+  AZ[5] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[6]) + LXX18 - LXX17 + LT2 + LT3);
+  AZ[6] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[7]) + LXX16 + LXX19 - LXX18 + LT3);
+  AZ[7] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[8]) + LXX16 + LXX17 + LXX20 - LXX19);
+  AZ[8] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[9]) + LXX18 - LXX20 + LT4);
+  AZ[9] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[10]) + LXX18 + LXX19 - LT5 + LT6);
+  AZ[10] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + (Int64(AXX[11]) + LXX19 + LXX20 - LT6);
+  AZ[11] := UInt32(LCc);
+  LCc := TBitOperations.Asr64(LCc, 32);
+  LCc := LCc + LN;
+
+  {$IFDEF DEBUG}
+  Assert(LCc >= 0);
+  {$ENDIF DEBUG}
+
+  Reduce32(UInt32(LCc), AZ);
+end;
+
+class procedure TSecP384R1Field.Reduce32(AX: UInt32; const AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LCc: Int64;
+  LXX12: Int64;
 begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  tt := TNat.Create(24);
-  TNat384.Square(x, tt);
-  Reduce(tt, z);
+  LCc := 0;
 
-  System.Dec(n);
-  while (n > 0) do
+  if AX <> 0 then
   begin
-    TNat384.Square(z, tt);
-    Reduce(tt, z);
-    System.Dec(n);
+    LXX12 := Int64(AX);
+
+    LCc := LCc + (Int64(AZ[0]) + LXX12);
+    AZ[0] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+    LCc := LCc + (Int64(AZ[1]) - LXX12);
+    AZ[1] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+    if LCc <> 0 then
+    begin
+      LCc := LCc + Int64(AZ[2]);
+      AZ[2] := UInt32(LCc);
+      LCc := TBitOperations.Asr64(LCc, 32);
+    end;
+    LCc := LCc + (Int64(AZ[3]) + LXX12);
+    AZ[3] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+    LCc := LCc + (Int64(AZ[4]) + LXX12);
+    AZ[4] := UInt32(LCc);
+    LCc := TBitOperations.Asr64(LCc, 32);
+
+    {$IFDEF DEBUG}
+    Assert((LCc = 0) or (LCc = 1));
+    {$ENDIF DEBUG}
   end;
+
+  if ((LCc <> 0) and (TNat.IncAt(12, AZ, 5) <> 0)) or
+    ((AZ[11] = P11) and TNat.Gte(12, AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-class procedure TSecP384R1Field.Subtract(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP384R1Field.Square(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: Int32;
+  LTT: TCryptoLibUInt32Array;
 begin
-  c := TNat.Sub(12, x, y, z);
-  if (c <> 0) then
-  begin
-    SubPInvFrom(z);
-  end;
+  LTT := TNat.Create(24);
+  TNat384.Square(AX, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP384R1Field.SubtractExt(const xx, yy,
-  zz: TCryptoLibUInt32Array);
-var
-  c: Int32;
+class procedure TSecP384R1Field.Square(const AX, AZ, ATT: TCryptoLibUInt32Array);
 begin
-  c := TNat.Sub(24, xx, yy, zz);
-  if (c <> 0) then
+  TNat384.Square(AX, ATT);
+  Reduce(ATT, AZ);
+end;
+
+class procedure TSecP384R1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ: TCryptoLibUInt32Array);
+var
+  LTT: TCryptoLibUInt32Array;
+begin
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  LTT := TNat.Create(24);
+  TNat384.Square(AX, LTT);
+  Reduce(LTT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    if (TNat.SubFrom(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
-    begin
-      TNat.DecAt(24, zz, System.Length(FPExtInv));
-    end;
+    TNat384.Square(AZ, LTT);
+    Reduce(LTT, AZ);
+    Dec(AN);
   end;
 end;
 
-class procedure TSecP384R1Field.Twice(const x, z: TCryptoLibUInt32Array);
-var
-  c: UInt32;
+class procedure TSecP384R1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ, ATT: TCryptoLibUInt32Array);
 begin
-  c := TNat.ShiftUpBit(12, x, 0, z);
-  if ((c <> 0) or ((z[11] = P11) and (TNat.Gte(12, z, FP)))) then
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  TNat384.Square(AX, ATT);
+  Reduce(ATT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    AddPInvTo(z);
+    TNat384.Square(AZ, ATT);
+    Reduce(ATT, AZ);
+    Dec(AN);
   end;
 end;
 
-{ TSecP384R1FieldElement }
-
-class function TSecP384R1FieldElement.GetQ: TBigInteger;
+class procedure TSecP384R1Field.Subtract(const AX, AY, AZ: TCryptoLibUInt32Array);
+var
+  LC: Int32;
 begin
-  result := TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF')
-    );
+  LC := TNat.Sub(12, AX, AY, AZ);
+  if LC <> 0 then
+    SubPInvFrom(AZ);
 end;
 
-function TSecP384R1FieldElement.GetX: TCryptoLibUInt32Array;
+class procedure TSecP384R1Field.SubtractExt(const AXX, AYY, AZZ: TCryptoLibUInt32Array);
+var
+  LC: Int32;
 begin
-  result := Fx;
+  LC := TNat.Sub(24, AXX, AYY, AZZ);
+  if LC <> 0 then
+    if TNat.SubFrom(System.Length(FPExtInv), FPExtInv, AZZ) <> 0 then
+      TNat.DecAt(24, AZZ, System.Length(FPExtInv));
 end;
 
-constructor TSecP384R1FieldElement.Create;
+class procedure TSecP384R1Field.Twice(const AX, AZ: TCryptoLibUInt32Array);
+var
+  LC: UInt32;
 begin
-  Inherited Create();
-  Fx := TNat.Create(12);
+  LC := TNat.ShiftUpBit(12, AX, 0, AZ);
+  if (LC <> 0) or ((AZ[11] = P11) and TNat.Gte(12, AZ, FP)) then
+    AddPInvTo(AZ);
 end;
 
-constructor TSecP384R1FieldElement.Create(const x: TBigInteger);
+{ TSecP384R1FieldElement }
+
+class procedure TSecP384R1FieldElement.Boot;
 begin
-  if ((not(x.IsInitialized)) or (x.SignValue < 0) or (x.CompareTo(Q) >= 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt
-      (@SInvalidValueForSecP384R1FieldElement, ['x']);
-  end;
-  Inherited Create();
-  Fx := TSecP384R1Field.FromBigInteger(x);
+  FQ := TBigInteger.Create(1, THex.Decode('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF'));
 end;
 
-constructor TSecP384R1FieldElement.Create(const x: TCryptoLibUInt32Array);
+class constructor TSecP384R1FieldElement.Create;
 begin
-  Inherited Create();
-  Fx := x;
+  Boot;
 end;
 
-function TSecP384R1FieldElement.GetFieldName: string;
+class function TSecP384R1FieldElement.GetQ: TBigInteger;
 begin
-  result := 'SecP384R1Field';
+  Result := FQ;
 end;
 
-function TSecP384R1FieldElement.GetFieldSize: Int32;
+constructor TSecP384R1FieldElement.Create(const AX: TBigInteger);
 begin
-  result := Q.BitLength;
+  Inherited Create;
+  if (not AX.IsInitialized) or (AX.SignValue < 0) or (AX.CompareTo(FQ) >= 0) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidSecP384R1FieldElement);
+  FX := TSecP384R1Field.FromBigInteger(AX);
 end;
 
-function TSecP384R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+constructor TSecP384R1FieldElement.Create();
 begin
-  result := Q.GetHashCode() xor TArrayUtilities.GetArrayHashCode(Fx, 0, 12);
+  Inherited Create;
+  FX := TNat.Create(12);
 end;
 
-function TSecP384R1FieldElement.GetIsOne: Boolean;
+constructor TSecP384R1FieldElement.Create(const AX: TCryptoLibUInt32Array);
 begin
-  result := TNat.IsOne(12, Fx);
+  Inherited Create;
+  FX := AX;
 end;
 
-function TSecP384R1FieldElement.GetIsZero: Boolean;
+function TSecP384R1FieldElement.GetX: TCryptoLibUInt32Array;
 begin
-  result := TNat.IsZero(12, Fx);
+  Result := FX;
 end;
 
-function TSecP384R1FieldElement.Sqrt: IECFieldElement;
-var
-  x1, t1, t2, t3, t4, r: TCryptoLibUInt32Array;
+function TSecP384R1FieldElement.GetFieldName: String;
 begin
-  // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30
-  x1 := Fx;
-  if ((TNat.IsZero(12, x1)) or (TNat.IsOne(12, x1))) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  t1 := TNat.Create(12);
-  t2 := TNat.Create(12);
-  t3 := TNat.Create(12);
-  t4 := TNat.Create(12);
-
-  TSecP384R1Field.Square(x1, t1);
-  TSecP384R1Field.Multiply(t1, x1, t1);
-
-  TSecP384R1Field.SquareN(t1, 2, t2);
-  TSecP384R1Field.Multiply(t2, t1, t2);
-
-  TSecP384R1Field.Square(t2, t2);
-  TSecP384R1Field.Multiply(t2, x1, t2);
-
-  TSecP384R1Field.SquareN(t2, 5, t3);
-  TSecP384R1Field.Multiply(t3, t2, t3);
-
-  TSecP384R1Field.SquareN(t3, 5, t4);
-  TSecP384R1Field.Multiply(t4, t2, t4);
-
-  TSecP384R1Field.SquareN(t4, 15, t2);
-  TSecP384R1Field.Multiply(t2, t4, t2);
-
-  TSecP384R1Field.SquareN(t2, 2, t3);
-  TSecP384R1Field.Multiply(t1, t3, t1);
-
-  TSecP384R1Field.SquareN(t3, 28, t3);
-  TSecP384R1Field.Multiply(t2, t3, t2);
-
-  TSecP384R1Field.SquareN(t2, 60, t3);
-  TSecP384R1Field.Multiply(t3, t2, t3);
-
-  r := t2;
-
-  TSecP384R1Field.SquareN(t3, 120, r);
-  TSecP384R1Field.Multiply(r, t3, r);
-
-  TSecP384R1Field.SquareN(r, 15, r);
-  TSecP384R1Field.Multiply(r, t4, r);
-
-  TSecP384R1Field.SquareN(r, 33, r);
-  TSecP384R1Field.Multiply(r, t1, r);
-
-  TSecP384R1Field.SquareN(r, 64, r);
-  TSecP384R1Field.Multiply(r, x1, r);
+  Result := 'SecP384R1Field';
+end;
 
-  TSecP384R1Field.SquareN(r, 30, t1);
-  TSecP384R1Field.Square(t1, t2);
+function TSecP384R1FieldElement.GetFieldSize: Int32;
+begin
+  Result := FQ.BitLength;
+end;
 
-  if TNat.Eq(12, x1, t2) then
-  begin
-    result := TSecP384R1FieldElement.Create(t1);
-  end
-  else
-  begin
-    result := Nil;
-  end;
+function TSecP384R1FieldElement.GetIsOne: Boolean;
+begin
+  Result := TNat.IsOne(12, FX);
 end;
 
-function TSecP384R1FieldElement.TestBitZero: Boolean;
+function TSecP384R1FieldElement.GetIsZero: Boolean;
 begin
-  result := TNat.GetBit(Fx, 0) = 1;
+  Result := TNat.IsZero(12, FX);
 end;
 
 function TSecP384R1FieldElement.ToBigInteger: TBigInteger;
 begin
-  result := TNat.ToBigInteger(12, Fx);
+  Result := TNat.ToBigInteger(12, FX);
+end;
+
+function TSecP384R1FieldElement.TestBitZero: Boolean;
+begin
+  Result := TNat.GetBit(FX, 0) = 1;
 end;
 
-function TSecP384R1FieldElement.Add(const b: IECFieldElement): IECFieldElement;
+function TSecP384R1FieldElement.Add(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TSecP384R1Field.Add(Fx, (b as ISecP384R1FieldElement).x, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Add(FX, (AB as ISecP384R1FieldElement).X, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
 function TSecP384R1FieldElement.AddOne: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TSecP384R1Field.AddOne(Fx, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.AddOne(FX, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
-function TSecP384R1FieldElement.Subtract(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP384R1FieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TSecP384R1Field.Subtract(Fx, (b as ISecP384R1FieldElement).x, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Subtract(FX, (AB as ISecP384R1FieldElement).X, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
-function TSecP384R1FieldElement.Multiply(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP384R1FieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TSecP384R1Field.Multiply(Fx, (b as ISecP384R1FieldElement).x, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Multiply(FX, (AB as ISecP384R1FieldElement).X, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
-function TSecP384R1FieldElement.Divide(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP384R1FieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TMod.CheckedModOddInverse(TSecP384R1Field.P, (b as ISecP384R1FieldElement).x, z);
-  TSecP384R1Field.Multiply(z, Fx, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Inv((AB as ISecP384R1FieldElement).X, LZ);
+  TSecP384R1Field.Multiply(LZ, FX, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
 function TSecP384R1FieldElement.Negate: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TSecP384R1Field.Negate(Fx, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Negate(FX, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
 function TSecP384R1FieldElement.Square: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TSecP384R1Field.Square(Fx, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Square(FX, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
 function TSecP384R1FieldElement.Invert: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(12);
-  TMod.CheckedModOddInverse(TSecP384R1Field.P, Fx, z);
-  result := TSecP384R1FieldElement.Create(z);
+  LZ := TNat.Create(12);
+  TSecP384R1Field.Inv(FX, LZ);
+  Result := TSecP384R1FieldElement.Create(LZ);
 end;
 
-function TSecP384R1FieldElement.Equals(const AOther: ISecP384R1FieldElement): Boolean;
+function TSecP384R1FieldElement.Sqrt: IECFieldElement;
+var
+  LX1, LTT0, LT1, LT2, LT3, LT4: TCryptoLibUInt32Array;
+  LR: TCryptoLibUInt32Array;
 begin
-  if (Self as ISecP384R1FieldElement) = AOther then
-    Exit(True);
-  if AOther = nil then
-    Exit(False);
-  Result := TNat.Eq(12, Fx, AOther.x);
+  LX1 := FX;
+  if TNat.IsZero(12, LX1) or TNat.IsOne(12, LX1) then
+    Exit(Self as IECFieldElement);
+
+  LTT0 := TNat.Create(24);
+  LT1 := TNat.Create(12);
+  LT2 := TNat.Create(12);
+  LT3 := TNat.Create(12);
+  LT4 := TNat.Create(12);
+
+  TSecP384R1Field.Square(LX1, LT1, LTT0);
+  TSecP384R1Field.Multiply(LT1, LX1, LT1, LTT0);
+
+  TSecP384R1Field.SquareN(LT1, 2, LT2, LTT0);
+  TSecP384R1Field.Multiply(LT2, LT1, LT2, LTT0);
+
+  TSecP384R1Field.Square(LT2, LT2, LTT0);
+  TSecP384R1Field.Multiply(LT2, LX1, LT2, LTT0);
+
+  TSecP384R1Field.SquareN(LT2, 5, LT3, LTT0);
+  TSecP384R1Field.Multiply(LT3, LT2, LT3, LTT0);
+
+  TSecP384R1Field.SquareN(LT3, 5, LT4, LTT0);
+  TSecP384R1Field.Multiply(LT4, LT2, LT4, LTT0);
+
+  TSecP384R1Field.SquareN(LT4, 15, LT2, LTT0);
+  TSecP384R1Field.Multiply(LT2, LT4, LT2, LTT0);
+
+  TSecP384R1Field.SquareN(LT2, 2, LT3, LTT0);
+  TSecP384R1Field.Multiply(LT1, LT3, LT1, LTT0);
+
+  TSecP384R1Field.SquareN(LT3, 28, LT3, LTT0);
+  TSecP384R1Field.Multiply(LT2, LT3, LT2, LTT0);
+
+  TSecP384R1Field.SquareN(LT2, 60, LT3, LTT0);
+  TSecP384R1Field.Multiply(LT3, LT2, LT3, LTT0);
+
+  LR := LT2;
+
+  TSecP384R1Field.SquareN(LT3, 120, LR, LTT0);
+  TSecP384R1Field.Multiply(LR, LT3, LR, LTT0);
+
+  TSecP384R1Field.SquareN(LR, 15, LR, LTT0);
+  TSecP384R1Field.Multiply(LR, LT4, LR, LTT0);
+
+  TSecP384R1Field.SquareN(LR, 33, LR, LTT0);
+  TSecP384R1Field.Multiply(LR, LT1, LR, LTT0);
+
+  TSecP384R1Field.SquareN(LR, 64, LR, LTT0);
+  TSecP384R1Field.Multiply(LR, LX1, LR, LTT0);
+
+  TSecP384R1Field.SquareN(LR, 30, LT1, LTT0);
+  TSecP384R1Field.Square(LT1, LT2, LTT0);
+
+  if TNat.Eq(12, LX1, LT2) then
+    Result := TSecP384R1FieldElement.Create(LT1)
+  else
+    Result := nil;
 end;
 
 function TSecP384R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
-var
-  LSec: ISecP384R1FieldElement;
 begin
+  if (Self as IECFieldElement) = AOther then
+    Exit(True);
   if AOther = nil then
     Exit(False);
-  if Supports(AOther, ISecP384R1FieldElement, LSec) then
-    Result := Equals(LSec)
-  else
-    Result := ToBigInteger.Equals(AOther.ToBigInteger);
+  Result := TNat.Eq(12, FX, (AOther as ISecP384R1FieldElement).X);
+end;
+
+function TSecP384R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
+begin
+  Result := FQ.GetHashCode() xor TArrayUtilities.GetArrayHashCode(FX, 0, 12);
 end;
 
 { TSecP384R1Point }
 
-constructor TSecP384R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
+constructor TSecP384R1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
 begin
-  Create(curve, x, y, false);
+  Inherited Create(ACurve, AX, AY);
 end;
 
-constructor TSecP384R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
+constructor TSecP384R1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
 begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SOneOfECFieldElementIsNil);
-  end;
+  Inherited Create(ACurve, AX, AY, AZs);
 end;
 
-constructor TSecP384R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
+function TSecP384R1Point.Detach: IECPoint;
 begin
-  Inherited Create(curve, x, y, zs, withCompression);
+  Result := TSecP384R1Point.Create(nil, AffineXCoord, AffineYCoord);
 end;
 
-function TSecP384R1Point.Add(const b: IECPoint): IECPoint;
+function TSecP384R1Point.Add(const AB: IECPoint): IECPoint;
 var
-  Lcurve: IECCurve;
-  x1, Y1, X2, Y2, Z1, Z2, X3, Y3, Z3: ISecP384R1FieldElement;
-  c: UInt32;
-  tt1, tt2, t3, t4, U2, S2, U1, S1, H, r, HSquared, G, V: TCryptoLibUInt32Array;
-  Z1IsOne, Z2IsOne: Boolean;
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-begin
-  if (IsInfinity) then
+  LCurve: IECCurve;
+  LX1, LY1, LX2, LY2, LZ1, LZ2: ISecP384R1FieldElement;
+  LTT0, LTT1, LTT2: TCryptoLibUInt32Array;
+  LT3, LT4: TCryptoLibUInt32Array;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  LU2, LS2, LU1, LS1: TCryptoLibUInt32Array;
+  LH, LR, LHSquared, LG, LV: TCryptoLibUInt32Array;
+  LC: UInt32;
+  LX3, LY3, LZ3: ISecP384R1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Self as IECPoint);
+  if (Self as IECPoint) = AB then
+    Exit(Twice());
+
+  LCurve := Curve;
+  LX1 := RawXCoord as ISecP384R1FieldElement;
+  LY1 := RawYCoord as ISecP384R1FieldElement;
+  LX2 := AB.RawXCoord as ISecP384R1FieldElement;
+  LY2 := AB.RawYCoord as ISecP384R1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP384R1FieldElement;
+  LZ2 := AB.GetZCoord(0) as ISecP384R1FieldElement;
+
+  LTT0 := TNat.Create(24);
+  LTT1 := TNat.Create(24);
+  LTT2 := TNat.Create(24);
+  LT3 := TNat.Create(12);
+  LT4 := TNat.Create(12);
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
   begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
+    LU2 := LX2.X;
+    LS2 := LY2.X;
+  end
+  else
   begin
-    result := Self as IECPoint;
-    Exit;
+    LS2 := LT3;
+    TSecP384R1Field.Square(LZ1.X, LS2, LTT0);
+    LU2 := LTT2;
+    TSecP384R1Field.Multiply(LS2, LX2.X, LU2, LTT0);
+    TSecP384R1Field.Multiply(LS2, LZ1.X, LS2, LTT0);
+    TSecP384R1Field.Multiply(LS2, LY2.X, LS2, LTT0);
   end;
-  if ((Self as IECPoint) = b) then
+
+  LZ2IsOne := LZ2.IsOne;
+  if LZ2IsOne then
+  begin
+    LU1 := LX1.X;
+    LS1 := LY1.X;
+  end
+  else
   begin
-    result := Twice();
-    Exit;
+    LS1 := LT4;
+    TSecP384R1Field.Square(LZ2.X, LS1, LTT0);
+    LU1 := LTT1;
+    TSecP384R1Field.Multiply(LS1, LX1.X, LU1, LTT0);
+    TSecP384R1Field.Multiply(LS1, LZ2.X, LS1, LTT0);
+    TSecP384R1Field.Multiply(LS1, LY1.X, LS1, LTT0);
   end;
 
-  Lcurve := curve;
-
-  x1 := RawXCoord as ISecP384R1FieldElement;
-  Y1 := RawYCoord as ISecP384R1FieldElement;
-  X2 := b.RawXCoord as ISecP384R1FieldElement;
-  Y2 := b.RawYCoord as ISecP384R1FieldElement;
+  LH := TNat.Create(12);
+  TSecP384R1Field.Subtract(LU1, LU2, LH);
 
-  Z1 := RawZCoords[0] as ISecP384R1FieldElement;
-  Z2 := b.RawZCoords[0] as ISecP384R1FieldElement;
+  LR := TNat.Create(12);
+  TSecP384R1Field.Subtract(LS1, LS2, LR);
 
-  tt1 := TNat.Create(24);
-  tt2 := TNat.Create(24);
-  t3 := TNat.Create(12);
-  t4 := TNat.Create(12);
+  if TNat.IsZero(12, LH) then
+  begin
+    if TNat.IsZero(12, LR) then
+      Exit(Twice());
+    Exit(LCurve.Infinity);
+  end;
 
-  Z1IsOne := Z1.IsOne;
+  LHSquared := LT3;
+  TSecP384R1Field.Square(LH, LHSquared, LTT0);
 
-  if (Z1IsOne) then
-  begin
-    U2 := X2.x;
-    S2 := Y2.x;
-  end
-  else
-  begin
-    S2 := t3;
-    TSecP384R1Field.Square(Z1.x, S2);
+  LG := TNat.Create(12);
+  TSecP384R1Field.Multiply(LHSquared, LH, LG, LTT0);
 
-    U2 := tt2;
-    TSecP384R1Field.Multiply(S2, X2.x, U2);
+  LV := LT3;
+  TSecP384R1Field.Multiply(LHSquared, LU1, LV, LTT0);
 
-    TSecP384R1Field.Multiply(S2, Z1.x, S2);
-    TSecP384R1Field.Multiply(S2, Y2.x, S2);
-  end;
+  TSecP384R1Field.Negate(LG, LG);
+  TNat384.Mul(LS1, LG, LTT1);
 
-  Z2IsOne := Z2.IsOne;
-  if (Z2IsOne) then
-  begin
-    U1 := x1.x;
-    S1 := Y1.x;
-  end
-  else
-  begin
-    S1 := t4;
-    TSecP384R1Field.Square(Z2.x, S1);
+  LC := TNat.AddBothTo(12, LV, LV, LG);
+  TSecP384R1Field.Reduce32(LC, LG);
 
-    U1 := tt1;
-    TSecP384R1Field.Multiply(S1, x1.x, U1);
+  LX3 := TSecP384R1FieldElement.Create(LT4);
+  TSecP384R1Field.Square(LR, LX3.X, LTT0);
+  TSecP384R1Field.Subtract(LX3.X, LG, LX3.X);
 
-    TSecP384R1Field.Multiply(S1, Z2.x, S1);
-    TSecP384R1Field.Multiply(S1, Y1.x, S1);
-  end;
+  LY3 := TSecP384R1FieldElement.Create(LG);
+  TSecP384R1Field.Subtract(LV, LX3.X, LY3.X);
+  TNat384.Mul(LY3.X, LR, LTT2);
+  TSecP384R1Field.AddExt(LTT1, LTT2, LTT1);
+  TSecP384R1Field.Reduce(LTT1, LY3.X);
 
-  H := TNat.Create(12);
-  TSecP384R1Field.Subtract(U1, U2, H);
+  LZ3 := TSecP384R1FieldElement.Create(LH);
+  if not LZ1IsOne then
+    TSecP384R1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
+  if not LZ2IsOne then
+    TSecP384R1Field.Multiply(LZ3.X, LZ2.X, LZ3.X, LTT0);
 
-  r := TNat.Create(12);
-  TSecP384R1Field.Subtract(S1, S2, r);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP384R1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
 
-  // Check if b = Self or b = -Self
-  if (TNat.IsZero(12, H)) then
+function TSecP384R1Point.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LY1, LX1, LZ1: ISecP384R1FieldElement;
+  LTT0: TCryptoLibUInt32Array;
+  LY1Squared, LT, LT1, LT2: TCryptoLibUInt32Array;
+  LZ1Squared, LM, LS: TCryptoLibUInt32Array;
+  LZ1IsOne: Boolean;
+  LC: UInt32;
+  LX3, LY3, LZ3: ISecP384R1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(Self as IECPoint);
+
+  LCurve := Curve;
+  LY1 := RawYCoord as ISecP384R1FieldElement;
+  if LY1.IsZero then
+    Exit(LCurve.Infinity);
+
+  LX1 := RawXCoord as ISecP384R1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP384R1FieldElement;
+
+  LTT0 := TNat.Create(24);
+  LT1 := TNat.Create(12);
+  LT2 := TNat.Create(12);
+
+  LY1Squared := TNat.Create(12);
+  TSecP384R1Field.Square(LY1.X, LY1Squared, LTT0);
+
+  LT := TNat.Create(12);
+  TSecP384R1Field.Square(LY1Squared, LT, LTT0);
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
+    LZ1Squared := LZ1.X
+  else
   begin
-    if (TNat.IsZero(12, r)) then
-    begin
-      // Self = b, i.e. Self must be doubled
-      result := Twice();
-      Exit;
-    end;
-
-    // Self = -b, i.e. the result is the point at infinity
-    result := Lcurve.Infinity;
-    Exit;
+    LZ1Squared := LT2;
+    TSecP384R1Field.Square(LZ1.X, LZ1Squared, LTT0);
   end;
 
-  HSquared := t3;
-  TSecP384R1Field.Square(H, HSquared);
+  TSecP384R1Field.Subtract(LX1.X, LZ1Squared, LT1);
 
-  G := TNat.Create(12);
-  TSecP384R1Field.Multiply(HSquared, H, G);
+  LM := LT2;
+  TSecP384R1Field.Add(LX1.X, LZ1Squared, LM);
+  TSecP384R1Field.Multiply(LM, LT1, LM, LTT0);
+  LC := TNat.AddBothTo(12, LM, LM, LM);
+  TSecP384R1Field.Reduce32(LC, LM);
 
-  V := t3;
-  TSecP384R1Field.Multiply(HSquared, U1, V);
+  LS := LY1Squared;
+  TSecP384R1Field.Multiply(LY1Squared, LX1.X, LS, LTT0);
+  LC := TNat.ShiftUpBits(12, LS, 2, 0, LS);
+  TSecP384R1Field.Reduce32(LC, LS);
 
-  TSecP384R1Field.Negate(G, G);
-  TNat384.Mul(S1, G, tt1);
+  LC := TNat.ShiftUpBits(12, LT, 3, 0, LT1);
+  TSecP384R1Field.Reduce32(LC, LT1);
 
-  c := TNat.AddBothTo(12, V, V, G);
-  TSecP384R1Field.Reduce32(c, G);
+  LX3 := TSecP384R1FieldElement.Create(LT);
+  TSecP384R1Field.Square(LM, LX3.X, LTT0);
+  TSecP384R1Field.Subtract(LX3.X, LS, LX3.X);
+  TSecP384R1Field.Subtract(LX3.X, LS, LX3.X);
 
-  X3 := TSecP384R1FieldElement.Create(t4);
-  TSecP384R1Field.Square(r, X3.x);
-  TSecP384R1Field.Subtract(X3.x, G, X3.x);
+  LY3 := TSecP384R1FieldElement.Create(LS);
+  TSecP384R1Field.Subtract(LS, LX3.X, LY3.X);
+  TSecP384R1Field.Multiply(LY3.X, LM, LY3.X, LTT0);
+  TSecP384R1Field.Subtract(LY3.X, LT1, LY3.X);
 
-  Y3 := TSecP384R1FieldElement.Create(G);
-  TSecP384R1Field.Subtract(V, X3.x, Y3.x);
-  TNat384.Mul(Y3.x, r, tt2);
-  TSecP384R1Field.AddExt(tt1, tt2, tt1);
-  TSecP384R1Field.Reduce(tt1, Y3.x);
+  LZ3 := TSecP384R1FieldElement.Create(LM);
+  TSecP384R1Field.Twice(LY1.X, LZ3.X);
+  if not LZ1IsOne then
+    TSecP384R1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
 
-  Z3 := TSecP384R1FieldElement.Create(H);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP384R1Field.Multiply(Z3.x, Z1.x, Z3.x);
-  end;
-  if (not(Z2IsOne)) then
-  begin
-    TSecP384R1Field.Multiply(Z3.x, Z2.x, Z3.x);
-  end;
-
-  zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP384R1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
 
-  result := TSecP384R1Point.Create(Lcurve, X3, Y3, zs, IsCompressed)
-    as IECPoint;
+function TSecP384R1Point.TwicePlus(const AB: IECPoint): IECPoint;
+begin
+  if (Self as IECPoint) = AB then
+    Exit(ThreeTimes());
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Twice());
+  if RawYCoord.IsZero then
+    Exit(AB);
+  Result := Twice().Add(AB);
 end;
 
-function TSecP384R1Point.Detach: IECPoint;
+function TSecP384R1Point.ThreeTimes: IECPoint;
 begin
-  result := TSecP384R1Point.Create(Nil, AffineXCoord, AffineYCoord) as IECPoint;
+  if IsInfinity or RawYCoord.IsZero then
+    Exit(Self as IECPoint);
+  Result := Twice().Add(Self as IECPoint);
 end;
 
 function TSecP384R1Point.Negate: IECPoint;
 begin
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  if IsInfinity then
+    Exit(Self as IECPoint);
+  Result := TSecP384R1Point.Create(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords);
+end;
+
+{ TSecP384R1Curve.TSecP384R1LookupTable }
 
-  result := TSecP384R1Point.Create(curve, RawXCoord, RawYCoord.Negate(),
-    RawZCoords, IsCompressed) as IECPoint;
+constructor TSecP384R1Curve.TSecP384R1LookupTable.Create(const AOuter: ISecP384R1Curve;
+  const ATable: TCryptoLibUInt32Array; ASize: Int32);
+begin
+  Inherited Create;
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
 end;
 
-function TSecP384R1Point.ThreeTimes: IECPoint;
+function TSecP384R1Curve.TSecP384R1LookupTable.GetSize: Int32;
 begin
-  if ((IsInfinity) or (RawYCoord.IsZero)) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  Result := FSize;
+end;
 
-  // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
-  result := Twice().Add(Self as IECPoint);
+function TSecP384R1Curve.TSecP384R1LookupTable.CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
+begin
+  Result := FOuter.CreateRawPoint(TSecP384R1FieldElement.Create(AX) as IECFieldElement,
+    TSecP384R1FieldElement.Create(AY) as IECFieldElement, TSecP384R1Curve.SecP384R1AffineZs);
 end;
 
-function TSecP384R1Point.Twice: IECPoint;
+function TSecP384R1Curve.TSecP384R1LookupTable.Lookup(AIndex: Int32): IECPoint;
 var
-  Lcurve: IECCurve;
-  Y1, x1, Z1, X3, Y3, Z3: ISecP384R1FieldElement;
-  c: UInt32;
-  Y1Squared, Z1Squared, T, M, S, t1, t2: TCryptoLibUInt32Array;
-  Z1IsOne: Boolean;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LI, LJ: Int32;
+  LMask: UInt32;
 begin
+  LX := TNat.Create(SECP384R1_FE_INTS);
+  LY := TNat.Create(SECP384R1_FE_INTS);
+  LPos := 0;
 
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  Lcurve := curve;
-
-  Y1 := RawYCoord as ISecP384R1FieldElement;
-  if (Y1.IsZero) then
-  begin
-    result := Lcurve.Infinity;
-    Exit;
-  end;
-
-  x1 := RawXCoord as ISecP384R1FieldElement;
-  Z1 := RawZCoords[0] as ISecP384R1FieldElement;
-
-  t1 := TNat.Create(12);
-  t2 := TNat.Create(12);
-  Y1Squared := TNat.Create(12);
-  TSecP384R1Field.Square(Y1.x, Y1Squared);
-
-  T := TNat.Create(12);
-  TSecP384R1Field.Square(Y1Squared, T);
-
-  Z1IsOne := Z1.IsOne;
-
-  Z1Squared := Z1.x;
-  if (not(Z1IsOne)) then
+  for LI := 0 to System.Pred(FSize) do
   begin
-    Z1Squared := t2;
-    TSecP384R1Field.Square(Z1.x, Z1Squared);
-  end;
+    LMask := UInt32(TBitOperations.Asr32(((LI xor AIndex) - 1), 31));
 
-  TSecP384R1Field.Subtract(x1.x, Z1Squared, t1);
-
-  M := t2;
-  TSecP384R1Field.Add(x1.x, Z1Squared, M);
-  TSecP384R1Field.Multiply(M, t1, M);
-  c := TNat.AddBothTo(12, M, M, M);
-  TSecP384R1Field.Reduce32(c, M);
-
-  S := Y1Squared;
-  TSecP384R1Field.Multiply(Y1Squared, x1.x, S);
-  c := TNat.ShiftUpBits(12, S, 2, 0);
-  TSecP384R1Field.Reduce32(c, S);
-
-  c := TNat.ShiftUpBits(12, T, 3, 0, t1);
-  TSecP384R1Field.Reduce32(c, t1);
-
-  X3 := TSecP384R1FieldElement.Create(T);
-  TSecP384R1Field.Square(M, X3.x);
-  TSecP384R1Field.Subtract(X3.x, S, X3.x);
-  TSecP384R1Field.Subtract(X3.x, S, X3.x);
-
-  Y3 := TSecP384R1FieldElement.Create(S);
-  TSecP384R1Field.Subtract(S, X3.x, Y3.x);
-  TSecP384R1Field.Multiply(Y3.x, M, Y3.x);
-  TSecP384R1Field.Subtract(Y3.x, t1, Y3.x);
+    for LJ := 0 to System.Pred(SECP384R1_FE_INTS) do
+    begin
+      LX[LJ] := LX[LJ] xor (FTable[LPos + LJ] and LMask);
+      LY[LJ] := LY[LJ] xor (FTable[LPos + SECP384R1_FE_INTS + LJ] and LMask);
+    end;
 
-  Z3 := TSecP384R1FieldElement.Create(M);
-  TSecP384R1Field.Twice(Y1.x, Z3.x);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP384R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+    LPos := LPos + (SECP384R1_FE_INTS * 2);
   end;
 
-  result := TSecP384R1Point.Create(Lcurve, X3, Y3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed)
-    as IECPoint;
+  Result := CreatePoint(LX, LY);
 end;
 
-function TSecP384R1Point.TwicePlus(const b: IECPoint): IECPoint;
+function TSecP384R1Curve.TSecP384R1LookupTable.LookupVar(AIndex: Int32): IECPoint;
 var
-  Y1: IECFieldElement;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LJ: 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;
+  LX := TNat.Create(SECP384R1_FE_INTS);
+  LY := TNat.Create(SECP384R1_FE_INTS);
+  LPos := AIndex * SECP384R1_FE_INTS * 2;
 
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
+  for LJ := 0 to System.Pred(SECP384R1_FE_INTS) do
   begin
-    result := b;
-    Exit;
+    LX[LJ] := FTable[LPos + LJ];
+    LY[LJ] := FTable[LPos + SECP384R1_FE_INTS + LJ];
   end;
 
-  result := Twice().Add(b);
+  Result := CreatePoint(LX, LY);
 end;
 
 { TSecP384R1Curve }
 
-constructor TSecP384R1Curve.Create;
+class procedure TSecP384R1Curve.Boot;
 begin
-  Fq := TSecP384R1FieldElement.Q;
-  Inherited Create(Fq);
-  Fm_infinity := TSecP384R1Point.Create(Self as IECCurve, Nil, Nil);
-  Fm_a := FromBigInteger(TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC'))
-    );
-  Fm_b := FromBigInteger(TBigInteger.Create(1,
-    THex.Decode
-    ('B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF'))
-    );
-  Fm_order := TBigInteger.Create(1,
-    THex.Decode
-    ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973')
-    );
-  Fm_cofactor := TBigInteger.One;
-  Fm_coord := SECP384R1_DEFAULT_COORDS;
+  FQ := TSecP384R1FieldElement.Q;
+  FSecP384R1AffineZs := TCryptoLibGenericArray<IECFieldElement>.Create(
+    TSecP384R1FieldElement.Create(TBigInteger.One) as IECFieldElement);
 end;
 
-function TSecP384R1Curve.CloneCurve: IECCurve;
+class constructor TSecP384R1Curve.Create;
 begin
-  result := TSecP384R1Curve.Create();
+  Boot;
 end;
 
-function TSecP384R1Curve.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  table: TCryptoLibUInt32Array;
-  pos, i: Int32;
-  P: IECPoint;
+constructor TSecP384R1Curve.Create;
 begin
-  System.SetLength(table, len * SECP384R1_FE_INTS * 2);
-
-  pos := 0;
-  for i := 0 to System.Pred(len) do
-  begin
-    P := points[off + i];
-    TNat.Copy(SECP384R1_FE_INTS, (P.RawXCoord as ISecP384R1FieldElement).x, 0,
-      table, pos);
-    pos := pos + SECP384R1_FE_INTS;
-    TNat.Copy(SECP384R1_FE_INTS, (P.RawYCoord as ISecP384R1FieldElement).x, 0,
-      table, pos);
-    pos := pos + SECP384R1_FE_INTS;
-  end;
-
-  result := TSecP384R1LookupTable.Create(Self as ISecP384R1Curve, table, len);
+  Inherited Create(TSecP384R1Curve.Q, True);
+  FInfinity := TSecP384R1Point.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(TBigInteger.Create(1, THex.Decode('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC')));
+  FB := FromBigInteger(TBigInteger.Create(1, THex.Decode('B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF')));
+  FOrder := TBigInteger.Create(1, THex.Decode('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973'));
+  FCofactor := TBigInteger.One;
+  FCoord := SECP384R1_DEFAULT_COORDS;
 end;
 
-function TSecP384R1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
+destructor TSecP384R1Curve.Destroy;
 begin
-  result := TSecP384R1Point.Create(Self as IECCurve, x, y, withCompression);
+  FInfinity := nil;
+  inherited Destroy;
 end;
 
-function TSecP384R1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
+function TSecP384R1Curve.GetQ: TBigInteger;
 begin
-  result := TSecP384R1Point.Create(Self as IECCurve, x, y, zs, withCompression);
+  Result := TSecP384R1Curve.Q;
 end;
 
-function TSecP384R1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
+function TSecP384R1Curve.CloneCurve: IECCurve;
 begin
-  result := TSecP384R1FieldElement.Create(x);
+  Result := TSecP384R1Curve.Create;
 end;
 
 function TSecP384R1Curve.GetFieldSize: Int32;
 begin
-  result := Fq.BitLength;
+  Result := TSecP384R1Curve.Q.BitLength;
 end;
 
 function TSecP384R1Curve.GetInfinity: IECPoint;
 begin
-  result := Fm_infinity;
+  Result := FInfinity;
 end;
 
-function TSecP384R1Curve.GetQ: TBigInteger;
+function TSecP384R1Curve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
 begin
-  result := Fq;
+  Result := TSecP384R1FieldElement.Create(AX);
 end;
 
-function TSecP384R1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
+function TSecP384R1Curve.CreateRawPoint(const AX, AY: IECFieldElement): IECPoint;
 begin
-  case coord of
-    TECCurveConstants.COORD_JACOBIAN:
-      result := true
-  else
-    result := false;
-  end;
+  Result := TSecP384R1Point.Create(Self as IECCurve, AX, AY);
 end;
 
-{ TSecP384R1Curve.TSecP384R1LookupTable }
-
-constructor TSecP384R1Curve.TSecP384R1LookupTable.Create
-  (const outer: ISecP384R1Curve; const table: TCryptoLibUInt32Array;
-  size: Int32);
+function TSecP384R1Curve.CreateRawPoint(const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
 begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := size;
+  Result := TSecP384R1Point.Create(Self as IECCurve, AX, AY, AZs);
 end;
 
-function TSecP384R1Curve.TSecP384R1LookupTable.CreatePoint(const x,
-  y: TCryptoLibUInt32Array): IECPoint;
+function TSecP384R1Curve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
 var
-  XFieldElement, YFieldElement: ISecP384R1FieldElement;
-  SECP384R1_AFFINE_ZS: TCryptoLibGenericArray<IECFieldElement>;
+  LTable: TCryptoLibUInt32Array;
+  LPos, LI: Int32;
+  LP: IECPoint;
 begin
-  SECP384R1_AFFINE_ZS := TCryptoLibGenericArray<IECFieldElement>.Create
-    (TSecP384R1FieldElement.Create(TBigInteger.One) as ISecP384R1FieldElement);
-
-  XFieldElement := TSecP384R1FieldElement.Create(x);
-  YFieldElement := TSecP384R1FieldElement.Create(y);
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement,
-    SECP384R1_AFFINE_ZS, false);
+  System.SetLength(LTable, ALen * SECP384R1_FE_INTS * 2);
+  LPos := 0;
+  for LI := 0 to System.Pred(ALen) do
+  begin
+    LP := APoints[AOff + LI];
+    TNat.Copy(SECP384R1_FE_INTS, (LP.RawXCoord as ISecP384R1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP384R1_FE_INTS;
+    TNat.Copy(SECP384R1_FE_INTS, (LP.RawYCoord as ISecP384R1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP384R1_FE_INTS;
+  end;
+  Result := TSecP384R1LookupTable.Create(Self as ISecP384R1Curve, LTable, ALen);
 end;
 
-function TSecP384R1Curve.TSecP384R1LookupTable.GetSize: Int32;
+function TSecP384R1Curve.RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LX: TCryptoLibUInt32Array;
 begin
-  result := Fm_size;
+  LX := TNat.Create(12);
+  TSecP384R1Field.Random(ARandom, LX);
+  Result := TSecP384R1FieldElement.Create(LX);
 end;
 
-function TSecP384R1Curve.TSecP384R1LookupTable.Lookup(index: Int32): IECPoint;
+function TSecP384R1Curve.RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
 var
-  x, y: TCryptoLibUInt32Array;
-  pos, i, J: Int32;
-  MASK: UInt32;
+  LX: TCryptoLibUInt32Array;
 begin
-  x := TNat.Create(SECP384R1_FE_INTS);
-  y := TNat.Create(SECP384R1_FE_INTS);
-  pos := 0;
-
-  for i := 0 to System.Pred(Fm_size) do
-  begin
-    MASK := UInt32(TBitOperations.Asr32((i xor index) - 1, 31));
-
-    for J := 0 to System.Pred(SECP384R1_FE_INTS) do
-    begin
-      x[J] := x[J] xor (Fm_table[pos + J] and MASK);
-      y[J] := y[J] xor (Fm_table[pos + SECP384R1_FE_INTS + J] and MASK);
-    end;
-
-    pos := pos + (SECP384R1_FE_INTS * 2);
-  end;
-
-  result := CreatePoint(x, y)
+  LX := TNat.Create(12);
+  TSecP384R1Field.RandomMult(ARandom, LX);
+  Result := TSecP384R1FieldElement.Create(LX);
 end;
 
-function TSecP384R1Curve.TSecP384R1LookupTable.LookupVar(index: Int32)
-  : IECPoint;
-var
-  x, y: TCryptoLibUInt32Array;
-  pos, J: Int32;
+function TSecP384R1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
 begin
-  x := TNat.Create(SECP384R1_FE_INTS);
-  y := TNat.Create(SECP384R1_FE_INTS);
-  pos := index * SECP384R1_FE_INTS * 2;
-
-  for J := 0 to System.Pred(SECP384R1_FE_INTS) do
-  begin
-    x[J] := Fm_table[pos + J];
-    y[J] := Fm_table[pos + SECP384R1_FE_INTS + J];
+  case ACoord of
+    TECCurveConstants.COORD_JACOBIAN:
+      Result := True;
+  else
+    Result := False;
   end;
-
-  result := CreatePoint(x, y)
 end;
 
 end.

+ 681 - 782
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas

@@ -22,1121 +22,1020 @@ unit ClpSecP521R1Custom;
 interface
 
 uses
+  SysUtils,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpNat512,
   ClpNat,
   ClpMod,
+  ClpPack,
   ClpEncoders,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpArrayUtilities,
   ClpBitOperations,
-  ClpNat512,
   ClpECCurve,
-  ClpBigInteger,
-  ClpArrayUtilities,
+  ClpECCurveConstants,
+  ClpECFieldElement,
+  ClpECPoint,
+  ClpECLookupTables,
+  ClpFiniteFields,
   ClpIECCore,
   ClpIECFieldElement,
-  ClpCryptoLibTypes,
-  ClpECCurveConstants,
-  ClpISecP521R1Custom;
+  ClpISecP521R1Custom,
+  ClpCryptoLibTypes;
 
 resourcestring
-  SInvalidValueForSecP521R1FieldElement =
-    'Value Invalid for SecP521R1FieldElement "%s"';
-  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
+  SInvalidSecP521R1FieldElement = 'value invalid for SecP521R1FieldElement';
 
 type
-  // 2^521 - 1
   TSecP521R1Field = class sealed(TObject)
-
   strict private
   const
     P16 = UInt32($1FF);
-
-    class var
-
-      FP: TCryptoLibUInt32Array;
-
-    class function GetP: TCryptoLibUInt32Array; static; inline;
-
-    class procedure ImplMultiply(const x, y, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure ImplSquare(const x, zz: TCryptoLibUInt32Array);
-      static; inline;
-
-    class procedure Boot(); static;
-    class constructor SecP521R1Field();
-
+  class var
+    FP: TCryptoLibUInt32Array;
+  class procedure Boot; static;
+  class procedure ImplMultiply(const AX, AY, AZZ: TCryptoLibUInt32Array); static;
+  class procedure ImplSquare(const AX, AZZ: TCryptoLibUInt32Array); static;
+  class constructor Create;
   public
-    class procedure Add(const x, y, z: TCryptoLibUInt32Array); static; inline;
-    class procedure AddOne(const x, z: TCryptoLibUInt32Array); static; inline;
-    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt32Array;
-      static; inline;
-    class procedure Half(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Multiply(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Negate(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce(const xx, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce23(const z: TCryptoLibUInt32Array); static; inline;
-    class procedure Square(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure SquareN(const x: TCryptoLibUInt32Array; n: Int32;
-      const z: TCryptoLibUInt32Array); static; inline;
-    class procedure Subtract(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Twice(const x, z: TCryptoLibUInt32Array); static; inline;
-
-    class property P: TCryptoLibUInt32Array read GetP;
+    class procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure AddOne(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array; static;
+    class procedure Half(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Inv(const AX, AZ: TCryptoLibUInt32Array); static;
+    class function IsZero(const AX: TCryptoLibUInt32Array): Int32; static;
+    class procedure Multiply(const AX, AY, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure Negate(const AX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce(const AXX, AZ: TCryptoLibUInt32Array); static;
+    class procedure Reduce23(const AZ: TCryptoLibUInt32Array); static;
+    class procedure Square(const AX, AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure Square(const AX, AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ: TCryptoLibUInt32Array); overload; static;
+    class procedure SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+      const AZ, ATT: TCryptoLibUInt32Array); overload; static;
+    class procedure Subtract(const AX, AY, AZ: TCryptoLibUInt32Array); static;
+    class procedure Twice(const AX, AZ: TCryptoLibUInt32Array); static;
+
+    class property P: TCryptoLibUInt32Array read FP;
   end;
 
 type
-  TSecP521R1FieldElement = class(TAbstractFpFieldElement,
-    ISecP521R1FieldElement)
-
+  TSecP521R1FieldElement = class sealed(TAbstractFpFieldElement,
+    IAbstractFpFieldElement, IECFieldElement, ISecP521R1FieldElement)
   strict private
-
-    function Equals(const AOther: ISecP521R1FieldElement): Boolean;
-      reintroduce; overload;
-
-    class function GetQ: TBigInteger; static; inline;
-
+  class var
+    FQ: TBigInteger;
+  class procedure Boot; static;
+  class constructor Create;
   strict protected
-  var
-    Fx: TCryptoLibUInt32Array;
-
-    function GetFieldName: string; override;
-    function GetFieldSize: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
+    FX: TCryptoLibUInt32Array;
     function GetX: TCryptoLibUInt32Array; inline;
-    property x: TCryptoLibUInt32Array read GetX;
-
   public
+    class function GetQ: TBigInteger; static;
+    class property Q: TBigInteger read GetQ;
+    constructor Create(const AX: TBigInteger); overload;
     constructor Create(); overload;
-    constructor Create(const x: TBigInteger); overload;
-    constructor Create(const x: TCryptoLibUInt32Array); overload;
+    constructor Create(const AX: TCryptoLibUInt32Array); overload;
 
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+    function ToBigInteger: TBigInteger; 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
-    /// returns the right value - if <br />none exists it returns null.
-    /// </summary>
-    function Sqrt(): IECFieldElement; override;
 
-    function Equals(const AOther: IECFieldElement): Boolean; overload; 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 Divide(const AB: IECFieldElement): IECFieldElement; override;
+    function Negate: IECFieldElement; override;
+    function Square: IECFieldElement; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: IECFieldElement; override;
 
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
+    function Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
 
-    property IsZero: Boolean read GetIsZero;
-    property IsOne: Boolean read GetIsOne;
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    class property Q: TBigInteger read GetQ;
+    property X: TCryptoLibUInt32Array read GetX;
   end;
 
 type
-  TSecP521R1Point = class sealed(TAbstractFpPoint, ISecP521R1Point)
-
+  TSecP521R1Point = class sealed(TAbstractFpPoint, IAbstractFpPoint, IECPoint,
+    ISecP521R1Point)
   strict protected
-    function Detach(): IECPoint; override;
-
+    function Detach: IECPoint; override;
   public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="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 that encodes with or without point compresion.
-    /// </summary>
-    /// <param name="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;
-
-    function Add(const b: IECPoint): IECPoint; override;
-    function Negate(): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function ThreeTimes(): IECPoint; override;
-
+    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 Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function ThreeTimes: IECPoint; override;
+    function Negate: IECPoint; override;
   end;
 
 type
-  TSecP521R1Curve = class sealed(TAbstractFpCurve, ISecP521R1Curve)
-
+  TSecP521R1Curve = class sealed(TAbstractFpCurve, IAbstractFpCurve, IECCurve,
+    ISecP521R1Curve)
+  strict private
+  const
+    SECP521R1_DEFAULT_COORDS = TECCurveConstants.COORD_JACOBIAN;
+    SECP521R1_FE_INTS = 17;
   strict private
-
   type
-    TSecP521R1LookupTable = class sealed(TAbstractECLookupTable,
-      ISecP521R1LookupTable, IECLookupTable)
-
+    TSecP521R1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable,
+      ISecP521R1LookupTable)
     strict private
-    var
-      Fm_outer: ISecP521R1Curve;
-      Fm_table: TCryptoLibUInt32Array;
-      Fm_size: Int32;
-
-      function CreatePoint(const x, y: TCryptoLibUInt32Array): IECPoint;
-
-    strict protected
-
-      function GetSize: Int32; override;
-
+      FOuter: ISecP521R1Curve;
+      FTable: TCryptoLibUInt32Array;
+      FSize: Int32;
+      function CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
     public
-
-      constructor Create(const outer: ISecP521R1Curve;
-        const table: TCryptoLibUInt32Array; size: Int32);
-
-      function Lookup(index: Int32): IECPoint; override;
-      function LookupVar(index: Int32): IECPoint; override;
-
+      constructor Create(const AOuter: ISecP521R1Curve;
+        const ATable: TCryptoLibUInt32Array; ASize: Int32);
+      function GetSize: Int32; override;
+      function Lookup(AIndex: Int32): IECPoint; override;
+      function LookupVar(AIndex: Int32): IECPoint; override;
     end;
-
-  const
-    SECP521R1_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_JACOBIAN);
-    SECP521R1_FE_INTS = Int32(17);
-
+  class var
+    FQ: TBigInteger;
+    FSecP521R1AffineZs: TCryptoLibGenericArray<IECFieldElement>;
+  class procedure Boot; static;
+  class constructor Create;
   var
-    Fq: TBigInteger;
-
+    FInfinity: TSecP521R1Point;
   strict protected
-  var
-    Fm_infinity: ISecP521R1Point;
+    function GetQ: TBigInteger;
+  public
+    constructor Create;
+    destructor Destroy; override;
 
-    function GetQ: TBigInteger; virtual;
+    function CloneCurve: IECCurve; override;
     function GetFieldSize: Int32; override;
     function GetInfinity: IECPoint; 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();
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property Q: TBigInteger read GetQ;
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement;
+      const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint; override;
+    function CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+      AOff, ALen: Int32): IECLookupTable; override;
+    function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override;
+    function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override;
+    function SupportsCoordinateSystem(ACoord: Int32): Boolean; override;
+
+    class property Q: TBigInteger read FQ;
+    class property SecP521R1AffineZs: TCryptoLibGenericArray<IECFieldElement> read FSecP521R1AffineZs;
   end;
 
 implementation
 
 { TSecP521R1Field }
 
-class constructor TSecP521R1Field.SecP521R1Field;
+class procedure TSecP521R1Field.Boot;
 begin
-  TSecP521R1Field.Boot;
+  FP := TCryptoLibUInt32Array.Create($FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $1FF);
 end;
 
-class function TSecP521R1Field.GetP: TCryptoLibUInt32Array;
+class constructor TSecP521R1Field.Create;
+begin
+  Boot;
+end;
+
+class procedure TSecP521R1Field.ImplMultiply(const AX, AY, AZZ: TCryptoLibUInt32Array);
+var
+  LX16, LY16: UInt32;
 begin
-  result := FP;
+  TNat512.Mul(AX, AY, AZZ);
+  LX16 := AX[16];
+  LY16 := AY[16];
+  AZZ[32] := TNat.Mul31BothAdd(16, LX16, AY, LY16, AX, AZZ, 16) + (LX16 * LY16);
 end;
 
-class procedure TSecP521R1Field.Add(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.ImplSquare(const AX, AZZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LX16: UInt32;
 begin
-  c := TNat.Add(16, x, y, z) + x[16] + y[16];
-  if ((c > P16) or ((c = P16) and (TNat.Eq(16, z, FP)))) then
+  TNat512.Square(AX, AZZ);
+  LX16 := AX[16];
+  AZZ[32] := TNat.MulWordAddTo(16, LX16 shl 1, AX, 0, AZZ, 16) + (LX16 * LX16);
+end;
+
+class procedure TSecP521R1Field.Add(const AX, AY, AZ: TCryptoLibUInt32Array);
+var
+  LC: UInt32;
+begin
+  LC := TNat.Add(16, AX, AY, AZ) + AX[16] + AY[16];
+  if (LC > P16) or ((LC = P16) and TNat.Eq(16, AZ, FP)) then
   begin
-    c := c + (TNat.Inc(16, z));
-    c := c and P16;
+    LC := LC + TNat.Inc(16, AZ);
+    LC := LC and P16;
   end;
-  z[16] := c;
+  AZ[16] := LC;
 end;
 
-class procedure TSecP521R1Field.AddOne(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.AddOne(const AX, AZ: TCryptoLibUInt32Array);
 var
-  c: UInt32;
+  LC: UInt32;
 begin
-  c := TNat.Inc(16, x, z) + x[16];
-  if ((c > P16) or ((c = P16) and (TNat.Eq(16, z, FP)))) then
+  LC := TNat.Inc(16, AX, AZ) + AX[16];
+  if (LC > P16) or ((LC = P16) and TNat.Eq(16, AZ, FP)) then
   begin
-    c := c + TNat.Inc(16, z);
-    c := c and P16;
+    LC := LC + TNat.Inc(16, AZ);
+    LC := LC and P16;
   end;
-  z[16] := c;
+  AZ[16] := LC;
 end;
 
-class procedure TSecP521R1Field.Boot;
+class function TSecP521R1Field.FromBigInteger(const AX: TBigInteger): TCryptoLibUInt32Array;
+var
+  LZ: TCryptoLibUInt32Array;
 begin
-  FP := TCryptoLibUInt32Array.Create($FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $1FF);
+  LZ := TNat.FromBigInteger(521, AX);
+  if TNat.Eq(17, LZ, FP) then
+    TNat.Zero(17, LZ);
+  Result := LZ;
 end;
 
-class function TSecP521R1Field.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
+class procedure TSecP521R1Field.Half(const AX, AZ: TCryptoLibUInt32Array);
 var
-  z: TCryptoLibUInt32Array;
+  LX16: UInt32;
+  LC: UInt32;
 begin
-  z := TNat.FromBigInteger(521, x);
-  if (TNat.Eq(17, z, FP)) then
-  begin
-    TNat.Zero(17, z);
-  end;
-  result := z;
+  LX16 := AX[16];
+  LC := TNat.ShiftDownBit(16, AX, LX16, AZ);
+  AZ[16] := (LX16 shr 1) or (LC shr 23);
 end;
 
-class procedure TSecP521R1Field.Half(const x, z: TCryptoLibUInt32Array);
-var
-  x16, c: UInt32;
+class procedure TSecP521R1Field.Inv(const AX, AZ: TCryptoLibUInt32Array);
 begin
-  x16 := x[16];
-  c := TNat.ShiftDownBit(16, x, x16, z);
-  z[16] := (x16 shr 1) or (c shr 23);
+  TMod.CheckedModOddInverse(FP, AX, AZ);
 end;
 
-class procedure TSecP521R1Field.ImplMultiply(const x, y,
-  zz: TCryptoLibUInt32Array);
+class function TSecP521R1Field.IsZero(const AX: TCryptoLibUInt32Array): Int32;
 var
-  x16, y16: UInt32;
+  LD: UInt32;
+  LI: Int32;
 begin
-  TNat512.Mul(x, y, zz);
-  x16 := x[16];
-  y16 := y[16];
-  zz[32] := TNat.Mul31BothAdd(16, x16, y, y16, x, zz, 16) + (x16 * y16);
+  LD := 0;
+  for LI := 0 to 16 do
+    LD := LD or AX[LI];
+  LD := (LD shr 1) or (LD and 1);
+  Result := TBitOperations.Asr32(Int32(LD) - 1, 31);
 end;
 
-class procedure TSecP521R1Field.ImplSquare(const x, zz: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Multiply(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  x16: UInt32;
+  LTT: TCryptoLibUInt32Array;
 begin
-  TNat512.Square(x, zz);
-  x16 := x[16];
-  zz[32] := TNat.MulWordAddTo(16, (x16 shl 1), x, 0, zz, 16) + (x16 * x16);
+  LTT := TNat.Create(33);
+  ImplMultiply(AX, AY, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP521R1Field.Reduce23(const z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Multiply(const AX, AY, AZ, ATT: TCryptoLibUInt32Array);
+begin
+  ImplMultiply(AX, AY, ATT);
+  Reduce(ATT, AZ);
+end;
+
+class procedure TSecP521R1Field.Negate(const AX, AZ: TCryptoLibUInt32Array);
+begin
+  if IsZero(AX) <> 0 then
+    TNat.Sub(17, FP, FP, AZ)
+  else
+    TNat.Sub(17, FP, AX, AZ);
+end;
+
+class procedure TSecP521R1Field.Random(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
 var
-  z16, c: UInt32;
+  LBB: TCryptoLibByteArray;
+begin
+  System.SetLength(LBB, 17 * 4);
+  repeat
+    AR.NextBytes(LBB);
+    TPack.LE_To_UInt32(LBB, 0, AZ, 0, 17);
+    AZ[16] := AZ[16] and P16;
+  until TNat.LessThan(17, AZ, FP) <> 0;
+end;
+
+class procedure TSecP521R1Field.RandomMult(const AR: ISecureRandom; const AZ: TCryptoLibUInt32Array);
 begin
-  z16 := z[16];
-  c := TNat.AddWordTo(16, (z16 shr 9), z) + (z16 and P16);
-  if ((c > P16) or ((c = P16) and (TNat.Eq(16, z, FP)))) then
+  repeat
+    Random(AR, AZ);
+  until IsZero(AZ) <> 0;
+end;
+
+class procedure TSecP521R1Field.Reduce(const AXX, AZ: TCryptoLibUInt32Array);
+var
+  LXX32: UInt32;
+  LC: UInt32;
+begin
+  {$IFDEF DEBUG}
+  Assert(AXX[32] shr 18 = 0);
+  {$ENDIF DEBUG}
+  LXX32 := AXX[32];
+  LC := TNat.ShiftDownBits(16, AXX, 16, 9, LXX32, AZ, 0) shr 23;
+  LC := LC + (LXX32 shr 9);
+  LC := LC + TNat.AddTo(16, AXX, AZ);
+  if (LC > P16) or ((LC = P16) and TNat.Eq(16, AZ, FP)) then
   begin
-    c := c + (TNat.Inc(16, z));
-    c := c and P16;
+    LC := LC + TNat.Inc(16, AZ);
+    LC := LC and P16;
   end;
-  z[16] := c;
+  AZ[16] := LC;
 end;
 
-class procedure TSecP521R1Field.Reduce(const xx, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Reduce23(const AZ: TCryptoLibUInt32Array);
 var
-  xx32, c: UInt32;
-begin
-{$IFDEF DEBUG}
-  System.Assert((xx[32] shr 18) = 0);
-{$ENDIF DEBUG}
-  xx32 := xx[32];
-  c := TNat.ShiftDownBits(16, xx, 16, 9, xx32, z, 0) shr 23;
-  c := c + (xx32 shr 9);
-  c := c + (TNat.AddTo(16, xx, z));
-  if ((c > P16) or ((c = P16) and (TNat.Eq(16, z, FP)))) then
+  LZ16: UInt32;
+  LC: UInt32;
+begin
+  LZ16 := AZ[16];
+  LC := TNat.AddWordTo(16, LZ16 shr 9, AZ) + (LZ16 and P16);
+  if (LC > P16) or ((LC = P16) and TNat.Eq(16, AZ, FP)) then
   begin
-    c := c + (TNat.Inc(16, z));
-    c := c and P16;
+    LC := LC + TNat.Inc(16, AZ);
+    LC := LC and P16;
   end;
-  z[16] := c;
+  AZ[16] := LC;
 end;
 
-class procedure TSecP521R1Field.Multiply(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Square(const AX, AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
+  LTT: TCryptoLibUInt32Array;
 begin
-  tt := TNat.Create(33);
-  ImplMultiply(x, y, tt);
-  Reduce(tt, z);
+  LTT := TNat.Create(33);
+  ImplSquare(AX, LTT);
+  Reduce(LTT, AZ);
 end;
 
-class procedure TSecP521R1Field.Negate(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Square(const AX, AZ, ATT: TCryptoLibUInt32Array);
 begin
-  if (TNat.IsZero(17, x)) then
-  begin
-    TNat.Zero(17, z);
-  end
-  else
-  begin
-    TNat.Sub(17, FP, x, z);
-  end;
+  ImplSquare(AX, ATT);
+  Reduce(ATT, AZ);
 end;
 
-class procedure TSecP521R1Field.Square(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ: TCryptoLibUInt32Array);
 var
-  tt: TCryptoLibUInt32Array;
-begin
-  tt := TNat.Create(33);
-  ImplSquare(x, tt);
-  Reduce(tt, z);
+  LTT: TCryptoLibUInt32Array;
+begin
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  LTT := TNat.Create(33);
+  ImplSquare(AX, LTT);
+  Reduce(LTT, AZ);
+  Dec(AN);
+  while AN > 0 do
+  begin
+    ImplSquare(AZ, LTT);
+    Reduce(LTT, AZ);
+    Dec(AN);
+  end;
 end;
 
-class procedure TSecP521R1Field.SquareN(const x: TCryptoLibUInt32Array;
-  n: Int32; const z: TCryptoLibUInt32Array);
-var
-  tt: TCryptoLibUInt32Array;
+class procedure TSecP521R1Field.SquareN(const AX: TCryptoLibUInt32Array; AN: Int32;
+  const AZ, ATT: TCryptoLibUInt32Array);
 begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  tt := TNat.Create(33);
-  ImplSquare(x, tt);
-  Reduce(tt, z);
-
-  System.Dec(n);
-  while (n > 0) do
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  ImplSquare(AX, ATT);
+  Reduce(ATT, AZ);
+  Dec(AN);
+  while AN > 0 do
   begin
-    ImplSquare(z, tt);
-    Reduce(tt, z);
-    System.Dec(n);
+    ImplSquare(AZ, ATT);
+    Reduce(ATT, AZ);
+    Dec(AN);
   end;
 end;
 
-class procedure TSecP521R1Field.Subtract(const x, y, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Subtract(const AX, AY, AZ: TCryptoLibUInt32Array);
 var
-  c: Int32;
+  LC: Int32;
 begin
-  c := TNat.Sub(16, x, y, z) + Int32(x[16] - y[16]);
-  if (c < 0) then
+  LC := Int32(TNat.Sub(16, AX, AY, AZ)) + Int32(AX[16] - AY[16]);
+  if LC < 0 then
   begin
-    c := c + TNat.Dec(16, z);
-    c := c and P16;
+    LC := LC + Int32(TNat.Dec(16, AZ));
+    LC := LC and Int32(P16);
   end;
-  z[16] := UInt32(c);
+  AZ[16] := UInt32(LC);
 end;
 
-class procedure TSecP521R1Field.Twice(const x, z: TCryptoLibUInt32Array);
+class procedure TSecP521R1Field.Twice(const AX, AZ: TCryptoLibUInt32Array);
 var
-  x16, c: UInt32;
+  LX16: UInt32;
+  LC: UInt32;
 begin
-  x16 := x[16];
-  c := TNat.ShiftUpBit(16, x, x16 shl 23, z) or (x16 shl 1);
-  z[16] := c and P16;
+  LX16 := AX[16];
+  LC := TNat.ShiftUpBit(16, AX, LX16 shl 23, AZ) or (LX16 shl 1);
+  AZ[16] := LC and P16;
 end;
 
 { TSecP521R1FieldElement }
 
-class function TSecP521R1FieldElement.GetQ: TBigInteger;
+class procedure TSecP521R1FieldElement.Boot;
 begin
-  result := TBigInteger.Create(1,
-    THex.Decode
-    ('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')
-    );
+  FQ := TBigInteger.Create(1, THex.Decode('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'));
 end;
 
-function TSecP521R1FieldElement.GetX: TCryptoLibUInt32Array;
+class constructor TSecP521R1FieldElement.Create;
 begin
-  result := Fx;
+  Boot;
 end;
 
-constructor TSecP521R1FieldElement.Create;
+class function TSecP521R1FieldElement.GetQ: TBigInteger;
 begin
-  Inherited Create();
-  Fx := TNat.Create(17);
+  Result := FQ;
 end;
 
-constructor TSecP521R1FieldElement.Create(const x: TBigInteger);
+constructor TSecP521R1FieldElement.Create(const AX: TBigInteger);
 begin
-  if ((not(x.IsInitialized)) or (x.SignValue < 0) or (x.CompareTo(Q) >= 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt
-      (@SInvalidValueForSecP521R1FieldElement, ['x']);
-  end;
-  Inherited Create();
-  Fx := TSecP521R1Field.FromBigInteger(x);
+  Inherited Create;
+  if (not AX.IsInitialized) or (AX.SignValue < 0) or (AX.CompareTo(FQ) >= 0) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidSecP521R1FieldElement);
+  FX := TSecP521R1Field.FromBigInteger(AX);
 end;
 
-constructor TSecP521R1FieldElement.Create(const x: TCryptoLibUInt32Array);
+constructor TSecP521R1FieldElement.Create();
 begin
-  Inherited Create();
-  Fx := x;
+  Inherited Create;
+  FX := TNat.Create(17);
 end;
 
-function TSecP521R1FieldElement.GetFieldName: string;
+constructor TSecP521R1FieldElement.Create(const AX: TCryptoLibUInt32Array);
 begin
-  result := 'SecP521R1Field';
+  Inherited Create;
+  FX := AX;
 end;
 
-function TSecP521R1FieldElement.GetFieldSize: Int32;
+function TSecP521R1FieldElement.GetX: TCryptoLibUInt32Array;
 begin
-  result := Q.BitLength;
+  Result := FX;
 end;
 
-function TSecP521R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
+function TSecP521R1FieldElement.GetFieldName: String;
 begin
-  result := Q.GetHashCode() xor TArrayUtilities.GetArrayHashCode(Fx, 0, 17);
+  Result := 'SecP521R1Field';
 end;
 
-function TSecP521R1FieldElement.GetIsOne: Boolean;
+function TSecP521R1FieldElement.GetFieldSize: Int32;
 begin
-  result := TNat.IsOne(17, Fx);
+  Result := FQ.BitLength;
 end;
 
-function TSecP521R1FieldElement.GetIsZero: Boolean;
+function TSecP521R1FieldElement.GetIsOne: Boolean;
 begin
-  result := TNat.IsZero(17, Fx);
+  Result := TNat.IsOne(17, FX);
 end;
 
-function TSecP521R1FieldElement.Sqrt: IECFieldElement;
-var
-  x1, t1, t2: TCryptoLibUInt32Array;
+function TSecP521R1FieldElement.GetIsZero: Boolean;
 begin
-  // Raise this element to the exponent 2^519
-  x1 := Fx;
-  if ((TNat.IsZero(17, x1)) or (TNat.IsOne(17, x1))) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  t1 := TNat.Create(17);
-  t2 := TNat.Create(17);
-
-  TSecP521R1Field.SquareN(x1, 519, t1);
-  TSecP521R1Field.Square(t1, t2);
-
-  if TNat.Eq(17, x1, t2) then
-  begin
-    result := TSecP521R1FieldElement.Create(t1);
-  end
-  else
-  begin
-    result := Nil;
-  end;
+  Result := TNat.IsZero(17, FX);
 end;
 
-function TSecP521R1FieldElement.TestBitZero: Boolean;
+function TSecP521R1FieldElement.ToBigInteger: TBigInteger;
 begin
-  result := TNat.GetBit(Fx, 0) = 1;
+  Result := TNat.ToBigInteger(17, FX);
 end;
 
-function TSecP521R1FieldElement.ToBigInteger: TBigInteger;
+function TSecP521R1FieldElement.TestBitZero: Boolean;
 begin
-  result := TNat.ToBigInteger(17, Fx);
+  Result := TNat.GetBit(FX, 0) = 1;
 end;
 
-function TSecP521R1FieldElement.Add(const b: IECFieldElement): IECFieldElement;
+function TSecP521R1FieldElement.Add(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TSecP521R1Field.Add(Fx, (b as ISecP521R1FieldElement).x, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Add(FX, (AB as ISecP521R1FieldElement).X, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
 function TSecP521R1FieldElement.AddOne: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TSecP521R1Field.AddOne(Fx, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.AddOne(FX, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
-function TSecP521R1FieldElement.Subtract(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP521R1FieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TSecP521R1Field.Subtract(Fx, (b as ISecP521R1FieldElement).x, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Subtract(FX, (AB as ISecP521R1FieldElement).X, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
-function TSecP521R1FieldElement.Multiply(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP521R1FieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TSecP521R1Field.Multiply(Fx, (b as ISecP521R1FieldElement).x, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Multiply(FX, (AB as ISecP521R1FieldElement).X, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
-function TSecP521R1FieldElement.Divide(const b: IECFieldElement)
-  : IECFieldElement;
+function TSecP521R1FieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TMod.CheckedModOddInverse(TSecP521R1Field.P, (b as ISecP521R1FieldElement).x, z);
-  TSecP521R1Field.Multiply(z, Fx, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Inv((AB as ISecP521R1FieldElement).X, LZ);
+  TSecP521R1Field.Multiply(LZ, FX, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
 function TSecP521R1FieldElement.Negate: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TSecP521R1Field.Negate(Fx, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Negate(FX, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
 function TSecP521R1FieldElement.Square: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TSecP521R1Field.Square(Fx, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Square(FX, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
 function TSecP521R1FieldElement.Invert: IECFieldElement;
 var
-  z: TCryptoLibUInt32Array;
+  LZ: TCryptoLibUInt32Array;
 begin
-  z := TNat.Create(17);
-  TMod.CheckedModOddInverse(TSecP521R1Field.P, Fx, z);
-  result := TSecP521R1FieldElement.Create(z);
+  LZ := TNat.Create(17);
+  TSecP521R1Field.Inv(FX, LZ);
+  Result := TSecP521R1FieldElement.Create(LZ);
 end;
 
-function TSecP521R1FieldElement.Equals(const AOther: ISecP521R1FieldElement): Boolean;
+function TSecP521R1FieldElement.Sqrt: IECFieldElement;
+var
+  LX1, LTT0, LT1, LT2: TCryptoLibUInt32Array;
 begin
-  if (Self as ISecP521R1FieldElement) = AOther then
-    Exit(True);
-  if AOther = nil then
-    Exit(False);
-  Result := TNat.Eq(17, Fx, AOther.x);
+  LX1 := FX;
+  if TNat.IsZero(17, LX1) or TNat.IsOne(17, LX1) then
+    Exit(Self as IECFieldElement);
+
+  LTT0 := TNat.Create(33);
+  LT1 := TNat.Create(17);
+  LT2 := TNat.Create(17);
+
+  TSecP521R1Field.SquareN(LX1, 519, LT1, LTT0);
+  TSecP521R1Field.Square(LT1, LT2, LTT0);
+
+  if TNat.Eq(17, LX1, LT2) then
+    Result := TSecP521R1FieldElement.Create(LT1)
+  else
+    Result := nil;
 end;
 
 function TSecP521R1FieldElement.Equals(const AOther: IECFieldElement): Boolean;
-var
-  LSec: ISecP521R1FieldElement;
 begin
+  if (Self as IECFieldElement) = AOther then
+    Exit(True);
   if AOther = nil then
     Exit(False);
-  if Supports(AOther, ISecP521R1FieldElement, LSec) then
-    Result := Equals(LSec)
-  else
-    Result := ToBigInteger.Equals(AOther.ToBigInteger);
+  Result := TNat.Eq(17, FX, (AOther as ISecP521R1FieldElement).X);
+end;
+
+function TSecP521R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
+begin
+  Result := FQ.GetHashCode() xor TArrayUtilities.GetArrayHashCode(FX, 0, 17);
 end;
 
 { TSecP521R1Point }
 
-constructor TSecP521R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
+constructor TSecP521R1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
 begin
-  Create(curve, x, y, false);
+  Inherited Create(ACurve, AX, AY);
 end;
 
-constructor TSecP521R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
+constructor TSecP521R1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
 begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SOneOfECFieldElementIsNil);
-  end;
+  Inherited Create(ACurve, AX, AY, AZs);
 end;
 
-constructor TSecP521R1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
+function TSecP521R1Point.Detach: IECPoint;
 begin
-  Inherited Create(curve, x, y, zs, withCompression);
+  Result := TSecP521R1Point.Create(nil, AffineXCoord, AffineYCoord);
 end;
 
-function TSecP521R1Point.Add(const b: IECPoint): IECPoint;
+function TSecP521R1Point.Add(const AB: IECPoint): IECPoint;
 var
-  Lcurve: IECCurve;
-  x1, Y1, X2, Y2, Z1, Z2, X3, Y3, Z3: ISecP521R1FieldElement;
-  t1, t2, t3, t4, U2, S2, U1, S1, H, R, HSquared, G, V: TCryptoLibUInt32Array;
-  Z1IsOne, Z2IsOne: Boolean;
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-begin
-  if (IsInfinity) then
+  LCurve: IECCurve;
+  LX1, LY1, LX2, LY2, LZ1, LZ2: ISecP521R1FieldElement;
+  LTT0: TCryptoLibUInt32Array;
+  LT1, LT2, LT3, LT4: TCryptoLibUInt32Array;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  LU2, LS2, LU1, LS1: TCryptoLibUInt32Array;
+  LH, LR, LHSquared, LG, LV: TCryptoLibUInt32Array;
+  LX3, LY3, LZ3: ISecP521R1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Self as IECPoint);
+  if (Self as IECPoint) = AB then
+    Exit(Twice());
+
+  LCurve := Curve;
+  LX1 := RawXCoord as ISecP521R1FieldElement;
+  LY1 := RawYCoord as ISecP521R1FieldElement;
+  LX2 := AB.RawXCoord as ISecP521R1FieldElement;
+  LY2 := AB.RawYCoord as ISecP521R1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP521R1FieldElement;
+  LZ2 := AB.GetZCoord(0) as ISecP521R1FieldElement;
+
+  LTT0 := TNat.Create(33);
+  LT1 := TNat.Create(17);
+  LT2 := TNat.Create(17);
+  LT3 := TNat.Create(17);
+  LT4 := TNat.Create(17);
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
   begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-  if ((Self as IECPoint) = b) then
+    LU2 := LX2.X;
+    LS2 := LY2.X;
+  end
+  else
   begin
-    result := Twice();
-    Exit;
+    LS2 := LT3;
+    TSecP521R1Field.Square(LZ1.X, LS2, LTT0);
+    LU2 := LT2;
+    TSecP521R1Field.Multiply(LS2, LX2.X, LU2, LTT0);
+    TSecP521R1Field.Multiply(LS2, LZ1.X, LS2, LTT0);
+    TSecP521R1Field.Multiply(LS2, LY2.X, LS2, LTT0);
   end;
 
-  Lcurve := curve;
-
-  x1 := RawXCoord as ISecP521R1FieldElement;
-  Y1 := RawYCoord as ISecP521R1FieldElement;
-  X2 := b.RawXCoord as ISecP521R1FieldElement;
-  Y2 := b.RawYCoord as ISecP521R1FieldElement;
-
-  Z1 := RawZCoords[0] as ISecP521R1FieldElement;
-  Z2 := b.RawZCoords[0] as ISecP521R1FieldElement;
-
-  t1 := TNat.Create(17);
-  t2 := TNat.Create(17);
-  t3 := TNat.Create(17);
-  t4 := TNat.Create(17);
-
-  Z1IsOne := Z1.IsOne;
-
-  if (Z1IsOne) then
+  LZ2IsOne := LZ2.IsOne;
+  if LZ2IsOne then
   begin
-    U2 := X2.x;
-    S2 := Y2.x;
+    LU1 := LX1.X;
+    LS1 := LY1.X;
   end
   else
   begin
-    S2 := t3;
-    TSecP521R1Field.Square(Z1.x, S2);
+    LS1 := LT4;
+    TSecP521R1Field.Square(LZ2.X, LS1, LTT0);
+    LU1 := LT1;
+    TSecP521R1Field.Multiply(LS1, LX1.X, LU1, LTT0);
+    TSecP521R1Field.Multiply(LS1, LZ2.X, LS1, LTT0);
+    TSecP521R1Field.Multiply(LS1, LY1.X, LS1, LTT0);
+  end;
 
-    U2 := t2;
-    TSecP521R1Field.Multiply(S2, X2.x, U2);
+  LH := TNat.Create(17);
+  TSecP521R1Field.Subtract(LU1, LU2, LH);
 
-    TSecP521R1Field.Multiply(S2, Z1.x, S2);
-    TSecP521R1Field.Multiply(S2, Y2.x, S2);
-  end;
+  LR := LT2;
+  TSecP521R1Field.Subtract(LS1, LS2, LR);
 
-  Z2IsOne := Z2.IsOne;
-  if (Z2IsOne) then
+  if TNat.IsZero(17, LH) then
   begin
-    U1 := x1.x;
-    S1 := Y1.x;
-  end
-  else
-  begin
-    S1 := t4;
-    TSecP521R1Field.Square(Z2.x, S1);
+    if TNat.IsZero(17, LR) then
+      Exit(Twice());
+    Exit(LCurve.Infinity);
+  end;
 
-    U1 := t1;
-    TSecP521R1Field.Multiply(S1, x1.x, U1);
+  LHSquared := LT3;
+  TSecP521R1Field.Square(LH, LHSquared, LTT0);
 
-    TSecP521R1Field.Multiply(S1, Z2.x, S1);
-    TSecP521R1Field.Multiply(S1, Y1.x, S1);
-  end;
+  LG := TNat.Create(17);
+  TSecP521R1Field.Multiply(LHSquared, LH, LG, LTT0);
 
-  H := TNat.Create(17);
-  TSecP521R1Field.Subtract(U1, U2, H);
+  LV := LT3;
+  TSecP521R1Field.Multiply(LHSquared, LU1, LV, LTT0);
 
-  R := t2;
-  TSecP521R1Field.Subtract(S1, S2, R);
+  TSecP521R1Field.Multiply(LS1, LG, LT1, LTT0);
 
-  // Check if b = Self or b = -Self
-  if (TNat.IsZero(17, H)) then
-  begin
-    if (TNat.IsZero(17, R)) then
-    begin
-      // Self = b, i.e. Self must be doubled
-      result := Twice();
-      Exit;
-    end;
+  LX3 := TSecP521R1FieldElement.Create(LT4);
+  TSecP521R1Field.Square(LR, LX3.X, LTT0);
+  TSecP521R1Field.Add(LX3.X, LG, LX3.X);
+  TSecP521R1Field.Subtract(LX3.X, LV, LX3.X);
+  TSecP521R1Field.Subtract(LX3.X, LV, LX3.X);
+
+  LY3 := TSecP521R1FieldElement.Create(LG);
+  TSecP521R1Field.Subtract(LV, LX3.X, LY3.X);
+  TSecP521R1Field.Multiply(LY3.X, LR, LT2, LTT0);
+  TSecP521R1Field.Subtract(LT2, LT1, LY3.X);
+
+  LZ3 := TSecP521R1FieldElement.Create(LH);
+  if not LZ1IsOne then
+    TSecP521R1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
+  if not LZ2IsOne then
+    TSecP521R1Field.Multiply(LZ3.X, LZ2.X, LZ3.X, LTT0);
 
-    // Self = -b, i.e. the result is the point at infinity
-    result := Lcurve.Infinity;
-    Exit;
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP521R1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
+
+function TSecP521R1Point.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LY1, LX1, LZ1: ISecP521R1FieldElement;
+  LTT0: TCryptoLibUInt32Array;
+  LY1Squared, LT, LT1, LT2: TCryptoLibUInt32Array;
+  LZ1Squared, LM, LS: TCryptoLibUInt32Array;
+  LZ1IsOne: Boolean;
+  LX3, LY3, LZ3: ISecP521R1FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+begin
+  if IsInfinity then
+    Exit(Self as IECPoint);
+
+  LCurve := Curve;
+  LY1 := RawYCoord as ISecP521R1FieldElement;
+  if LY1.IsZero then
+    Exit(LCurve.Infinity);
+
+  LX1 := RawXCoord as ISecP521R1FieldElement;
+  LZ1 := RawZCoords[0] as ISecP521R1FieldElement;
+
+  LTT0 := TNat.Create(33);
+  LT1 := TNat.Create(17);
+  LT2 := TNat.Create(17);
+
+  LY1Squared := TNat.Create(17);
+  TSecP521R1Field.Square(LY1.X, LY1Squared, LTT0);
+
+  LT := TNat.Create(17);
+  TSecP521R1Field.Square(LY1Squared, LT, LTT0);
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
+    LZ1Squared := LZ1.X
+  else
+  begin
+    LZ1Squared := LT2;
+    TSecP521R1Field.Square(LZ1.X, LZ1Squared, LTT0);
   end;
 
-  HSquared := t3;
-  TSecP521R1Field.Square(H, HSquared);
+  TSecP521R1Field.Subtract(LX1.X, LZ1Squared, LT1);
 
-  G := TNat.Create(17);
-  TSecP521R1Field.Multiply(HSquared, H, G);
+  LM := LT2;
+  TSecP521R1Field.Add(LX1.X, LZ1Squared, LM);
+  TSecP521R1Field.Multiply(LM, LT1, LM, LTT0);
+  TNat.AddBothTo(17, LM, LM, LM);
+  TSecP521R1Field.Reduce23(LM);
 
-  V := t3;
-  TSecP521R1Field.Multiply(HSquared, U1, V);
+  LS := LY1Squared;
+  TSecP521R1Field.Multiply(LY1Squared, LX1.X, LS, LTT0);
+  TNat.ShiftUpBits(17, LS, 2, 0);
+  TSecP521R1Field.Reduce23(LS);
 
-  TSecP521R1Field.Multiply(S1, G, t1);
+  TNat.ShiftUpBits(17, LT, 3, 0, LT1);
+  TSecP521R1Field.Reduce23(LT1);
 
-  X3 := TSecP521R1FieldElement.Create(t4);
-  TSecP521R1Field.Square(R, X3.x);
-  TSecP521R1Field.Add(X3.x, G, X3.x);
-  TSecP521R1Field.Subtract(X3.x, V, X3.x);
-  TSecP521R1Field.Subtract(X3.x, V, X3.x);
+  LX3 := TSecP521R1FieldElement.Create(LT);
+  TSecP521R1Field.Square(LM, LX3.X, LTT0);
+  TSecP521R1Field.Subtract(LX3.X, LS, LX3.X);
+  TSecP521R1Field.Subtract(LX3.X, LS, LX3.X);
 
-  Y3 := TSecP521R1FieldElement.Create(G);
-  TSecP521R1Field.Subtract(V, X3.x, Y3.x);
-  TSecP521R1Field.Multiply(Y3.x, R, t2);
-  TSecP521R1Field.Subtract(t2, t1, Y3.x);
+  LY3 := TSecP521R1FieldElement.Create(LS);
+  TSecP521R1Field.Subtract(LS, LX3.X, LY3.X);
+  TSecP521R1Field.Multiply(LY3.X, LM, LY3.X, LTT0);
+  TSecP521R1Field.Subtract(LY3.X, LT1, LY3.X);
 
-  Z3 := TSecP521R1FieldElement.Create(H);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP521R1Field.Multiply(Z3.x, Z1.x, Z3.x);
-  end;
-  if (not(Z2IsOne)) then
-  begin
-    TSecP521R1Field.Multiply(Z3.x, Z2.x, Z3.x);
-  end;
+  LZ3 := TSecP521R1FieldElement.Create(LM);
+  TSecP521R1Field.Twice(LY1.X, LZ3.X);
+  if not LZ1IsOne then
+    TSecP521R1Field.Multiply(LZ3.X, LZ1.X, LZ3.X, LTT0);
 
-  zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecP521R1Point.Create(LCurve, LX3 as IECFieldElement, LY3 as IECFieldElement, LZs);
+end;
 
-  result := TSecP521R1Point.Create(Lcurve, X3, Y3, zs, IsCompressed)
-    as IECPoint;
+function TSecP521R1Point.TwicePlus(const AB: IECPoint): IECPoint;
+begin
+  if (Self as IECPoint) = AB then
+    Exit(ThreeTimes());
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Twice());
+  if RawYCoord.IsZero then
+    Exit(AB);
+  Result := Twice().Add(AB);
 end;
 
-function TSecP521R1Point.Detach: IECPoint;
+function TSecP521R1Point.ThreeTimes: IECPoint;
 begin
-  result := TSecP521R1Point.Create(Nil, AffineXCoord, AffineYCoord) as IECPoint;
+  if IsInfinity or RawYCoord.IsZero then
+    Exit(Self as IECPoint);
+  Result := Twice().Add(Self as IECPoint);
 end;
 
 function TSecP521R1Point.Negate: IECPoint;
 begin
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  if IsInfinity then
+    Exit(Self as IECPoint);
+  Result := TSecP521R1Point.Create(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords);
+end;
 
-  result := TSecP521R1Point.Create(curve, RawXCoord, RawYCoord.Negate(),
-    RawZCoords, IsCompressed) as IECPoint;
+{ TSecP521R1Curve.TSecP521R1LookupTable }
+
+constructor TSecP521R1Curve.TSecP521R1LookupTable.Create(const AOuter: ISecP521R1Curve;
+  const ATable: TCryptoLibUInt32Array; ASize: Int32);
+begin
+  Inherited Create;
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
 end;
 
-function TSecP521R1Point.ThreeTimes: IECPoint;
+function TSecP521R1Curve.TSecP521R1LookupTable.GetSize: Int32;
 begin
-  if ((IsInfinity) or (RawYCoord.IsZero)) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
+  Result := FSize;
+end;
 
-  // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
-  result := Twice().Add(Self as IECPoint);
+function TSecP521R1Curve.TSecP521R1LookupTable.CreatePoint(const AX, AY: TCryptoLibUInt32Array): IECPoint;
+begin
+  Result := FOuter.CreateRawPoint(TSecP521R1FieldElement.Create(AX) as IECFieldElement,
+    TSecP521R1FieldElement.Create(AY) as IECFieldElement, TSecP521R1Curve.SecP521R1AffineZs);
 end;
 
-function TSecP521R1Point.Twice: IECPoint;
+function TSecP521R1Curve.TSecP521R1LookupTable.Lookup(AIndex: Int32): IECPoint;
 var
-  Lcurve: IECCurve;
-  Y1, x1, Z1, X3, Y3, Z3: ISecP521R1FieldElement;
-  Y1Squared, Z1Squared, T, M, S, t1, t2: TCryptoLibUInt32Array;
-  Z1IsOne: Boolean;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LI, LJ: Int32;
+  LMask: UInt32;
 begin
+  LX := TNat.Create(SECP521R1_FE_INTS);
+  LY := TNat.Create(SECP521R1_FE_INTS);
+  LPos := 0;
 
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  Lcurve := curve;
-
-  Y1 := RawYCoord as ISecP521R1FieldElement;
-  if (Y1.IsZero) then
-  begin
-    result := Lcurve.Infinity;
-    Exit;
-  end;
-
-  x1 := RawXCoord as ISecP521R1FieldElement;
-  Z1 := RawZCoords[0] as ISecP521R1FieldElement;
-
-  t1 := TNat.Create(17);
-  t2 := TNat.Create(17);
-  Y1Squared := TNat.Create(17);
-  TSecP521R1Field.Square(Y1.x, Y1Squared);
-
-  T := TNat.Create(17);
-  TSecP521R1Field.Square(Y1Squared, T);
-
-  Z1IsOne := Z1.IsOne;
-
-  Z1Squared := Z1.x;
-  if (not(Z1IsOne)) then
+  for LI := 0 to System.Pred(FSize) do
   begin
-    Z1Squared := t2;
-    TSecP521R1Field.Square(Z1.x, Z1Squared);
-  end;
-
-  TSecP521R1Field.Subtract(x1.x, Z1Squared, t1);
-
-  M := t2;
-  TSecP521R1Field.Add(x1.x, Z1Squared, M);
-  TSecP521R1Field.Multiply(M, t1, M);
-  TNat.AddBothTo(17, M, M, M);
-  TSecP521R1Field.Reduce23(M);
-
-  S := Y1Squared;
-  TSecP521R1Field.Multiply(Y1Squared, x1.x, S);
-  TNat.ShiftUpBits(17, S, 2, 0);
-  TSecP521R1Field.Reduce23(S);
-
-  TNat.ShiftUpBits(17, T, 3, 0, t1);
-  TSecP521R1Field.Reduce23(t1);
+    LMask := UInt32(TBitOperations.Asr32(((LI xor AIndex) - 1), 31));
 
-  X3 := TSecP521R1FieldElement.Create(T);
-  TSecP521R1Field.Square(M, X3.x);
-  TSecP521R1Field.Subtract(X3.x, S, X3.x);
-  TSecP521R1Field.Subtract(X3.x, S, X3.x);
-
-  Y3 := TSecP521R1FieldElement.Create(S);
-  TSecP521R1Field.Subtract(S, X3.x, Y3.x);
-  TSecP521R1Field.Multiply(Y3.x, M, Y3.x);
-  TSecP521R1Field.Subtract(Y3.x, t1, Y3.x);
+    for LJ := 0 to System.Pred(SECP521R1_FE_INTS) do
+    begin
+      LX[LJ] := LX[LJ] xor (FTable[LPos + LJ] and LMask);
+      LY[LJ] := LY[LJ] xor (FTable[LPos + SECP521R1_FE_INTS + LJ] and LMask);
+    end;
 
-  Z3 := TSecP521R1FieldElement.Create(M);
-  TSecP521R1Field.Twice(Y1.x, Z3.x);
-  if (not(Z1IsOne)) then
-  begin
-    TSecP521R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+    LPos := LPos + (SECP521R1_FE_INTS * 2);
   end;
 
-  result := TSecP521R1Point.Create(Lcurve, X3, Y3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed)
-    as IECPoint;
+  Result := CreatePoint(LX, LY);
 end;
 
-function TSecP521R1Point.TwicePlus(const b: IECPoint): IECPoint;
+function TSecP521R1Curve.TSecP521R1LookupTable.LookupVar(AIndex: Int32): IECPoint;
 var
-  Y1: IECFieldElement;
+  LX, LY: TCryptoLibUInt32Array;
+  LPos, LJ: 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;
+  LX := TNat.Create(SECP521R1_FE_INTS);
+  LY := TNat.Create(SECP521R1_FE_INTS);
+  LPos := AIndex * SECP521R1_FE_INTS * 2;
 
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
+  for LJ := 0 to System.Pred(SECP521R1_FE_INTS) do
   begin
-    result := b;
-    Exit;
+    LX[LJ] := FTable[LPos + LJ];
+    LY[LJ] := FTable[LPos + SECP521R1_FE_INTS + LJ];
   end;
 
-  result := Twice().Add(b);
+  Result := CreatePoint(LX, LY);
 end;
 
 { TSecP521R1Curve }
 
-constructor TSecP521R1Curve.Create;
+class procedure TSecP521R1Curve.Boot;
 begin
-  Fq := TSecP521R1FieldElement.Q;
-  Inherited Create(Fq);
-  Fm_infinity := TSecP521R1Point.Create(Self as IECCurve, Nil, Nil);
-  Fm_a := FromBigInteger(TBigInteger.Create(1,
-    THex.Decode
-    ('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC'))
-    );
-  Fm_b := FromBigInteger(TBigInteger.Create(1,
-    THex.Decode
-    ('0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00'))
-    );
-  Fm_order := TBigInteger.Create(1,
-    THex.Decode
-    ('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409')
-    );
-  Fm_cofactor := TBigInteger.One;
-  Fm_coord := SECP521R1_DEFAULT_COORDS;
+  FQ := TSecP521R1FieldElement.Q;
+  FSecP521R1AffineZs := TCryptoLibGenericArray<IECFieldElement>.Create(
+    TSecP521R1FieldElement.Create(TBigInteger.One) as IECFieldElement);
 end;
 
-function TSecP521R1Curve.CloneCurve: IECCurve;
+class constructor TSecP521R1Curve.Create;
 begin
-  result := TSecP521R1Curve.Create();
+  Boot;
 end;
 
-function TSecP521R1Curve.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  table: TCryptoLibUInt32Array;
-  pos, i: Int32;
-  P: IECPoint;
+constructor TSecP521R1Curve.Create;
 begin
-  System.SetLength(table, len * SECP521R1_FE_INTS * 2);
-
-  pos := 0;
-  for i := 0 to System.Pred(len) do
-  begin
-    P := points[off + i];
-    TNat.Copy(SECP521R1_FE_INTS, (P.RawXCoord as ISecP521R1FieldElement).x, 0,
-      table, pos);
-    pos := pos + SECP521R1_FE_INTS;
-    TNat.Copy(SECP521R1_FE_INTS, (P.RawYCoord as ISecP521R1FieldElement).x, 0,
-      table, pos);
-    pos := pos + SECP521R1_FE_INTS;
-  end;
-
-  result := TSecP521R1LookupTable.Create(Self as ISecP521R1Curve, table, len);
+  Inherited Create(TSecP521R1Curve.Q, True);
+  FInfinity := TSecP521R1Point.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(TBigInteger.Create(1, THex.Decode('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC')));
+  FB := FromBigInteger(TBigInteger.Create(1, THex.Decode('0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00')));
+  FOrder := TBigInteger.Create(1, THex.Decode('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409'));
+  FCofactor := TBigInteger.One;
+  FCoord := SECP521R1_DEFAULT_COORDS;
 end;
 
-function TSecP521R1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
+destructor TSecP521R1Curve.Destroy;
 begin
-  result := TSecP521R1Point.Create(Self as IECCurve, x, y, withCompression);
+  FInfinity := nil;
+  inherited Destroy;
 end;
 
-function TSecP521R1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
+function TSecP521R1Curve.GetQ: TBigInteger;
 begin
-  result := TSecP521R1Point.Create(Self as IECCurve, x, y, zs, withCompression);
+  Result := TSecP521R1Curve.Q;
 end;
 
-function TSecP521R1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
+function TSecP521R1Curve.CloneCurve: IECCurve;
 begin
-  result := TSecP521R1FieldElement.Create(x);
+  Result := TSecP521R1Curve.Create;
 end;
 
 function TSecP521R1Curve.GetFieldSize: Int32;
 begin
-  result := Fq.BitLength;
+  Result := TSecP521R1Curve.Q.BitLength;
 end;
 
 function TSecP521R1Curve.GetInfinity: IECPoint;
 begin
-  result := Fm_infinity;
+  Result := FInfinity;
 end;
 
-function TSecP521R1Curve.GetQ: TBigInteger;
+function TSecP521R1Curve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
 begin
-  result := Fq;
+  Result := TSecP521R1FieldElement.Create(AX);
 end;
 
-function TSecP521R1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
+function TSecP521R1Curve.CreateRawPoint(const AX, AY: IECFieldElement): IECPoint;
 begin
-  case coord of
-    TECCurveConstants.COORD_JACOBIAN:
-      result := true
-  else
-    result := false;
-  end;
+  Result := TSecP521R1Point.Create(Self as IECCurve, AX, AY);
 end;
 
-{ TSecP521R1Curve.TSecP521R1LookupTable }
-
-constructor TSecP521R1Curve.TSecP521R1LookupTable.Create
-  (const outer: ISecP521R1Curve; const table: TCryptoLibUInt32Array;
-  size: Int32);
+function TSecP521R1Curve.CreateRawPoint(const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
 begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := size;
+  Result := TSecP521R1Point.Create(Self as IECCurve, AX, AY, AZs);
 end;
 
-function TSecP521R1Curve.TSecP521R1LookupTable.CreatePoint(const x,
-  y: TCryptoLibUInt32Array): IECPoint;
+function TSecP521R1Curve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
 var
-  XFieldElement, YFieldElement: ISecP521R1FieldElement;
-  SECP521R1_AFFINE_ZS: TCryptoLibGenericArray<IECFieldElement>;
+  LTable: TCryptoLibUInt32Array;
+  LPos, LI: Int32;
+  LP: IECPoint;
 begin
-  SECP521R1_AFFINE_ZS := TCryptoLibGenericArray<IECFieldElement>.Create
-    (TSecP521R1FieldElement.Create(TBigInteger.One) as ISecP521R1FieldElement);
-
-  XFieldElement := TSecP521R1FieldElement.Create(x);
-  YFieldElement := TSecP521R1FieldElement.Create(y);
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement,
-    SECP521R1_AFFINE_ZS, false);
+  System.SetLength(LTable, ALen * SECP521R1_FE_INTS * 2);
+  LPos := 0;
+  for LI := 0 to System.Pred(ALen) do
+  begin
+    LP := APoints[AOff + LI];
+    TNat.Copy(SECP521R1_FE_INTS, (LP.RawXCoord as ISecP521R1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP521R1_FE_INTS;
+    TNat.Copy(SECP521R1_FE_INTS, (LP.RawYCoord as ISecP521R1FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECP521R1_FE_INTS;
+  end;
+  Result := TSecP521R1LookupTable.Create(Self as ISecP521R1Curve, LTable, ALen);
 end;
 
-function TSecP521R1Curve.TSecP521R1LookupTable.GetSize: Int32;
+function TSecP521R1Curve.RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement;
+var
+  LX: TCryptoLibUInt32Array;
 begin
-  result := Fm_size;
+  LX := TNat.Create(17);
+  TSecP521R1Field.Random(ARandom, LX);
+  Result := TSecP521R1FieldElement.Create(LX);
 end;
 
-function TSecP521R1Curve.TSecP521R1LookupTable.Lookup(index: Int32): IECPoint;
+function TSecP521R1Curve.RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement;
 var
-  x, y: TCryptoLibUInt32Array;
-  pos, i, J: Int32;
-  MASK: UInt32;
+  LX: TCryptoLibUInt32Array;
 begin
-  x := TNat.Create(SECP521R1_FE_INTS);
-  y := TNat.Create(SECP521R1_FE_INTS);
-  pos := 0;
-
-  for i := 0 to System.Pred(Fm_size) do
-  begin
-    MASK := UInt32(TBitOperations.Asr32((i xor index) - 1, 31));
-
-    for J := 0 to System.Pred(SECP521R1_FE_INTS) do
-    begin
-      x[J] := x[J] xor (Fm_table[pos + J] and MASK);
-      y[J] := y[J] xor (Fm_table[pos + SECP521R1_FE_INTS + J] and MASK);
-    end;
-
-    pos := pos + (SECP521R1_FE_INTS * 2);
-  end;
-
-  result := CreatePoint(x, y);
+  LX := TNat.Create(17);
+  TSecP521R1Field.RandomMult(ARandom, LX);
+  Result := TSecP521R1FieldElement.Create(LX);
 end;
 
-function TSecP521R1Curve.TSecP521R1LookupTable.LookupVar(index: Int32)
-  : IECPoint;
-var
-  x, y: TCryptoLibUInt32Array;
-  pos, J: Int32;
+function TSecP521R1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
 begin
-  x := TNat.Create(SECP521R1_FE_INTS);
-  y := TNat.Create(SECP521R1_FE_INTS);
-  pos := index * SECP521R1_FE_INTS * 2;
-
-  for J := 0 to System.Pred(SECP521R1_FE_INTS) do
-  begin
-    x[J] := x[J] xor Fm_table[pos + J];
-    y[J] := y[J] xor Fm_table[pos + SECP521R1_FE_INTS + J];
+  case ACoord of
+    TECCurveConstants.COORD_JACOBIAN:
+      Result := True;
+  else
+    Result := False;
   end;
-
-  result := CreatePoint(x, y);
 end;
 
 end.

+ 0 - 1653
CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283Custom.pas

@@ -1,1653 +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 ClpSecT283Custom;
-
-{$I ..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpBitOperations,
-  ClpEncoders,
-  ClpNat,
-  ClpNat320,
-  ClpECCurve,
-  ClpInterleave,
-  ClpBigInteger,
-  ClpArrayUtilities,
-  ClpIECCore,
-  ClpIECFieldElement,
-  ClpMultipliers,
-  ClpCryptoLibTypes,
-  ClpECCurveConstants,
-  ClpISecT283Custom;
-
-resourcestring
-  SInvalidValueForSecT283FieldElement =
-    'Value Invalid for SecT283FieldElement "%s"';
-  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
-
-type
-  TSecT283Field = class sealed(TObject)
-
-  strict private
-  const
-    M27 = UInt64(System.High(UInt64) shr 37);
-    M57 = UInt64(System.High(UInt64) shr 7);
-
-    class var
-
-      FROOT_Z: TCryptoLibUInt64Array;
-
-    class procedure ImplCompactExt(const zz: TCryptoLibUInt64Array); static;
-    class procedure ImplExpand(const x, z: TCryptoLibUInt64Array);
-      static; inline;
-    class procedure ImplMultiply(const x, y, zz: TCryptoLibUInt64Array); static;
-    class procedure ImplMulw(x, y: UInt64; const z: TCryptoLibUInt64Array;
-      zOff: Int32); static;
-
-    class procedure ImplSquare(const x, zz: TCryptoLibUInt64Array); static;
-
-    class procedure AddTo(const x, z: TCryptoLibUInt64Array); static; inline;
-
-    class procedure Boot(); static;
-    class constructor SecT283Field();
-
-  public
-    class procedure Add(const x, y, z: TCryptoLibUInt64Array); static; inline;
-    class procedure AddExt(const xx, yy, zz: TCryptoLibUInt64Array);
-      static; inline;
-    class procedure AddOne(const x, z: TCryptoLibUInt64Array); static; inline;
-
-    class procedure HalfTrace(const x, z: TCryptoLibUInt64Array);
-      static; inline;
-
-    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt64Array;
-      static; inline;
-
-    class procedure Invert(const x, z: TCryptoLibUInt64Array); static;
-    class procedure Multiply(const x, y, z: TCryptoLibUInt64Array);
-      static; inline;
-    class procedure MultiplyAddToExt(const x, y, zz: TCryptoLibUInt64Array);
-      static; inline;
-    class procedure Reduce(const xx, z: TCryptoLibUInt64Array); static;
-    class procedure Reduce37(const z: TCryptoLibUInt64Array; zOff: Int32);
-      static; inline;
-    class procedure Sqrt(const x, z: TCryptoLibUInt64Array); static;
-
-    class procedure Square(const x, z: TCryptoLibUInt64Array); static; inline;
-    class procedure SquareAddToExt(const x, zz: TCryptoLibUInt64Array);
-      static; inline;
-    class procedure SquareN(const x: TCryptoLibUInt64Array; n: Int32;
-      const z: TCryptoLibUInt64Array); static; inline;
-
-    class function Trace(const x: TCryptoLibUInt64Array): UInt32;
-      static; inline;
-
-  end;
-
-type
-  TSecT283FieldElement = class(TAbstractF2mFieldElement, ISecT283FieldElement)
-
-  strict private
-
-    function GetM: Int32; inline;
-
-    function GetRepresentation: Int32; inline;
-
-    function GetK1: Int32; inline;
-    function GetK2: Int32; inline;
-    function GetK3: Int32; inline;
-
-    function Equals(const AOther: ISecT283FieldElement): Boolean;
-      reintroduce; overload;
-
-  strict protected
-  var
-    Fx: TCryptoLibUInt64Array;
-
-    function GetFieldName: string; override;
-    function GetFieldSize: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
-    function GetX: TCryptoLibUInt64Array; inline;
-    property x: TCryptoLibUInt64Array read GetX;
-
-  public
-    constructor Create(); overload;
-    constructor Create(const x: TBigInteger); overload;
-    constructor Create(const x: TCryptoLibUInt64Array); overload;
-
-    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 MultiplyMinusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; override;
-    function MultiplyPlusProduct(const b, x, y: IECFieldElement)
-      : IECFieldElement; override;
-    function Divide(const b: IECFieldElement): IECFieldElement; override;
-    function Negate(): IECFieldElement; override;
-    function Square(): 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 Trace(): Int32; override;
-
-    function HalfTrace(): IECFieldElement; override;
-
-    function HasFastTrace(): Boolean; override;
-
-    function Invert(): IECFieldElement; override;
-
-    /// <summary>
-    /// return a sqrt root - the routine verifies that the calculation
-    /// returns the right value - if <br />none exists it returns null.
-    /// </summary>
-    function Sqrt(): IECFieldElement; override;
-
-    function Equals(const AOther: IECFieldElement): Boolean; overload; override;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    property IsZero: Boolean read GetIsZero;
-    property IsOne: Boolean read GetIsOne;
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    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;
-
-  end;
-
-type
-  TSecT283K1Point = class sealed(TAbstractF2mPoint, ISecT283K1Point)
-
-  strict protected
-    function Detach(): IECPoint; override;
-
-    function GetCompressionYTilde: Boolean; override;
-    property CompressionYTilde: Boolean read GetCompressionYTilde;
-
-  public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="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 that encodes with or without point compresion.
-    /// </summary>
-    /// <param name="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;
-
-    function Add(const b: IECPoint): IECPoint; override;
-    function Negate(): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function GetYCoord: IECFieldElement; override;
-    property YCoord: IECFieldElement read GetYCoord;
-
-  end;
-
-type
-  TSecT283K1Curve = class sealed(TAbstractF2mCurve, ISecT283K1Curve)
-
-  strict private
-
-  type
-    TSecT283K1LookupTable = class sealed(TAbstractECLookupTable,
-      ISecT283K1LookupTable)
-
-    strict private
-    var
-      Fm_outer: ISecT283K1Curve;
-      Fm_table: TCryptoLibUInt64Array;
-      Fm_size: Int32;
-
-      function CreatePoint(const x, y: TCryptoLibUInt64Array): IECPoint;
-
-    strict protected
-
-      function GetSize: Int32; override;
-
-    public
-
-      constructor Create(const outer: ISecT283K1Curve;
-        const table: TCryptoLibUInt64Array; size: Int32);
-
-      function Lookup(index: Int32): IECPoint; override;
-      function LookupVar(index: Int32): IECPoint; override;
-
-    end;
-
-  const
-    SECT283K1_DEFAULT_COORDS = Int32(TECCurveConstants.COORD_LAMBDA_PROJECTIVE);
-    SECT283K1_FE_LONGS = Int32(5);
-
-    function GetM: Int32; inline;
-    function GetK1: Int32; inline;
-    function GetK2: Int32; inline;
-    function GetK3: Int32; inline;
-    function GetIsTrinomial: Boolean; inline;
-
-  strict protected
-  var
-    Fm_infinity: ISecT283K1Point;
-
-    function GetFieldSize: Int32; override;
-    function GetInfinity: IECPoint; override;
-    function GetIsKoblitz: Boolean; 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 Create();
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-    property IsKoblitz: Boolean read GetIsKoblitz;
-
-    property M: Int32 read GetM;
-    property k1: Int32 read GetK1;
-    property k2: Int32 read GetK2;
-    property k3: Int32 read GetK3;
-    property IsTrinomial: Boolean read GetIsTrinomial;
-
-  end;
-
-implementation
-
-{ TSecT283Field }
-
-class constructor TSecT283Field.SecT283Field;
-begin
-  TSecT283Field.Boot;
-end;
-
-class procedure TSecT283Field.Reduce37(const z: TCryptoLibUInt64Array;
-  zOff: Int32);
-var
-  z4, t: UInt64;
-begin
-  z4 := z[zOff + 4];
-  t := z4 shr 27;
-  z[zOff] := z[zOff] xor (t xor (t shl 5) xor (t shl 7) xor (t shl 12));
-  z[zOff + 4] := z4 and M27;
-end;
-
-class procedure TSecT283Field.Add(const x, y, z: TCryptoLibUInt64Array);
-begin
-  z[0] := x[0] xor y[0];
-  z[1] := x[1] xor y[1];
-  z[2] := x[2] xor y[2];
-  z[3] := x[3] xor y[3];
-  z[4] := x[4] xor y[4];
-end;
-
-class procedure TSecT283Field.AddExt(const xx, yy, zz: TCryptoLibUInt64Array);
-begin
-  zz[0] := xx[0] xor yy[0];
-  zz[1] := xx[1] xor yy[1];
-  zz[2] := xx[2] xor yy[2];
-  zz[3] := xx[3] xor yy[3];
-  zz[4] := xx[4] xor yy[4];
-  zz[5] := xx[5] xor yy[5];
-  zz[6] := xx[6] xor yy[6];
-  zz[7] := xx[7] xor yy[7];
-  zz[8] := xx[8] xor yy[8];
-end;
-
-class procedure TSecT283Field.AddOne(const x, z: TCryptoLibUInt64Array);
-begin
-  z[0] := x[0] xor UInt64(1);
-  z[1] := x[1];
-  z[2] := x[2];
-  z[3] := x[3];
-  z[4] := x[4];
-end;
-
-class procedure TSecT283Field.AddTo(const x, z: TCryptoLibUInt64Array);
-begin
-  z[0] := z[0] xor x[0];
-  z[1] := z[1] xor x[1];
-  z[2] := z[2] xor x[2];
-  z[3] := z[3] xor x[3];
-  z[4] := z[4] xor x[4];
-end;
-
-class procedure TSecT283Field.Boot;
-begin
-  FROOT_Z := TCryptoLibUInt64Array.Create(UInt64($0C30C30C30C30808),
-    UInt64($30C30C30C30C30C3), UInt64($820820820820830C),
-    UInt64($0820820820820820), UInt64($2082082));
-end;
-
-class procedure TSecT283Field.HalfTrace(const x, z: TCryptoLibUInt64Array);
-var
-  tt: TCryptoLibUInt64Array;
-  i: Int32;
-begin
-  tt := TNat.Create64(9);
-
-  TNat320.Copy64(x, z);
-  i := 1;
-
-  while i < 283 do
-  begin
-    ImplSquare(z, tt);
-    Reduce(tt, z);
-    ImplSquare(z, tt);
-    Reduce(tt, z);
-    AddTo(x, z);
-    System.Inc(i, 2);
-  end;
-end;
-
-class function TSecT283Field.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt64Array;
-begin
-  result := TNat.FromBigInteger64(283, x);
-end;
-
-class procedure TSecT283Field.Multiply(const x, y, z: TCryptoLibUInt64Array);
-var
-  tt: TCryptoLibUInt64Array;
-begin
-  tt := TNat320.CreateExt64();
-  ImplMultiply(x, y, tt);
-  Reduce(tt, z);
-end;
-
-class procedure TSecT283Field.ImplSquare(const x, zz: TCryptoLibUInt64Array);
-begin
-  TInterleave.Expand64To128(x[0], zz, 0);
-  TInterleave.Expand64To128(x[1], zz, 2);
-  TInterleave.Expand64To128(x[2], zz, 4);
-  TInterleave.Expand64To128(x[3], zz, 6);
-  zz[8] := TInterleave.Expand32to64(UInt32(x[4]));
-end;
-
-class procedure TSecT283Field.Square(const x, z: TCryptoLibUInt64Array);
-var
-  tt: TCryptoLibUInt64Array;
-begin
-  tt := TNat.Create64(9);
-  ImplSquare(x, tt);
-  Reduce(tt, z);
-end;
-
-class procedure TSecT283Field.SquareN(const x: TCryptoLibUInt64Array; n: Int32;
-  const z: TCryptoLibUInt64Array);
-var
-  tt: TCryptoLibUInt64Array;
-begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  tt := TNat.Create64(9);
-  ImplSquare(x, tt);
-  Reduce(tt, z);
-
-  System.Dec(n);
-  while (n > 0) do
-  begin
-    ImplSquare(z, tt);
-    Reduce(tt, z);
-    System.Dec(n);
-  end;
-end;
-
-class procedure TSecT283Field.Invert(const x, z: TCryptoLibUInt64Array);
-var
-  t0, t1: TCryptoLibUInt64Array;
-begin
-  if TNat320.IsZero64(x) then
-  begin
-    raise EInvalidOperationCryptoLibException.Create('');
-  end;
-
-  // Itoh-Tsujii inversion
-
-  t0 := TNat320.Create64();
-  t1 := TNat320.Create64();
-
-  Square(x, t0);
-  Multiply(t0, x, t0);
-  SquareN(t0, 2, t1);
-  Multiply(t1, t0, t1);
-  SquareN(t1, 4, t0);
-  Multiply(t0, t1, t0);
-  SquareN(t0, 8, t1);
-  Multiply(t1, t0, t1);
-  Square(t1, t1);
-  Multiply(t1, x, t1);
-  SquareN(t1, 17, t0);
-  Multiply(t0, t1, t0);
-  Square(t0, t0);
-  Multiply(t0, x, t0);
-  SquareN(t0, 35, t1);
-  Multiply(t1, t0, t1);
-  SquareN(t1, 70, t0);
-  Multiply(t0, t1, t0);
-  Square(t0, t0);
-  Multiply(t0, x, t0);
-  SquareN(t0, 141, t1);
-  Multiply(t1, t0, t1);
-  Square(t1, z);
-end;
-
-class procedure TSecT283Field.ImplCompactExt(const zz: TCryptoLibUInt64Array);
-var
-  z0, z1, z2, z3, z4, z5, z6, z7, z8, z9: UInt64;
-begin
-  z0 := zz[0];
-  z1 := zz[1];
-  z2 := zz[2];
-  z3 := zz[3];
-  z4 := zz[4];
-  z5 := zz[5];
-  z6 := zz[6];
-  z7 := zz[7];
-  z8 := zz[8];
-  z9 := zz[9];
-  zz[0] := z0 xor (z1 shl 57);
-  zz[1] := (z1 shr 7) xor (z2 shl 50);
-  zz[2] := (z2 shr 14) xor (z3 shl 43);
-  zz[3] := (z3 shr 21) xor (z4 shl 36);
-  zz[4] := (z4 shr 28) xor (z5 shl 29);
-  zz[5] := (z5 shr 35) xor (z6 shl 22);
-  zz[6] := (z6 shr 42) xor (z7 shl 15);
-  zz[7] := (z7 shr 49) xor (z8 shl 8);
-  zz[8] := (z8 shr 56) xor (z9 shl 1);
-  zz[9] := (z9 shr 63); // Zero!
-end;
-
-class procedure TSecT283Field.ImplExpand(const x, z: TCryptoLibUInt64Array);
-var
-  x0, x1, x2, x3, x4: UInt64;
-begin
-  x0 := x[0];
-  x1 := x[1];
-  x2 := x[2];
-  x3 := x[3];
-  x4 := x[4];
-  z[0] := x0 and M57;
-  z[1] := ((x0 shr 57) xor (x1 shl 7)) and M57;
-  z[2] := ((x1 shr 50) xor (x2 shl 14)) and M57;
-  z[3] := ((x2 shr 43) xor (x3 shl 21)) and M57;
-  z[4] := ((x3 shr 36) xor (x4 shl 28));
-end;
-
-class procedure TSecT283Field.ImplMultiply(const x, y,
-  zz: TCryptoLibUInt64Array);
-var
-  a, b, p: TCryptoLibUInt64Array;
-  u0, u1, u2, u3, v0, v1, v2, v3, A4, A5, B4, B5, t1, t2, t3, t4, t5, t6, t7,
-    t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22,
-    t23, t24, t25, t26, t27, t28, t29, t30, t31, t32, t33, t34, t35, t36, t37,
-    t38, t39: UInt64;
-begin
-  // /*
-  // * Formula (17) from "Some New Results on Binary Polynomial Multiplication",
-  // * Murat Cenk and M. Anwar Hasan.
-  // *
-  // * The formula as given contained an error in the term t25, as noted below
-  // */
-  System.SetLength(a, 5);
-  System.SetLength(b, 5);
-  ImplExpand(x, a);
-  ImplExpand(y, b);
-
-  System.SetLength(p, 26);
-
-  ImplMulw(a[0], b[0], p, 0); // m1
-  ImplMulw(a[1], b[1], p, 2); // m2
-  ImplMulw(a[2], b[2], p, 4); // m3
-  ImplMulw(a[3], b[3], p, 6); // m4
-  ImplMulw(a[4], b[4], p, 8); // m5
-
-  u0 := a[0] xor a[1];
-  v0 := b[0] xor b[1];
-  u1 := a[0] xor a[2];
-  v1 := b[0] xor b[2];
-  u2 := a[2] xor a[4];
-  v2 := b[2] xor b[4];
-  u3 := a[3] xor a[4];
-  v3 := b[3] xor b[4];
-
-  ImplMulw(u1 xor a[3], v1 xor b[3], p, 18); // m10
-  ImplMulw(u2 xor a[1], v2 xor b[1], p, 20); // m11
-
-  A4 := u0 xor u3;
-  B4 := v0 xor v3;
-  A5 := A4 xor a[2];
-  B5 := B4 xor b[2];
-
-  ImplMulw(A4, B4, p, 22); // m12
-  ImplMulw(A5, B5, p, 24); // m13
-
-  ImplMulw(u0, v0, p, 10); // m6
-  ImplMulw(u1, v1, p, 12); // m7
-  ImplMulw(u2, v2, p, 14); // m8
-  ImplMulw(u3, v3, p, 16); // m9
-
-
-  // Improved method factors out common single-word terms
-  // NOTE: p1,...,p26 in the paper maps to p[0],...,p[25] here
-
-  zz[0] := p[0];
-  zz[9] := p[9];
-
-  t1 := p[0] xor p[1];
-  t2 := t1 xor p[2];
-  t3 := t2 xor p[10];
-
-  zz[1] := t3;
-
-  t4 := p[3] xor p[4];
-  t5 := p[11] xor p[12];
-  t6 := t4 xor t5;
-  t7 := t2 xor t6;
-
-  zz[2] := t7;
-
-  t8 := t1 xor t4;
-  t9 := p[5] xor p[6];
-  t10 := t8 xor t9;
-  t11 := t10 xor p[8];
-  t12 := p[13] xor p[14];
-  t13 := t11 xor t12;
-  t14 := p[18] xor p[22];
-  t15 := t14 xor p[24];
-  t16 := t13 xor t15;
-
-  zz[3] := t16;
-
-  t17 := p[7] xor p[8];
-  t18 := t17 xor p[9];
-  t19 := t18 xor p[17];
-
-  zz[8] := t19;
-
-  t20 := t18 xor t9;
-  t21 := p[15] xor p[16];
-  t22 := t20 xor t21;
-
-  zz[7] := t22;
-
-  t23 := t22 xor t3;
-  t24 := p[19] xor p[20];
-  // t25 := p[23] xor  p[24];
-  t25 := p[25] xor p[24]; // Fixes an error in the paper: p[23] -> p{25]
-  t26 := p[18] xor p[23];
-  t27 := t24 xor t25;
-  t28 := t27 xor t26;
-  t29 := t28 xor t23;
-
-  zz[4] := t29;
-
-  t30 := t7 xor t19;
-  t31 := t27 xor t30;
-  t32 := p[21] xor p[22];
-  t33 := t31 xor t32;
-
-  zz[5] := t33;
-
-  t34 := t11 xor p[0];
-  t35 := t34 xor p[9];
-  t36 := t35 xor t12;
-  t37 := t36 xor p[21];
-  t38 := t37 xor p[23];
-  t39 := t38 xor p[25];
-
-  zz[6] := t39;
-
-  ImplCompactExt(zz);
-end;
-
-class procedure TSecT283Field.ImplMulw(x, y: UInt64;
-  const z: TCryptoLibUInt64Array; zOff: Int32);
-var
-  u: TCryptoLibUInt64Array;
-  j: UInt32;
-  g, h, l: UInt64;
-  k: Int32;
-begin
-{$IFDEF DEBUG}
-  System.Assert((x shr 57) = 0);
-  System.Assert((y shr 57) = 0);
-{$ENDIF DEBUG}
-  System.SetLength(u, 8);
-  // u[0] := 0;
-  u[1] := y;
-  u[2] := u[1] shl 1;
-  u[3] := u[2] xor y;
-  u[4] := u[2] shl 1;
-  u[5] := u[4] xor y;
-  u[6] := u[3] shl 1;
-  u[7] := u[6] xor y;
-
-  j := UInt32(x);
-  h := 0;
-  l := u[j and 7];
-  k := 48;
-
-  repeat
-
-    j := UInt32(x shr k);
-    g := u[j and 7] xor u[(j shr 3) and 7] shl 3 xor u[(j shr 6) and 7] shl 6;
-    l := l xor ((g shl k));
-    h := h xor TBitOperations.NegativeRightShift64(g, -k);
-
-    System.Dec(k, 9);
-  until not(k > 0);
-
-  h := h xor (((x and Int64($0100804020100800)) and
-    UInt64(TBitOperations.Asr64(Int64(y) shl 7, 63))) shr 8);
-
-{$IFDEF DEBUG}
-  System.Assert((h shr 49) = 0);
-{$ENDIF DEBUG}
-  z[zOff] := l and M57;
-  z[zOff + 1] := (l shr 57) xor (h shl 7);
-end;
-
-class procedure TSecT283Field.MultiplyAddToExt(const x, y,
-  zz: TCryptoLibUInt64Array);
-var
-  tt: TCryptoLibUInt64Array;
-begin
-  tt := TNat320.CreateExt64();
-  ImplMultiply(x, y, tt);
-  AddExt(zz, tt, zz);
-end;
-
-class procedure TSecT283Field.Reduce(const xx, z: TCryptoLibUInt64Array);
-var
-  x0, x1, x2, x3, x4, x5, x6, x7, x8, t: UInt64;
-begin
-  x0 := xx[0];
-  x1 := xx[1];
-  x2 := xx[2];
-  x3 := xx[3];
-  x4 := xx[4];
-  x5 := xx[5];
-  x6 := xx[6];
-  x7 := xx[7];
-  x8 := xx[8];
-
-  x3 := x3 xor ((x8 shl 37) xor (x8 shl 42) xor (x8 shl 44) xor (x8 shl 49));
-  x4 := x4 xor ((x8 shr 27) xor (x8 shr 22) xor (x8 shr 20) xor (x8 shr 15));
-
-  x2 := x2 xor ((x7 shl 37) xor (x7 shl 42) xor (x7 shl 44) xor (x7 shl 49));
-  x3 := x3 xor ((x7 shr 27) xor (x7 shr 22) xor (x7 shr 20) xor (x7 shr 15));
-
-  x1 := x1 xor ((x6 shl 37) xor (x6 shl 42) xor (x6 shl 44) xor (x6 shl 49));
-  x2 := x2 xor ((x6 shr 27) xor (x6 shr 22) xor (x6 shr 20) xor (x6 shr 15));
-
-  x0 := x0 xor ((x5 shl 37) xor (x5 shl 42) xor (x5 shl 44) xor (x5 shl 49));
-  x1 := x1 xor ((x5 shr 27) xor (x5 shr 22) xor (x5 shr 20) xor (x5 shr 15));
-
-  t := x4 shr 27;
-  z[0] := x0 xor t xor (t shl 5) xor (t shl 7) xor (t shl 12);
-  z[1] := x1;
-  z[2] := x2;
-  z[3] := x3;
-  z[4] := x4 and M27;
-end;
-
-class procedure TSecT283Field.Sqrt(const x, z: TCryptoLibUInt64Array);
-var
-  e0, e1, e2: UInt64;
-  odd: TCryptoLibUInt64Array;
-begin
-  odd := TNat320.Create64();
-
-  odd[0] := TInterleave.Unshuffle(x[0], x[1], e0);
-  odd[1] := TInterleave.Unshuffle(x[2], x[3], e1);
-  odd[2] := TInterleave.Unshuffle(x[4], e2);
-
-  Multiply(odd, FROOT_Z, z);
-
-  z[0] := z[0] xor e0;
-  z[1] := z[1] xor e1;
-  z[2] := z[2] xor e2;
-end;
-
-class procedure TSecT283Field.SquareAddToExt(const x,
-  zz: TCryptoLibUInt64Array);
-var
-  tt: TCryptoLibUInt64Array;
-begin
-  tt := TNat.Create64(9);
-  ImplSquare(x, tt);
-  AddExt(zz, tt, zz);
-end;
-
-class function TSecT283Field.Trace(const x: TCryptoLibUInt64Array): UInt32;
-begin
-  // Non-zero-trace bits: 0, 271
-  result := UInt32(x[0] xor (x[4] shr 15)) and UInt32(1);
-end;
-
-{ TSecT283FieldElement }
-
-function TSecT283FieldElement.Add(const b: IECFieldElement): IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.Add(Fx, (b as ISecT283FieldElement).x, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.AddOne: IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.AddOne(Fx, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-constructor TSecT283FieldElement.Create(const x: TBigInteger);
-begin
-  if ((not(x.IsInitialized)) or (x.SignValue < 0) or (x.BitLength > 283)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt
-      (@SInvalidValueForSecT283FieldElement, ['x']);
-  end;
-  Inherited Create();
-  Fx := TSecT283Field.FromBigInteger(x);
-end;
-
-constructor TSecT283FieldElement.Create;
-begin
-  Inherited Create();
-  Fx := TNat320.Create64();
-end;
-
-constructor TSecT283FieldElement.Create(const x: TCryptoLibUInt64Array);
-begin
-  Inherited Create();
-  Fx := x;
-end;
-
-function TSecT283FieldElement.Divide(const b: IECFieldElement): IECFieldElement;
-begin
-  result := Multiply(b.Invert());
-end;
-
-function TSecT283FieldElement.Equals(const AOther: ISecT283FieldElement): Boolean;
-begin
-  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 AOther: IECFieldElement): Boolean;
-var
-  LSec: ISecT283FieldElement;
-begin
-  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;
-begin
-  result := 'SecT283Field';
-end;
-
-function TSecT283FieldElement.GetFieldSize: Int32;
-begin
-  result := 283;
-end;
-
-function TSecT283FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-begin
-  result := 2831275 xor TArrayUtilities.GetArrayHashCode(Fx, 0, 5);
-end;
-
-function TSecT283FieldElement.GetIsOne: Boolean;
-begin
-  result := TNat320.IsOne64(Fx);
-end;
-
-function TSecT283FieldElement.GetIsZero: Boolean;
-begin
-  result := TNat320.IsZero64(Fx);
-end;
-
-function TSecT283FieldElement.GetK1: Int32;
-begin
-  result := 5;
-end;
-
-function TSecT283FieldElement.GetK2: Int32;
-begin
-  result := 7;
-end;
-
-function TSecT283FieldElement.GetK3: Int32;
-begin
-  result := 12;
-end;
-
-function TSecT283FieldElement.GetM: Int32;
-begin
-  result := 283;
-end;
-
-function TSecT283FieldElement.GetRepresentation: Int32;
-begin
-  result := TF2mFieldElement.Ppb;
-end;
-
-function TSecT283FieldElement.GetX: TCryptoLibUInt64Array;
-begin
-  result := Fx;
-end;
-
-function TSecT283FieldElement.HalfTrace: IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.HalfTrace(x, z);
-  result := TSecT283FieldElement.Create(z) as ISecT283FieldElement;
-end;
-
-function TSecT283FieldElement.HasFastTrace: Boolean;
-begin
-  result := true;
-end;
-
-function TSecT283FieldElement.Invert: IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.Invert(Fx, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.Multiply(const b: IECFieldElement)
-  : IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.Multiply(Fx, (b as ISecT283FieldElement).x, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.MultiplyMinusProduct(const b, x,
-  y: IECFieldElement): IECFieldElement;
-begin
-  result := MultiplyPlusProduct(b, x, y);
-end;
-
-function TSecT283FieldElement.MultiplyPlusProduct(const b, x,
-  y: IECFieldElement): IECFieldElement;
-var
-  ax, bx, xx, yx, tt, z: TCryptoLibUInt64Array;
-begin
-  ax := Fx;
-  bx := (b as ISecT283FieldElement).x;
-  xx := (x as ISecT283FieldElement).x;
-  yx := (y as ISecT283FieldElement).x;
-
-  tt := TNat.Create64(9);
-  TSecT283Field.MultiplyAddToExt(ax, bx, tt);
-  TSecT283Field.MultiplyAddToExt(xx, yx, tt);
-
-  z := TNat320.Create64();
-  TSecT283Field.Reduce(tt, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.Negate: IECFieldElement;
-begin
-  result := Self as IECFieldElement;
-end;
-
-function TSecT283FieldElement.Sqrt: IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.Sqrt(Fx, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.Square: IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  z := TNat320.Create64();
-  TSecT283Field.Square(Fx, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.SquareMinusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-begin
-  result := SquarePlusProduct(x, y);
-end;
-
-function TSecT283FieldElement.SquarePlusProduct(const x, y: IECFieldElement)
-  : IECFieldElement;
-var
-  ax, xx, yx, tt, z: TCryptoLibUInt64Array;
-begin
-  ax := Fx;
-  xx := (x as ISecT283FieldElement).x;
-  yx := (y as ISecT283FieldElement).x;
-
-  tt := TNat.Create64(9);
-  TSecT283Field.SquareAddToExt(ax, tt);
-  TSecT283Field.MultiplyAddToExt(xx, yx, tt);
-
-  z := TNat320.Create64();
-  TSecT283Field.Reduce(tt, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.SquarePow(pow: Int32): IECFieldElement;
-var
-  z: TCryptoLibUInt64Array;
-begin
-  if (pow < 1) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  z := TNat320.Create64();
-  TSecT283Field.SquareN(Fx, pow, z);
-  result := TSecT283FieldElement.Create(z);
-end;
-
-function TSecT283FieldElement.Subtract(const b: IECFieldElement)
-  : IECFieldElement;
-begin
-  // Addition and subtraction are the same in F2m
-  result := Add(b);
-end;
-
-function TSecT283FieldElement.TestBitZero: Boolean;
-begin
-  result := (Fx[0] and UInt64(1)) <> UInt64(0);
-end;
-
-function TSecT283FieldElement.ToBigInteger: TBigInteger;
-begin
-  result := TNat320.ToBigInteger64(Fx);
-end;
-
-function TSecT283FieldElement.Trace: Int32;
-begin
-  result := Int32(TSecT283Field.Trace(Fx));
-end;
-
-{ TSecT283K1Point }
-
-function TSecT283K1Point.Add(const b: IECPoint): IECPoint;
-var
-  LCurve: IECCurve;
-  x1, x2, L1, L2, z1, z2, u2, S2, u1, S1, a, LB, x3, L3, z3, Y1, Y2, l, Y3, AU1,
-    AU2, ABZ2: IECFieldElement;
-  Z1IsOne, Z2IsOne: Boolean;
-  p: IECPoint;
-begin
-  if ((IsInfinity)) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if ((b.IsInfinity)) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  LCurve := curve;
-
-  x1 := RawXCoord;
-  x2 := b.RawXCoord;
-
-  if (x1.IsZero) then
-  begin
-    if (x2.IsZero) then
-    begin
-      result := LCurve.Infinity;
-      Exit;
-    end;
-
-    result := b.Add(Self as IECPoint);
-    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);
-  LB := u1.Add(u2);
-
-  if (LB.IsZero) then
-  begin
-    if (a.IsZero) then
-    begin
-      result := Twice();
-      Exit;
-    end;
-
-    result := LCurve.Infinity;
-    Exit;
-  end;
-
-  if (x2.IsZero) then
-  begin
-    // TODO This can probably be optimized quite a bit
-    p := Self.Normalize();
-    x1 := p.XCoord;
-    Y1 := p.YCoord;
-
-    Y2 := L2;
-    l := Y1.Add(Y2).Divide(x1);
-
-    x3 := l.Square().Add(l).Add(x1);
-    if (x3.IsZero) then
-    begin
-      result := TSecT283K1Point.Create(LCurve, x3, LCurve.b, IsCompressed);
-      Exit;
-    end;
-
-    Y3 := l.Multiply(x1.Add(x3)).Add(x3).Add(Y1);
-    L3 := Y3.Divide(x3).Add(x3);
-    z3 := LCurve.FromBigInteger(TBigInteger.One);
-  end
-  else
-  begin
-    LB := LB.Square();
-
-    AU1 := a.Multiply(u1);
-    AU2 := a.Multiply(u2);
-
-    x3 := AU1.Multiply(AU2);
-    if (x3.IsZero) then
-    begin
-      result := TSecT283K1Point.Create(curve, x3, curve.b, IsCompressed);
-      Exit;
-    end;
-
-    ABZ2 := a.Multiply(LB);
-    if (not(Z2IsOne)) then
-    begin
-      ABZ2 := ABZ2.Multiply(z2);
-    end;
-
-    L3 := AU2.Add(LB).SquarePlusProduct(ABZ2, L1.Add(z1));
-
-    z3 := ABZ2;
-    if (not(Z1IsOne)) then
-    begin
-      z3 := z3.Multiply(z1);
-    end;
-  end;
-
-  result := TSecT283K1Point.Create(LCurve, x3, L3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(z3), IsCompressed);
-end;
-
-constructor TSecT283K1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
-begin
-  Create(curve, x, y, false);
-end;
-
-constructor TSecT283K1Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-constructor TSecT283K1Point.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(@SOneOfECFieldElementIsNil);
-  end;
-end;
-
-function TSecT283K1Point.Detach: IECPoint;
-begin
-  result := TSecT283K1Point.Create(Nil, AffineXCoord, AffineYCoord);
-end;
-
-function TSecT283K1Point.GetCompressionYTilde: Boolean;
-var
-  x, y: IECFieldElement;
-begin
-  x := RawXCoord;
-  if (x.IsZero) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  y := RawYCoord;
-
-  // Y is actually Lambda (X + Y/X) here
-  result := y.TestBitZero() <> x.TestBitZero();
-end;
-
-function TSecT283K1Point.GetYCoord: IECFieldElement;
-var
-  x, l, y, z: IECFieldElement;
-begin
-  x := RawXCoord;
-  l := RawYCoord;
-
-  if ((IsInfinity) or (x.IsZero)) then
-  begin
-    result := l;
-    Exit;
-  end;
-
-  // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
-  y := l.Add(x).Multiply(x);
-
-  z := RawZCoords[0];
-  if (not(z.IsOne)) then
-  begin
-    y := y.Divide(z);
-  end;
-
-  result := y;
-end;
-
-function TSecT283K1Point.Negate: IECPoint;
-var
-  x, l, z: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  x := RawXCoord;
-  if (x.IsZero) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  // L is actually Lambda (X + Y/X) here
-  l := RawYCoord;
-  z := RawZCoords[0];
-  result := TSecT283K1Point.Create(curve, x, l.Add(z),
-    TCryptoLibGenericArray<IECFieldElement>.Create(z), IsCompressed);
-end;
-
-function TSecT283K1Point.Twice: IECPoint;
-var
-  LCurve: IECCurve;
-  x1, L1, z1, Z1Sq, t, x3, z3, t1, t2, L3: IECFieldElement;
-  Z1IsOne: Boolean;
-begin
-  if ((IsInfinity)) then
-  begin
-    result := Self as IECPoint;
-    Exit;
-  end;
-
-  LCurve := Self.curve;
-
-  x1 := RawXCoord;
-  if (x1.IsZero) then
-  begin
-    // A point with X == 0 is it's own Additive inverse
-    result := LCurve.Infinity;
-    Exit;
-  end;
-
-  L1 := RawYCoord;
-  z1 := RawZCoords[0];
-
-  Z1IsOne := z1.IsOne;
-  if Z1IsOne then
-  begin
-    Z1Sq := z1;
-  end
-  else
-  begin
-    Z1Sq := z1.Square();
-  end;
-
-  if (Z1IsOne) then
-  begin
-    t := L1.Square().Add(L1);
-  end
-  else
-  begin
-    t := L1.Add(z1).Multiply(L1);
-  end;
-
-  if (t.IsZero) then
-  begin
-    result := TSecT283K1Point.Create(LCurve, t, LCurve.b, IsCompressed);
-    Exit;
-  end;
-
-  x3 := t.Square();
-  if Z1IsOne then
-  begin
-    z3 := t;
-  end
-  else
-  begin
-    z3 := t.Multiply(Z1Sq);
-  end;
-
-  t1 := L1.Add(x1).Square();
-
-  if Z1IsOne then
-  begin
-    t2 := z1;
-  end
-  else
-  begin
-    t2 := Z1Sq.Square();
-  end;
-
-  L3 := t1.Add(t).Add(Z1Sq).Multiply(t1).Add(t2).Add(x3).Add(z3);
-
-  result := TSecT283K1Point.Create(LCurve, x3, L3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(z3), IsCompressed);
-end;
-
-function TSecT283K1Point.TwicePlus(const b: IECPoint): IECPoint;
-var
-  LCurve: IECCurve;
-  x1, x2, z2, L1, z1, L2, X1Sq, L1Sq, Z1Sq, L1Z1, t, L2plus1, a, X2Z1Sq, LB, x3,
-    z3, L3: IECFieldElement;
-begin
-  if ((IsInfinity)) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  LCurve := Self.curve;
-
-  x1 := RawXCoord;
-  if (x1.IsZero) then
-  begin
-    // A point with X == 0 is it's own Additive inverse
-    result := b;
-    Exit;
-  end;
-
-  // 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 := L1Sq.Add(L1Z1);
-  L2plus1 := L2.AddOne();
-  a := L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(t, X1Sq, Z1Sq);
-  X2Z1Sq := x2.Multiply(Z1Sq);
-  LB := X2Z1Sq.Add(t).Square();
-
-  if (LB.IsZero) then
-  begin
-    if (a.IsZero) then
-    begin
-      result := b.Twice();
-      Exit;
-    end;
-
-    result := LCurve.Infinity;
-    Exit;
-  end;
-
-  if (a.IsZero) then
-  begin
-    result := TSecT283K1Point.Create(LCurve, a, LCurve.b, IsCompressed);
-    Exit;
-  end;
-
-  x3 := a.Square().Multiply(X2Z1Sq);
-  z3 := a.Multiply(LB).Multiply(Z1Sq);
-  L3 := a.Add(LB).Square().MultiplyPlusProduct(t, L2plus1, z3);
-
-  result := TSecT283K1Point.Create(LCurve, x3, L3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(z3), IsCompressed);
-end;
-
-{ TSecT283K1Curve }
-
-constructor TSecT283K1Curve.Create;
-begin
-  Inherited Create(283, 5, 7, 12);
-  Fm_infinity := TSecT283K1Point.Create(Self as IECCurve, Nil, Nil);
-
-  Fm_a := FromBigInteger(TBigInteger.Zero);
-  Fm_b := FromBigInteger(TBigInteger.One);
-  Fm_order := TBigInteger.Create(1,
-    THex.Decode
-    ('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61')
-    );
-  Fm_cofactor := TBigInteger.ValueOf(4);
-
-  Fm_coord := SECT283K1_DEFAULT_COORDS;
-end;
-
-function TSecT283K1Curve.CloneCurve: IECCurve;
-begin
-  result := TSecT283K1Curve.Create() as ISecT283K1Curve;
-end;
-
-function TSecT283K1Curve.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  table: TCryptoLibUInt64Array;
-  pos, i: Int32;
-  p: IECPoint;
-begin
-  System.SetLength(table, len * SECT283K1_FE_LONGS * 2);
-
-  pos := 0;
-  for i := 0 to System.Pred(len) do
-  begin
-    p := points[off + i];
-    TNat320.Copy64((p.RawXCoord as ISecT283FieldElement).x, 0, table, pos);
-    pos := pos + SECT283K1_FE_LONGS;
-    TNat320.Copy64((p.RawYCoord as ISecT283FieldElement).x, 0, table, pos);
-    pos := pos + SECT283K1_FE_LONGS;
-  end;
-
-  result := TSecT283K1LookupTable.Create(Self as ISecT283K1Curve, table, len);
-end;
-
-function TSecT283K1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
-begin
-  result := TSecT283K1Point.Create(Self as IECCurve, x, y, withCompression);
-end;
-
-function TSecT283K1Curve.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
-begin
-  result := TSecT283K1Point.Create(Self as IECCurve, x, y, zs, withCompression);
-end;
-
-function TSecT283K1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
-begin
-  result := TSecT283FieldElement.Create(x);
-end;
-
-function TSecT283K1Curve.GetFieldSize: Int32;
-begin
-  result := 283;
-end;
-
-function TSecT283K1Curve.GetInfinity: IECPoint;
-begin
-  result := Fm_infinity;
-end;
-
-function TSecT283K1Curve.GetIsKoblitz: Boolean;
-begin
-  result := true;
-end;
-
-function TSecT283K1Curve.GetIsTrinomial: Boolean;
-begin
-  result := false;
-end;
-
-function TSecT283K1Curve.GetK1: Int32;
-begin
-  result := 5;
-end;
-
-function TSecT283K1Curve.GetK2: Int32;
-begin
-  result := 7;
-end;
-
-function TSecT283K1Curve.GetK3: Int32;
-begin
-  result := 12;
-end;
-
-function TSecT283K1Curve.GetM: Int32;
-begin
-  result := 283;
-end;
-
-function TSecT283K1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
-begin
-  case coord of
-    TECCurveConstants.COORD_LAMBDA_PROJECTIVE:
-      result := true
-  else
-    result := false;
-  end;
-end;
-
-function TSecT283K1Curve.CreateDefaultMultiplier(): IECMultiplier;
-begin
-  result := TWTauNafMultiplier.Create() as IECMultiplier;
-end;
-
-{ TSecT283K1Curve.TSecT283K1LookupTable }
-
-constructor TSecT283K1Curve.TSecT283K1LookupTable.Create
-  (const outer: ISecT283K1Curve; const table: TCryptoLibUInt64Array;
-  size: Int32);
-begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := size;
-end;
-
-function TSecT283K1Curve.TSecT283K1LookupTable.CreatePoint(const x,
-  y: TCryptoLibUInt64Array): IECPoint;
-var
-  XFieldElement, YFieldElement: ISecT283FieldElement;
-  SECT283K1_AFFINE_ZS: TCryptoLibGenericArray<IECFieldElement>;
-begin
-  SECT283K1_AFFINE_ZS := TCryptoLibGenericArray<IECFieldElement>.Create
-    (TSecT283FieldElement.Create(TBigInteger.One) as ISecT283FieldElement);
-
-  XFieldElement := TSecT283FieldElement.Create(x);
-  YFieldElement := TSecT283FieldElement.Create(y);
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement,
-    SECT283K1_AFFINE_ZS, false);
-end;
-
-function TSecT283K1Curve.TSecT283K1LookupTable.GetSize: Int32;
-begin
-  result := Fm_size;
-end;
-
-function TSecT283K1Curve.TSecT283K1LookupTable.Lookup(index: Int32): IECPoint;
-var
-  x, y: TCryptoLibUInt64Array;
-  pos, i, j: Int32;
-  MASK: UInt64;
-begin
-  x := TNat320.Create64();
-  y := TNat320.Create64();
-  pos := 0;
-
-  for i := 0 to System.Pred(Fm_size) do
-  begin
-    MASK := UInt64(Int64(TBitOperations.Asr32((i xor index) - 1, 31)));
-
-    for j := 0 to System.Pred(SECT283K1_FE_LONGS) do
-    begin
-      x[j] := x[j] xor (Fm_table[pos + j] and MASK);
-      y[j] := y[j] xor (Fm_table[pos + SECT283K1_FE_LONGS + j] and MASK);
-    end;
-
-    pos := pos + (SECT283K1_FE_LONGS * 2);
-  end;
-
-  result := CreatePoint(x, y);
-end;
-
-function TSecT283K1Curve.TSecT283K1LookupTable.LookupVar(index: Int32)
-  : IECPoint;
-var
-  x, y: TCryptoLibUInt64Array;
-  pos, j: Int32;
-begin
-  x := TNat320.Create64();
-  y := TNat320.Create64();
-  pos := index * SECT283K1_FE_LONGS * 2;
-
-  for j := 0 to System.Pred(SECT283K1_FE_LONGS) do
-  begin
-    x[j] := Fm_table[pos + j];
-    y[j] := Fm_table[pos + SECT283K1_FE_LONGS + j];
-  end;
-
-  result := CreatePoint(x, y);
-end;
-
-end.

+ 1328 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283K1Custom.pas

@@ -0,0 +1,1328 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecT283K1Custom;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpBitOperations,
+  ClpNat,
+  ClpNat320,
+  ClpInterleave,
+  ClpEncoders,
+  ClpECCurve,
+  ClpECCurveConstants,
+  ClpECFieldElement,
+  ClpECPoint,
+  ClpECLookupTables,
+  ClpMultipliers,
+  ClpIECCore,
+  ClpIECFieldElement,
+  ClpISecT283K1Custom,
+  ClpArrayUtilities,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidSecT283FieldElement = 'value invalid for SecT283FieldElement';
+
+type
+  TSecT283Field = class sealed(TObject)
+  strict private
+  const
+    M27: UInt64 = UInt64.MaxValue shr 37;
+    M57: UInt64 = UInt64.MaxValue shr 7;
+  class var
+    FRootZ: TCryptoLibUInt64Array;
+  class procedure Boot; static;
+  class procedure ImplCompactExt(const AZz: TCryptoLibUInt64Array); static;
+  class procedure ImplExpand(const AX: TCryptoLibUInt64Array;
+    const AZ: TCryptoLibUInt64Array); static;
+  class procedure ImplMulw(const AU: TCryptoLibUInt64Array; AX, AY: UInt64;
+    const AZ: TCryptoLibUInt64Array; AZOff: Int32); static;
+  class procedure ImplMultiply(const AX, AY, AZZ: TCryptoLibUInt64Array); static;
+  class procedure ImplSquare(const AX, AZZ: TCryptoLibUInt64Array); static;
+  class constructor Create;
+  public
+    class procedure Add(const AX, AY, AZ: TCryptoLibUInt64Array); static;
+    class procedure AddBothTo(const AX, AY, AZ: TCryptoLibUInt64Array); static;
+    class procedure AddExt(const AXX, AYY, AZZ: TCryptoLibUInt64Array); static;
+    class procedure AddOne(const AX, AZ: TCryptoLibUInt64Array); static;
+    class procedure AddTo(const AX, AZ: TCryptoLibUInt64Array); static;
+    class function FromBigInteger(const AX: TBigInteger): TCryptoLibUInt64Array; static;
+    class procedure HalfTrace(const AX, AZ: TCryptoLibUInt64Array); static;
+    class procedure Invert(const AX, AZ: TCryptoLibUInt64Array); static;
+    class procedure Multiply(const AX, AY, AZ: TCryptoLibUInt64Array); static;
+    class procedure MultiplyAddToExt(const AX, AY, AZZ: TCryptoLibUInt64Array); static;
+    class procedure MultiplyExt(const AX, AY, AZZ: TCryptoLibUInt64Array); static;
+    class procedure Reduce(const AXX, AZ: TCryptoLibUInt64Array); static;
+    class procedure Reduce37(const AZ: TCryptoLibUInt64Array; AZOff: Int32); static;
+    class procedure Sqrt(const AX, AZ: TCryptoLibUInt64Array); static;
+    class procedure Square(const AX, AZ: TCryptoLibUInt64Array); static;
+    class procedure SquareAddToExt(const AX, AZZ: TCryptoLibUInt64Array); static;
+    class procedure SquareExt(const AX, AZZ: TCryptoLibUInt64Array); static;
+    class procedure SquareN(const AX: TCryptoLibUInt64Array; AN: Int32;
+      const AZ: TCryptoLibUInt64Array); static;
+    class function Trace(const AX: TCryptoLibUInt64Array): UInt32; static;
+  end;
+
+type
+  TSecT283FieldElement = class sealed(TAbstractF2mFieldElement,
+    IAbstractF2mFieldElement, IECFieldElement, ISecT283FieldElement)
+  strict private
+    FX: TCryptoLibUInt64Array;
+    function GetX: TCryptoLibUInt64Array; inline;
+  public
+    constructor Create(const AX: TBigInteger); overload;
+    constructor Create(); overload;
+    constructor Create(const AX: TCryptoLibUInt64Array); overload;
+
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+    function ToBigInteger: TBigInteger; override;
+    function TestBitZero: Boolean; 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 HalfTrace: IECFieldElement; override;
+    function GetHasFastTrace: Boolean; override;
+    function Trace: Int32; override;
+    function Invert: IECFieldElement; override;
+    function Sqrt: IECFieldElement; override;
+
+    function GetRepresentation: Int32;
+    function GetM: Int32;
+    function GetK1: Int32;
+    function GetK2: Int32;
+    function GetK3: Int32;
+
+    function Equals(const AOther: IECFieldElement): Boolean; override;
+    function GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI} override;
+
+    property X: TCryptoLibUInt64Array read GetX;
+  end;
+
+type
+  TSecT283K1Point = class sealed(TAbstractF2mPoint, IAbstractF2mPoint, IECPoint,
+    ISecT283K1Point)
+  strict protected
+    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 Detach: IECPoint; override;
+
+    function Add(const AB: IECPoint): IECPoint; override;
+    function Twice: IECPoint; override;
+    function TwicePlus(const AB: IECPoint): IECPoint; override;
+    function Negate: IECPoint; override;
+  end;
+
+type
+  TSecT283K1Curve = class sealed(TAbstractF2mCurve, IAbstractF2mCurve, IECCurve,
+    ISecT283K1Curve)
+  strict private
+  const
+    SECT283K1_DEFAULT_COORDS = TECCurveConstants.COORD_LAMBDA_PROJECTIVE;
+    SECT283K1_FE_LONGS = 5;
+  strict private
+  type
+    TSecT283K1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable,
+      ISecT283K1LookupTable)
+    strict private
+      FOuter: ISecT283K1Curve;
+      FTable: TCryptoLibUInt64Array;
+      FSize: Int32;
+      function CreatePoint(const AX, AY: TCryptoLibUInt64Array): IECPoint;
+    public
+      constructor Create(const AOuter: ISecT283K1Curve;
+        const ATable: TCryptoLibUInt64Array; ASize: Int32);
+      function GetSize: Int32; override;
+      function Lookup(AIndex: Int32): IECPoint; override;
+      function LookupVar(AIndex: Int32): IECPoint; override;
+    end;
+  class var
+    FSecT283K1AffineZs: TCryptoLibGenericArray<IECFieldElement>;
+  class procedure Boot; static;
+  class constructor Create;
+  var
+    FInfinity: TSecT283K1Point;
+  strict protected
+    function GetIsKoblitz: Boolean; override;
+    function CreateDefaultMultiplier: IECMultiplier; override;
+  public
+    constructor Create;
+
+    function CloneCurve: IECCurve; override;
+    function GetFieldSize: Int32; override;
+    function GetInfinity: IECPoint; override;
+    function FromBigInteger(const AX: TBigInteger): IECFieldElement; override;
+    function CreateRawPoint(const AX, AY: IECFieldElement): IECPoint; override;
+    function CreateRawPoint(const AX, 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 GetM: Int32;
+    function GetIsTrinomial: Boolean;
+    function GetK1: Int32;
+    function GetK2: Int32;
+    function GetK3: Int32;
+
+    class property SecT283K1AffineZs: TCryptoLibGenericArray<IECFieldElement> read FSecT283K1AffineZs;
+  end;
+
+implementation
+
+{ TSecT283Field }
+
+class procedure TSecT283Field.Boot;
+begin
+  FRootZ := TCryptoLibUInt64Array.Create($0C30C30C30C30808, $30C30C30C30C30C3,
+    $820820820820830C, $0820820820820820, $2082082);
+end;
+
+class constructor TSecT283Field.Create;
+begin
+  Boot;
+end;
+
+class procedure TSecT283Field.ImplCompactExt(const AZz: TCryptoLibUInt64Array);
+var
+  LZ0, LZ1, LZ2, LZ3, LZ4, LZ5, LZ6, LZ7, LZ8, LZ9: UInt64;
+begin
+  LZ0 := AZz[0]; LZ1 := AZz[1]; LZ2 := AZz[2]; LZ3 := AZz[3]; LZ4 := AZz[4];
+  LZ5 := AZz[5]; LZ6 := AZz[6]; LZ7 := AZz[7]; LZ8 := AZz[8]; LZ9 := AZz[9];
+  AZz[0] := LZ0 xor (LZ1 shl 57);
+  AZz[1] := (LZ1 shr 7) xor (LZ2 shl 50);
+  AZz[2] := (LZ2 shr 14) xor (LZ3 shl 43);
+  AZz[3] := (LZ3 shr 21) xor (LZ4 shl 36);
+  AZz[4] := (LZ4 shr 28) xor (LZ5 shl 29);
+  AZz[5] := (LZ5 shr 35) xor (LZ6 shl 22);
+  AZz[6] := (LZ6 shr 42) xor (LZ7 shl 15);
+  AZz[7] := (LZ7 shr 49) xor (LZ8 shl 8);
+  AZz[8] := (LZ8 shr 56) xor (LZ9 shl 1);
+  AZz[9] := (LZ9 shr 63);
+end;
+
+class procedure TSecT283Field.ImplExpand(const AX: TCryptoLibUInt64Array;
+  const AZ: TCryptoLibUInt64Array);
+var
+  LX0, LX1, LX2, LX3, LX4: UInt64;
+begin
+  LX0 := AX[0]; LX1 := AX[1]; LX2 := AX[2]; LX3 := AX[3]; LX4 := AX[4];
+  AZ[0] := LX0 and M57;
+  AZ[1] := ((LX0 shr 57) xor (LX1 shl 7)) and M57;
+  AZ[2] := ((LX1 shr 50) xor (LX2 shl 14)) and M57;
+  AZ[3] := ((LX2 shr 43) xor (LX3 shl 21)) and M57;
+  AZ[4] := (LX3 shr 36) xor (LX4 shl 28);
+end;
+
+class procedure TSecT283Field.ImplMulw(const AU: TCryptoLibUInt64Array; AX, AY: UInt64;
+  const AZ: TCryptoLibUInt64Array; AZOff: Int32);
+var
+  LJ: UInt32;
+  LG, LH, LL: UInt64;
+  LK: Int32;
+begin
+  {$IFDEF DEBUG}
+  Assert(AX shr 57 = 0);
+  Assert(AY shr 57 = 0);
+  {$ENDIF DEBUG}
+  AU[1] := AY;
+  AU[2] := AU[1] shl 1;
+  AU[3] := AU[2] xor AY;
+  AU[4] := AU[2] shl 1;
+  AU[5] := AU[4] xor AY;
+  AU[6] := AU[3] shl 1;
+  AU[7] := AU[6] xor AY;
+
+  LJ := UInt32(AX);
+  LH := 0;
+  LL := AU[Int32(LJ) and 7];
+  LK := 48;
+  repeat
+    LJ := UInt32(AX shr LK);
+    LG := AU[Int32(LJ) and 7]
+      xor (AU[Int32(LJ shr 3) and 7] shl 3)
+      xor (AU[Int32(LJ shr 6) and 7] shl 6);
+    LL := LL xor (LG shl LK);
+    LH := LH xor (UInt64(Int64(LG) shr (64 - LK)));
+    Dec(LK, 9);
+  until LK <= 0;
+
+  LH := LH xor ((UInt64(TBitOperations.Asr64(Int64(AY) shl 7, 63)) and (AX and $0100804020100800)) shr 8);
+
+  {$IFDEF DEBUG}
+  Assert(LH shr 49 = 0);
+  {$ENDIF DEBUG}
+  AZ[AZOff] := LL and M57;
+  AZ[AZOff + 1] := (LL shr 57) xor (LH shl 7);
+end;
+
+class procedure TSecT283Field.ImplMultiply(const AX, AY, AZZ: TCryptoLibUInt64Array);
+var
+  LA, LB: TCryptoLibUInt64Array;
+  LP: TCryptoLibUInt64Array;
+  LU0, LV0, LU1, LV1, LU2, LV2, LU3, LV3, LA4, LB4, LA5, LB5: UInt64;
+  LT1, LT2, LT3, LT4, LT5, LT6, LT7, LT8, LT9, LT10, LT11, LT12, LT13, LT14, LT15, LT16: UInt64;
+  LT17, LT18, LT19, LT20, LT21, LT22, LT23, LT24, LT25, LT26, LT27, LT28, LT29: UInt64;
+  LT30, LT31, LT32, LT33, LT34, LT35, LT36, LT37, LT38, LT39: UInt64;
+  LI: Int32;
+begin
+  SetLength(LA, 5);
+  SetLength(LB, 5);
+  SetLength(LP, 26);
+  ImplExpand(AX, LA);
+  ImplExpand(AY, LB);
+
+  for LI := 0 to 9 do
+    AZZ[LI] := 0;
+
+  ImplMulw(AZZ, LA[0], LB[0], LP, 0);
+  ImplMulw(AZZ, LA[1], LB[1], LP, 2);
+  ImplMulw(AZZ, LA[2], LB[2], LP, 4);
+  ImplMulw(AZZ, LA[3], LB[3], LP, 6);
+  ImplMulw(AZZ, LA[4], LB[4], LP, 8);
+
+  LU0 := LA[0] xor LA[1]; LV0 := LB[0] xor LB[1];
+  LU1 := LA[0] xor LA[2]; LV1 := LB[0] xor LB[2];
+  LU2 := LA[2] xor LA[4]; LV2 := LB[2] xor LB[4];
+  LU3 := LA[3] xor LA[4]; LV3 := LB[3] xor LB[4];
+
+  ImplMulw(AZZ, LU1 xor LA[3], LV1 xor LB[3], LP, 18);
+  ImplMulw(AZZ, LU2 xor LA[1], LV2 xor LB[1], LP, 20);
+
+  LA4 := LU0 xor LU3; LB4 := LV0 xor LV3;
+  LA5 := LA4 xor LA[2]; LB5 := LB4 xor LB[2];
+
+  ImplMulw(AZZ, LA4, LB4, LP, 22);
+  ImplMulw(AZZ, LA5, LB5, LP, 24);
+
+  ImplMulw(AZZ, LU0, LV0, LP, 10);
+  ImplMulw(AZZ, LU1, LV1, LP, 12);
+  ImplMulw(AZZ, LU2, LV2, LP, 14);
+  ImplMulw(AZZ, LU3, LV3, LP, 16);
+
+  AZZ[0] := LP[0];
+  AZZ[9] := LP[9];
+
+  LT1 := LP[0] xor LP[1];
+  LT2 := LT1 xor LP[2];
+  LT3 := LT2 xor LP[10];
+  AZZ[1] := LT3;
+
+  LT4 := LP[3] xor LP[4];
+  LT5 := LP[11] xor LP[12];
+  LT6 := LT4 xor LT5;
+  LT7 := LT2 xor LT6;
+  AZZ[2] := LT7;
+
+  LT8 := LT1 xor LT4;
+  LT9 := LP[5] xor LP[6];
+  LT10 := LT8 xor LT9;
+  LT11 := LT10 xor LP[8];
+  LT12 := LP[13] xor LP[14];
+  LT13 := LT11 xor LT12;
+  LT14 := LP[18] xor LP[22];
+  LT15 := LT14 xor LP[24];
+  LT16 := LT13 xor LT15;
+  AZZ[3] := LT16;
+
+  LT17 := LP[7] xor LP[8];
+  LT18 := LT17 xor LP[9];
+  LT19 := LT18 xor LP[17];
+  AZZ[8] := LT19;
+
+  LT20 := LT18 xor LT9;
+  LT21 := LP[15] xor LP[16];
+  LT22 := LT20 xor LT21;
+  AZZ[7] := LT22;
+
+  LT23 := LT22 xor LT3;
+  LT24 := LP[19] xor LP[20];
+  LT25 := LP[25] xor LP[24];
+  LT26 := LP[18] xor LP[23];
+  LT27 := LT24 xor LT25;
+  LT28 := LT27 xor LT26;
+  LT29 := LT28 xor LT23;
+  AZZ[4] := LT29;
+
+  LT30 := LT7 xor LT19;
+  LT31 := LT27 xor LT30;
+  LT32 := LP[21] xor LP[22];
+  LT33 := LT31 xor LT32;
+  AZZ[5] := LT33;
+
+  LT34 := LT11 xor LP[0];
+  LT35 := LT34 xor LP[9];
+  LT36 := LT35 xor LT12;
+  LT37 := LT36 xor LP[21];
+  LT38 := LT37 xor LP[23];
+  LT39 := LT38 xor LP[25];
+  AZZ[6] := LT39;
+
+  ImplCompactExt(AZZ);
+end;
+
+class procedure TSecT283Field.ImplSquare(const AX, AZZ: TCryptoLibUInt64Array);
+begin
+  TInterleave.Expand64To128(AX, 0, 4, AZZ, 0);
+  AZZ[8] := TInterleave.Expand32to64(UInt32(AX[4]));
+end;
+
+class procedure TSecT283Field.Add(const AX, AY, AZ: TCryptoLibUInt64Array);
+begin
+  AZ[0] := AX[0] xor AY[0];
+  AZ[1] := AX[1] xor AY[1];
+  AZ[2] := AX[2] xor AY[2];
+  AZ[3] := AX[3] xor AY[3];
+  AZ[4] := AX[4] xor AY[4];
+end;
+
+class procedure TSecT283Field.AddBothTo(const AX, AY, AZ: TCryptoLibUInt64Array);
+begin
+  AZ[0] := AZ[0] xor AX[0] xor AY[0];
+  AZ[1] := AZ[1] xor AX[1] xor AY[1];
+  AZ[2] := AZ[2] xor AX[2] xor AY[2];
+  AZ[3] := AZ[3] xor AX[3] xor AY[3];
+  AZ[4] := AZ[4] xor AX[4] xor AY[4];
+end;
+
+class procedure TSecT283Field.AddExt(const AXX, AYY, AZZ: TCryptoLibUInt64Array);
+begin
+  AZZ[0] := AXX[0] xor AYY[0];
+  AZZ[1] := AXX[1] xor AYY[1];
+  AZZ[2] := AXX[2] xor AYY[2];
+  AZZ[3] := AXX[3] xor AYY[3];
+  AZZ[4] := AXX[4] xor AYY[4];
+  AZZ[5] := AXX[5] xor AYY[5];
+  AZZ[6] := AXX[6] xor AYY[6];
+  AZZ[7] := AXX[7] xor AYY[7];
+  AZZ[8] := AXX[8] xor AYY[8];
+end;
+
+class procedure TSecT283Field.AddOne(const AX, AZ: TCryptoLibUInt64Array);
+begin
+  AZ[0] := AX[0] xor 1;
+  AZ[1] := AX[1];
+  AZ[2] := AX[2];
+  AZ[3] := AX[3];
+  AZ[4] := AX[4];
+end;
+
+class procedure TSecT283Field.AddTo(const AX, AZ: TCryptoLibUInt64Array);
+begin
+  AZ[0] := AZ[0] xor AX[0];
+  AZ[1] := AZ[1] xor AX[1];
+  AZ[2] := AZ[2] xor AX[2];
+  AZ[3] := AZ[3] xor AX[3];
+  AZ[4] := AZ[4] xor AX[4];
+end;
+
+class function TSecT283Field.FromBigInteger(const AX: TBigInteger): TCryptoLibUInt64Array;
+begin
+  Result := TNat.FromBigInteger64(283, AX);
+end;
+
+class procedure TSecT283Field.HalfTrace(const AX, AZ: TCryptoLibUInt64Array);
+var
+  LTT: TCryptoLibUInt64Array;
+  LI: Int32;
+begin
+  LTT := TNat.Create64(9);
+  TNat320.Copy64(AX, AZ);
+  LI := 1;
+  while LI < 283 do
+  begin
+    ImplSquare(AZ, LTT);
+    Reduce(LTT, AZ);
+    ImplSquare(AZ, LTT);
+    Reduce(LTT, AZ);
+    AddTo(AX, AZ);
+    Inc(LI, 2);
+  end;
+end;
+
+class procedure TSecT283Field.Invert(const AX, AZ: TCryptoLibUInt64Array);
+var
+  LT0, LT1: TCryptoLibUInt64Array;
+begin
+  if TNat320.IsZero64(AX) then
+    raise EInvalidOperationCryptoLibException.Create('');
+  SetLength(LT0, 5);
+  SetLength(LT1, 5);
+  Square(AX, LT0);
+  Multiply(LT0, AX, LT0);
+  SquareN(LT0, 2, LT1);
+  Multiply(LT1, LT0, LT1);
+  SquareN(LT1, 4, LT0);
+  Multiply(LT0, LT1, LT0);
+  SquareN(LT0, 8, LT1);
+  Multiply(LT1, LT0, LT1);
+  Square(LT1, LT1);
+  Multiply(LT1, AX, LT1);
+  SquareN(LT1, 17, LT0);
+  Multiply(LT0, LT1, LT0);
+  Square(LT0, LT0);
+  Multiply(LT0, AX, LT0);
+  SquareN(LT0, 35, LT1);
+  Multiply(LT1, LT0, LT1);
+  SquareN(LT1, 70, LT0);
+  Multiply(LT0, LT1, LT0);
+  Square(LT0, LT0);
+  Multiply(LT0, AX, LT0);
+  SquareN(LT0, 141, LT1);
+  Multiply(LT1, LT0, LT1);
+  Square(LT1, AZ);
+end;
+
+class procedure TSecT283Field.Multiply(const AX, AY, AZ: TCryptoLibUInt64Array);
+var
+  LTT: TCryptoLibUInt64Array;
+begin
+  LTT := TNat320.CreateExt64();
+  ImplMultiply(AX, AY, LTT);
+  Reduce(LTT, AZ);
+end;
+
+class procedure TSecT283Field.MultiplyAddToExt(const AX, AY, AZZ: TCryptoLibUInt64Array);
+var
+  LTT: TCryptoLibUInt64Array;
+begin
+  LTT := TNat320.CreateExt64();
+  ImplMultiply(AX, AY, LTT);
+  AddExt(AZZ, LTT, AZZ);
+end;
+
+class procedure TSecT283Field.MultiplyExt(const AX, AY, AZZ: TCryptoLibUInt64Array);
+var
+  LI: Int32;
+begin
+  for LI := 0 to 9 do
+    AZZ[LI] := 0;
+  ImplMultiply(AX, AY, AZZ);
+end;
+
+class procedure TSecT283Field.Reduce(const AXX, AZ: TCryptoLibUInt64Array);
+var
+  LX0, LX1, LX2, LX3, LX4, LX5, LX6, LX7, LX8: UInt64;
+  LT: UInt64;
+begin
+  LX0 := AXX[0]; LX1 := AXX[1]; LX2 := AXX[2]; LX3 := AXX[3]; LX4 := AXX[4];
+  LX5 := AXX[5]; LX6 := AXX[6]; LX7 := AXX[7]; LX8 := AXX[8];
+
+  LX3 := LX3 xor (LX8 shl 37) xor (LX8 shl 42) xor (LX8 shl 44) xor (LX8 shl 49);
+  LX4 := LX4 xor (LX8 shr 27) xor (LX8 shr 22) xor (LX8 shr 20) xor (LX8 shr 15);
+
+  LX2 := LX2 xor (LX7 shl 37) xor (LX7 shl 42) xor (LX7 shl 44) xor (LX7 shl 49);
+  LX3 := LX3 xor (LX7 shr 27) xor (LX7 shr 22) xor (LX7 shr 20) xor (LX7 shr 15);
+
+  LX1 := LX1 xor (LX6 shl 37) xor (LX6 shl 42) xor (LX6 shl 44) xor (LX6 shl 49);
+  LX2 := LX2 xor (LX6 shr 27) xor (LX6 shr 22) xor (LX6 shr 20) xor (LX6 shr 15);
+
+  LX0 := LX0 xor (LX5 shl 37) xor (LX5 shl 42) xor (LX5 shl 44) xor (LX5 shl 49);
+  LX1 := LX1 xor (LX5 shr 27) xor (LX5 shr 22) xor (LX5 shr 20) xor (LX5 shr 15);
+
+  LT := LX4 shr 27;
+  AZ[0] := LX0 xor LT xor (LT shl 5) xor (LT shl 7) xor (LT shl 12);
+  AZ[1] := LX1;
+  AZ[2] := LX2;
+  AZ[3] := LX3;
+  AZ[4] := LX4 and M27;
+end;
+
+class procedure TSecT283Field.Reduce37(const AZ: TCryptoLibUInt64Array; AZOff: Int32);
+var
+  LZ4: UInt64;
+  LT: UInt64;
+begin
+  LZ4 := AZ[AZOff + 4];
+  LT := LZ4 shr 27;
+  AZ[AZOff] := AZ[AZOff] xor LT xor (LT shl 5) xor (LT shl 7) xor (LT shl 12);
+  AZ[AZOff + 4] := LZ4 and M27;
+end;
+
+class procedure TSecT283Field.Sqrt(const AX, AZ: TCryptoLibUInt64Array);
+var
+  LOdd: TCryptoLibUInt64Array;
+  LE0, LE1, LE2: UInt64;
+begin
+  LOdd := TNat320.Create64();
+  LOdd[0] := TInterleave.Unshuffle(AX[0], AX[1], LE0);
+  LOdd[1] := TInterleave.Unshuffle(AX[2], AX[3], LE1);
+  LOdd[2] := UInt64(TInterleave.Unshuffle(AX[4], LE2));
+  Multiply(LOdd, FRootZ, AZ);
+  AZ[0] := AZ[0] xor LE0;
+  AZ[1] := AZ[1] xor LE1;
+  AZ[2] := AZ[2] xor LE2;
+end;
+
+class procedure TSecT283Field.Square(const AX, AZ: TCryptoLibUInt64Array);
+var
+  LTT: TCryptoLibUInt64Array;
+begin
+  LTT := TNat.Create64(9);
+  ImplSquare(AX, LTT);
+  Reduce(LTT, AZ);
+end;
+
+class procedure TSecT283Field.SquareAddToExt(const AX, AZZ: TCryptoLibUInt64Array);
+var
+  LTT: TCryptoLibUInt64Array;
+begin
+  LTT := TNat.Create64(9);
+  ImplSquare(AX, LTT);
+  AddExt(AZZ, LTT, AZZ);
+end;
+
+class procedure TSecT283Field.SquareExt(const AX, AZZ: TCryptoLibUInt64Array);
+begin
+  ImplSquare(AX, AZZ);
+end;
+
+class procedure TSecT283Field.SquareN(const AX: TCryptoLibUInt64Array; AN: Int32;
+  const AZ: TCryptoLibUInt64Array);
+var
+  LTT: TCryptoLibUInt64Array;
+begin
+  {$IFDEF DEBUG}
+  Assert(AN > 0);
+  {$ENDIF DEBUG}
+  LTT := TNat.Create64(9);
+  ImplSquare(AX, LTT);
+  Reduce(LTT, AZ);
+  Dec(AN);
+  while AN > 0 do
+  begin
+    ImplSquare(AZ, LTT);
+    Reduce(LTT, AZ);
+    Dec(AN);
+  end;
+end;
+
+class function TSecT283Field.Trace(const AX: TCryptoLibUInt64Array): UInt32;
+begin
+  Result := UInt32(AX[0] xor (AX[4] shr 15)) and 1;
+end;
+
+{ TSecT283FieldElement }
+
+constructor TSecT283FieldElement.Create(const AX: TBigInteger);
+begin
+  Inherited Create;
+  if (not AX.IsInitialized) or (AX.SignValue < 0) or (AX.BitLength > 283) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidSecT283FieldElement);
+  FX := TSecT283Field.FromBigInteger(AX);
+end;
+
+constructor TSecT283FieldElement.Create();
+begin
+  Inherited Create;
+  FX := TNat320.Create64();
+end;
+
+constructor TSecT283FieldElement.Create(const AX: TCryptoLibUInt64Array);
+begin
+  Inherited Create;
+  FX := AX;
+end;
+
+function TSecT283FieldElement.GetX: TCryptoLibUInt64Array;
+begin
+  Result := FX;
+end;
+
+function TSecT283FieldElement.GetFieldName: String;
+begin
+  Result := 'SecT283Field';
+end;
+
+function TSecT283FieldElement.GetFieldSize: Int32;
+begin
+  Result := 283;
+end;
+
+function TSecT283FieldElement.GetIsOne: Boolean;
+begin
+  Result := TNat320.IsOne64(FX);
+end;
+
+function TSecT283FieldElement.GetIsZero: Boolean;
+begin
+  Result := TNat320.IsZero64(FX);
+end;
+
+function TSecT283FieldElement.ToBigInteger: TBigInteger;
+begin
+  Result := TNat320.ToBigInteger64(FX);
+end;
+
+function TSecT283FieldElement.TestBitZero: Boolean;
+begin
+  Result := (FX[0] and 1) <> 0;
+end;
+
+function TSecT283FieldElement.Add(const AB: IECFieldElement): IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.Add(FX, (AB as ISecT283FieldElement).X, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.AddOne: IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.AddOne(FX, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.Subtract(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := Add(AB);
+end;
+
+function TSecT283FieldElement.Multiply(const AB: IECFieldElement): IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.Multiply(FX, (AB as ISecT283FieldElement).X, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.MultiplyMinusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := MultiplyPlusProduct(AB, AX, AY);
+end;
+
+function TSecT283FieldElement.MultiplyPlusProduct(const AB, AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAX, LBX, LXX, LYX: TCryptoLibUInt64Array;
+  LTT: TCryptoLibUInt64Array;
+  LZ: TCryptoLibUInt64Array;
+begin
+  LAX := FX;
+  LBX := (AB as ISecT283FieldElement).X;
+  LXX := (AX as ISecT283FieldElement).X;
+  LYX := (AY as ISecT283FieldElement).X;
+  LTT := TNat.Create64(9);
+  TSecT283Field.MultiplyAddToExt(LAX, LBX, LTT);
+  TSecT283Field.MultiplyAddToExt(LXX, LYX, LTT);
+  LZ := TNat320.Create64();
+  TSecT283Field.Reduce(LTT, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.Divide(const AB: IECFieldElement): IECFieldElement;
+begin
+  Result := Multiply(AB.Invert());
+end;
+
+function TSecT283FieldElement.Negate: IECFieldElement;
+begin
+  Result := Self as IECFieldElement;
+end;
+
+function TSecT283FieldElement.Square: IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.Square(FX, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.SquareMinusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+begin
+  Result := SquarePlusProduct(AX, AY);
+end;
+
+function TSecT283FieldElement.SquarePlusProduct(const AX, AY: IECFieldElement): IECFieldElement;
+var
+  LAX, LXX, LYX: TCryptoLibUInt64Array;
+  LTT: TCryptoLibUInt64Array;
+  LZ: TCryptoLibUInt64Array;
+begin
+  LAX := FX;
+  LXX := (AX as ISecT283FieldElement).X;
+  LYX := (AY as ISecT283FieldElement).X;
+  LTT := TNat.Create64(9);
+  TSecT283Field.SquareExt(LAX, LTT);
+  TSecT283Field.MultiplyAddToExt(LXX, LYX, LTT);
+  LZ := TNat320.Create64();
+  TSecT283Field.Reduce(LTT, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.SquarePow(APow: Int32): IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  if APow < 1 then
+    Exit(Self as IECFieldElement);
+  LZ := TNat320.Create64();
+  TSecT283Field.SquareN(FX, APow, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.HalfTrace: IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.HalfTrace(FX, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.GetHasFastTrace: Boolean;
+begin
+  Result := True;
+end;
+
+function TSecT283FieldElement.Trace: Int32;
+begin
+  Result := Int32(TSecT283Field.Trace(FX));
+end;
+
+function TSecT283FieldElement.Invert: IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.Invert(FX, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.Sqrt: IECFieldElement;
+var
+  LZ: TCryptoLibUInt64Array;
+begin
+  LZ := TNat320.Create64();
+  TSecT283Field.Sqrt(FX, LZ);
+  Result := TSecT283FieldElement.Create(LZ);
+end;
+
+function TSecT283FieldElement.GetRepresentation: Int32;
+begin
+  Result := TF2mFieldElement.Ppb;
+end;
+
+function TSecT283FieldElement.GetM: Int32;
+begin
+  Result := 283;
+end;
+
+function TSecT283FieldElement.GetK1: Int32;
+begin
+  Result := 5;
+end;
+
+function TSecT283FieldElement.GetK2: Int32;
+begin
+  Result := 7;
+end;
+
+function TSecT283FieldElement.GetK3: Int32;
+begin
+  Result := 12;
+end;
+
+function TSecT283FieldElement.Equals(const AOther: IECFieldElement): Boolean;
+begin
+  if (Self as IECFieldElement) = AOther then
+    Exit(True);
+  if AOther = nil then
+    Exit(False);
+  Result := TNat320.Eq64(FX, (AOther as ISecT283FieldElement).X);
+end;
+
+function TSecT283FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt; {$ENDIF DELPHI}
+begin
+  Result := 2831275 xor TArrayUtilities.GetArrayHashCode(FX, 0, 5);
+end;
+
+{ TSecT283K1Point }
+
+constructor TSecT283K1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement);
+begin
+  Inherited Create(ACurve, AX, AY);
+end;
+
+constructor TSecT283K1Point.Create(const ACurve: IECCurve; const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>);
+begin
+  Inherited Create(ACurve, AX, AY, AZs);
+end;
+
+function TSecT283K1Point.GetYCoord: IECFieldElement;
+var
+  LX, LL, LZ: IECFieldElement;
+  LY: IECFieldElement;
+begin
+  LX := RawXCoord;
+  LL := RawYCoord;
+  if IsInfinity or LX.IsZero then
+    Exit(LL);
+  LY := LL.Add(LX).Multiply(LX);
+  LZ := RawZCoords[0];
+  if not LZ.IsOne then
+    LY := LY.Divide(LZ);
+  Result := LY;
+end;
+
+function TSecT283K1Point.GetCompressionYTilde: Boolean;
+var
+  LX, LY: IECFieldElement;
+begin
+  LX := RawXCoord;
+  if LX.IsZero then
+    Exit(False);
+  LY := RawYCoord;
+  Result := LY.TestBitZero <> LX.TestBitZero;
+end;
+
+function TSecT283K1Point.Detach: IECPoint;
+begin
+  Result := TSecT283K1Point.Create(nil, AffineXCoord, AffineYCoord);
+end;
+
+function TSecT283K1Point.Add(const AB: IECPoint): IECPoint;
+var
+  LCurve: IECCurve;
+  LX1, LX2: ISecT283FieldElement;
+  LL1, LZ1, LL2, LZ2: ISecT283FieldElement;
+  LTT0: TCryptoLibUInt64Array;
+  LT1, LT2, LT3: TCryptoLibUInt64Array;
+  LZ1IsOne, LZ2IsOne: Boolean;
+  LU2, LS2, LU1, LS1: TCryptoLibUInt64Array;
+  LA, LB: TCryptoLibUInt64Array;
+  LX3Arr, LZ3Arr, LL3Arr: TCryptoLibUInt64Array;
+  LX3, LL3, LZ3: ISecT283FieldElement;
+  LZs: TCryptoLibGenericArray<IECFieldElement>;
+  LNorm: IECPoint;
+  LY1, LY2, LL, LX3Fe, LY3Fe, LZ3Fe: IECFieldElement;
+begin
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Self as IECPoint);
+
+  LCurve := Curve;
+  LX1 := RawXCoord as ISecT283FieldElement;
+  LX2 := AB.RawXCoord as ISecT283FieldElement;
+
+  if LX1.IsZero then
+  begin
+    if LX2.IsZero then
+      Exit(LCurve.Infinity);
+    Exit(AB.Add(Self as IECPoint));
+  end;
+
+  LL1 := RawYCoord as ISecT283FieldElement;
+  LZ1 := RawZCoords[0] as ISecT283FieldElement;
+  LL2 := AB.RawYCoord as ISecT283FieldElement;
+  LZ2 := AB.GetZCoord(0) as ISecT283FieldElement;
+
+  LTT0 := TNat.Create64(9);
+  LT1 := TNat320.Create64();
+  LT2 := TNat320.Create64();
+  LT3 := TNat320.Create64();
+
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
+  begin
+    TNat320.Copy64(LX2.X, LT1);
+    TNat320.Copy64(LL2.X, LT2);
+  end
+  else
+  begin
+    TSecT283Field.Multiply(LX2.X, LZ1.X, LT1);
+    TSecT283Field.Multiply(LL2.X, LZ1.X, LT2);
+  end;
+
+  LZ2IsOne := LZ2.IsOne;
+  if LZ2IsOne then
+  begin
+    TNat320.Copy64(LX1.X, LT3);
+    TNat320.Copy64(LL1.X, LTT0);
+  end
+  else
+  begin
+    TSecT283Field.Multiply(LX1.X, LZ2.X, LT3);
+    TSecT283Field.Multiply(LL1.X, LZ2.X, LTT0);
+  end;
+
+  TSecT283Field.AddTo(LTT0, LT2);
+  TSecT283Field.Add(LT3, LT1, LTT0);
+
+  if TNat320.IsZero64(LTT0) then
+  begin
+    if TNat320.IsZero64(LT2) then
+      Exit(Twice());
+    Exit(LCurve.Infinity);
+  end;
+
+  if LX2.IsZero then
+  begin
+    LNorm := Normalize();
+    LX1 := LNorm.RawXCoord as ISecT283FieldElement;
+    LY1 := LNorm.GetYCoord;
+    LY2 := LL2;
+    LL := LY1.Add(LY2).Divide(LX1 as IECFieldElement);
+    LX3Fe := LL.Square().Add(LL).Add(LX1 as IECFieldElement);
+    if LX3Fe.IsZero then
+      Exit(TSecT283K1Point.Create(LCurve, LX3Fe, LCurve.B));
+    LY3Fe := LL.Multiply((LX1 as IECFieldElement).Add(LX3Fe)).Add(LX3Fe).Add(LY1);
+    LZ3Fe := LCurve.FromBigInteger(TBigInteger.One);
+    Result := TSecT283K1Point.Create(LCurve, LX3Fe, LY3Fe.Divide(LX3Fe).Add(LX3Fe),
+      TCryptoLibGenericArray<IECFieldElement>.Create(LZ3Fe));
+    Exit;
+  end;
+
+  TSecT283Field.Square(LTT0, LTT0);
+  TSecT283Field.Multiply(LT3, LT2, LT3);
+  TSecT283Field.Multiply(LT1, LT2, LT1);
+  LX3Arr := LT3;
+  TSecT283Field.Multiply(LX3Arr, LT1, LX3Arr);
+  if TNat320.IsZero64(LX3Arr) then
+    Exit(TSecT283K1Point.Create(LCurve, TSecT283FieldElement.Create(LX3Arr),
+      LCurve.B));
+  LZ3Arr := LT2;
+  TSecT283Field.Multiply(LZ3Arr, LTT0, LZ3Arr);
+  if not LZ2IsOne then
+    TSecT283Field.Multiply(LZ3Arr, LZ2.X, LZ3Arr);
+  LL3Arr := LT1;
+  TSecT283Field.AddTo(LTT0, LL3Arr);
+  TSecT283Field.SquareExt(LL3Arr, LTT0);
+  TSecT283Field.Add(LL1.X, LZ1.X, LL3Arr);
+  TSecT283Field.MultiplyAddToExt(LZ3Arr, LL3Arr, LTT0);
+  TSecT283Field.Reduce(LTT0, LL3Arr);
+  if not LZ1IsOne then
+    TSecT283Field.Multiply(LZ3Arr, LZ1.X, LZ3Arr);
+  LX3 := TSecT283FieldElement.Create(LX3Arr);
+  LL3 := TSecT283FieldElement.Create(LL3Arr);
+  LZ3 := TSecT283FieldElement.Create(LZ3Arr);
+  LZs := TCryptoLibGenericArray<IECFieldElement>.Create(LZ3 as IECFieldElement);
+  Result := TSecT283K1Point.Create(LCurve, LX3 as IECFieldElement, LL3 as IECFieldElement, LZs);
+end;
+
+function TSecT283K1Point.Twice: IECPoint;
+var
+  LCurve: IECCurve;
+  LX1, LL1, LZ1: IECFieldElement;
+  LZ1IsOne: Boolean;
+  LZ1Sq, LT, LX3, LZ3, LT1, LT2, LL3: IECFieldElement;
+begin
+  if IsInfinity then
+    Exit(Self as IECPoint);
+  LCurve := Curve;
+  LX1 := RawXCoord;
+  if LX1.IsZero then
+    Exit(LCurve.Infinity);
+  LL1 := RawYCoord;
+  LZ1 := RawZCoords[0];
+  LZ1IsOne := LZ1.IsOne;
+  if LZ1IsOne then
+    LZ1Sq := LZ1
+  else
+    LZ1Sq := LZ1.Square();
+  if LZ1IsOne then
+    LT := LL1.Square().Add(LL1)
+  else
+    LT := LL1.Add(LZ1).Multiply(LL1);
+  if LT.IsZero then
+    Exit(TSecT283K1Point.Create(LCurve, LT, LCurve.B));
+  LX3 := LT.Square();
+  if LZ1IsOne then
+    LZ3 := LT
+  else
+    LZ3 := LT.Multiply(LZ1Sq);
+  if LZ1IsOne then
+    LT1 := LL1.Add(LX1).Square()
+  else
+    LT1 := LL1.Add(LX1).Square();
+  if LZ1IsOne then
+    LT2 := LZ1
+  else
+    LT2 := LZ1Sq.Square();
+  LL3 := LT1.Add(LT).Add(LZ1Sq).Multiply(LT1).Add(LT2).Add(LX3).Add(LZ3);
+  Result := TSecT283K1Point.Create(LCurve, LX3, LL3,
+    TCryptoLibGenericArray<IECFieldElement>.Create(LZ3));
+end;
+
+function TSecT283K1Point.TwicePlus(const AB: IECPoint): IECPoint;
+var
+  LCurve: IECCurve;
+  LX1, LX2, LZ2, LL1, LZ1, LL2: IECFieldElement;
+  LX1Sq, LL1Sq, LZ1Sq, LL1Z1, LT, LL2Plus1, LA, LX2Z1Sq, LB: IECFieldElement;
+  LX3, LZ3, LL3: IECFieldElement;
+begin
+  if IsInfinity then
+    Exit(AB);
+  if AB.IsInfinity then
+    Exit(Twice());
+  LCurve := Curve;
+  LX1 := RawXCoord;
+  if LX1.IsZero then
+    Exit(AB);
+  LX2 := AB.RawXCoord;
+  LZ2 := AB.GetZCoord(0);
+  if LX2.IsZero or not LZ2.IsOne then
+    Exit(Twice().Add(AB));
+  LL1 := RawYCoord;
+  LZ1 := RawZCoords[0];
+  LL2 := AB.RawYCoord;
+  LX1Sq := LX1.Square();
+  LL1Sq := LL1.Square();
+  LZ1Sq := LZ1.Square();
+  LL1Z1 := LL1.Multiply(LZ1);
+  LT := LL1Sq.Add(LL1Z1);
+  LL2Plus1 := LL2.AddOne();
+  LA := LL2Plus1.Multiply(LZ1Sq).Add(LL1Sq).MultiplyPlusProduct(LT, LX1Sq, LZ1Sq);
+  LX2Z1Sq := LX2.Multiply(LZ1Sq);
+  LB := LX2Z1Sq.Add(LT).Square();
+  if LB.IsZero then
+  begin
+    if LA.IsZero then
+      Exit(AB.Twice());
+    Exit(LCurve.Infinity);
+  end;
+  if LA.IsZero then
+    Exit(TSecT283K1Point.Create(LCurve, LA, LCurve.B));
+  LX3 := LA.Square().Multiply(LX2Z1Sq);
+  LZ3 := LA.Multiply(LB).Multiply(LZ1Sq);
+  LL3 := LA.Add(LB).Square().MultiplyPlusProduct(LT, LL2Plus1, LZ3);
+  Result := TSecT283K1Point.Create(LCurve, LX3, LL3,
+    TCryptoLibGenericArray<IECFieldElement>.Create(LZ3));
+end;
+
+function TSecT283K1Point.Negate: IECPoint;
+var
+  LX, LL, LZ: IECFieldElement;
+begin
+  if IsInfinity then
+    Exit(Self as IECPoint);
+  LX := RawXCoord;
+  if LX.IsZero then
+    Exit(Self as IECPoint);
+  LL := RawYCoord;
+  LZ := RawZCoords[0];
+  Result := TSecT283K1Point.Create(Curve, LX, LL.Add(LZ),
+    TCryptoLibGenericArray<IECFieldElement>.Create(LZ));
+end;
+
+{ TSecT283K1Curve.TSecT283K1LookupTable }
+
+constructor TSecT283K1Curve.TSecT283K1LookupTable.Create(const AOuter: ISecT283K1Curve;
+  const ATable: TCryptoLibUInt64Array; ASize: Int32);
+begin
+  Inherited Create;
+  FOuter := AOuter;
+  FTable := ATable;
+  FSize := ASize;
+end;
+
+function TSecT283K1Curve.TSecT283K1LookupTable.GetSize: Int32;
+begin
+  Result := FSize;
+end;
+
+function TSecT283K1Curve.TSecT283K1LookupTable.CreatePoint(const AX, AY: TCryptoLibUInt64Array): IECPoint;
+begin
+  Result := FOuter.CreateRawPoint(TSecT283FieldElement.Create(AX) as IECFieldElement,
+    TSecT283FieldElement.Create(AY) as IECFieldElement, TSecT283K1Curve.SecT283K1AffineZs);
+end;
+
+function TSecT283K1Curve.TSecT283K1LookupTable.Lookup(AIndex: Int32): IECPoint;
+var
+  LX, LY: TCryptoLibUInt64Array;
+  LPos, LI, LJ: Int32;
+  LMask: UInt64;
+begin
+  LX := TNat320.Create64();
+  LY := TNat320.Create64();
+  LPos := 0;
+  for LI := 0 to System.Pred(FSize) do
+  begin
+    LMask := UInt64(TBitOperations.Asr32(((LI xor AIndex) - 1), 31));
+    for LJ := 0 to System.Pred(SECT283K1_FE_LONGS) do
+    begin
+      LX[LJ] := LX[LJ] xor (FTable[LPos + LJ] and LMask);
+      LY[LJ] := LY[LJ] xor (FTable[LPos + SECT283K1_FE_LONGS + LJ] and LMask);
+    end;
+    LPos := LPos + (SECT283K1_FE_LONGS * 2);
+  end;
+  Result := CreatePoint(LX, LY);
+end;
+
+function TSecT283K1Curve.TSecT283K1LookupTable.LookupVar(AIndex: Int32): IECPoint;
+var
+  LX, LY: TCryptoLibUInt64Array;
+  LPos, LJ: Int32;
+begin
+  LX := TNat320.Create64();
+  LY := TNat320.Create64();
+  LPos := AIndex * SECT283K1_FE_LONGS * 2;
+  for LJ := 0 to System.Pred(SECT283K1_FE_LONGS) do
+  begin
+    LX[LJ] := FTable[LPos + LJ];
+    LY[LJ] := FTable[LPos + SECT283K1_FE_LONGS + LJ];
+  end;
+  Result := CreatePoint(LX, LY);
+end;
+
+{ TSecT283K1Curve }
+
+class procedure TSecT283K1Curve.Boot;
+begin
+  FSecT283K1AffineZs := TCryptoLibGenericArray<IECFieldElement>.Create(
+    TSecT283FieldElement.Create(TBigInteger.One) as IECFieldElement);
+end;
+
+class constructor TSecT283K1Curve.Create;
+begin
+  Boot;
+end;
+
+constructor TSecT283K1Curve.Create;
+begin
+  Inherited Create(283, 5, 7, 12);
+  FInfinity := TSecT283K1Point.Create(Self as IECCurve, nil, nil);
+  FA := FromBigInteger(TBigInteger.Zero);
+  FB := FromBigInteger(TBigInteger.One);
+  FOrder := TBigInteger.Create(1, THex.Decode('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61'));
+  FCofactor := TBigInteger.Four;
+  FCoord := SECT283K1_DEFAULT_COORDS;
+end;
+
+function TSecT283K1Curve.GetIsKoblitz: Boolean;
+begin
+  Result := True;
+end;
+
+function TSecT283K1Curve.CreateDefaultMultiplier: IECMultiplier;
+begin
+  Result := TWTauNafMultiplier.Create() as IECMultiplier;
+end;
+
+function TSecT283K1Curve.CloneCurve: IECCurve;
+begin
+  Result := TSecT283K1Curve.Create;
+end;
+
+function TSecT283K1Curve.GetFieldSize: Int32;
+begin
+  Result := 283;
+end;
+
+function TSecT283K1Curve.GetInfinity: IECPoint;
+begin
+  Result := FInfinity;
+end;
+
+function TSecT283K1Curve.FromBigInteger(const AX: TBigInteger): IECFieldElement;
+begin
+  Result := TSecT283FieldElement.Create(AX);
+end;
+
+function TSecT283K1Curve.CreateRawPoint(const AX, AY: IECFieldElement): IECPoint;
+begin
+  Result := TSecT283K1Point.Create(Self as IECCurve, AX, AY);
+end;
+
+function TSecT283K1Curve.CreateRawPoint(const AX, AY: IECFieldElement;
+  const AZs: TCryptoLibGenericArray<IECFieldElement>): IECPoint;
+begin
+  Result := TSecT283K1Point.Create(Self as IECCurve, AX, AY, AZs);
+end;
+
+function TSecT283K1Curve.CreateCacheSafeLookupTable(const APoints: TCryptoLibGenericArray<IECPoint>;
+  AOff, ALen: Int32): IECLookupTable;
+var
+  LTable: TCryptoLibUInt64Array;
+  LPos, LI: Int32;
+  LP: IECPoint;
+begin
+  System.SetLength(LTable, ALen * SECT283K1_FE_LONGS * 2);
+  LPos := 0;
+  for LI := 0 to System.Pred(ALen) do
+  begin
+    LP := APoints[AOff + LI];
+    TNat320.Copy64((LP.RawXCoord as ISecT283FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECT283K1_FE_LONGS;
+    TNat320.Copy64((LP.RawYCoord as ISecT283FieldElement).X, 0, LTable, LPos);
+    LPos := LPos + SECT283K1_FE_LONGS;
+  end;
+  Result := TSecT283K1LookupTable.Create(Self as ISecT283K1Curve, LTable, ALen);
+end;
+
+function TSecT283K1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean;
+begin
+  Result := ACoord = TECCurveConstants.COORD_LAMBDA_PROJECTIVE;
+end;
+
+function TSecT283K1Curve.GetM: Int32;
+begin
+  Result := 283;
+end;
+
+function TSecT283K1Curve.GetIsTrinomial: Boolean;
+begin
+  Result := False;
+end;
+
+function TSecT283K1Curve.GetK1: Int32;
+begin
+  Result := 5;
+end;
+
+function TSecT283K1Curve.GetK2: Int32;
+begin
+  Result := 7;
+end;
+
+function TSecT283K1Curve.GetK3: Int32;
+begin
+  Result := 12;
+end;
+
+end.