Browse Source

add custom curve "secp256r1".

Ugochukwu Mmaduekwe 7 years ago
parent
commit
5f8545c7ec

+ 8 - 1
CryptoLib.Samples/Delphi.Samples/UsageSamples.dpr

@@ -448,7 +448,14 @@ uses
   ClpSecT283K1Point in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Point.pas',
   ClpISecT283K1Point in '..\..\CryptoLib\src\Interfaces\ClpISecT283K1Point.pas',
   ClpISecT283K1Curve in '..\..\CryptoLib\src\Interfaces\ClpISecT283K1Curve.pas',
-  ClpSecT283K1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Curve.pas';
+  ClpSecT283K1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Curve.pas',
+  ClpSecP256R1Field in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Field.pas',
+  ClpSecP256R1FieldElement in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1FieldElement.pas',
+  ClpISecP256R1FieldElement in '..\..\CryptoLib\src\Interfaces\ClpISecP256R1FieldElement.pas',
+  ClpISecP256R1Point in '..\..\CryptoLib\src\Interfaces\ClpISecP256R1Point.pas',
+  ClpSecP256R1Point in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Point.pas',
+  ClpISecP256R1Curve in '..\..\CryptoLib\src\Interfaces\ClpISecP256R1Curve.pas',
+  ClpSecP256R1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Curve.pas';
 
 begin
   try

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

@@ -500,7 +500,15 @@ uses
   ClpSecT283K1Point in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Point.pas',
   ClpISecT283K1Point in '..\..\CryptoLib\src\Interfaces\ClpISecT283K1Point.pas',
   ClpISecT283K1Curve in '..\..\CryptoLib\src\Interfaces\ClpISecT283K1Curve.pas',
-  ClpSecT283K1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Curve.pas';
+  ClpSecT283K1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecT283K1Curve.pas',
+  ClpSecP256R1Field in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Field.pas',
+  ClpSecP256R1FieldElement in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1FieldElement.pas',
+  ClpISecP256R1FieldElement in '..\..\CryptoLib\src\Interfaces\ClpISecP256R1FieldElement.pas',
+  ClpISecP256R1Point in '..\..\CryptoLib\src\Interfaces\ClpISecP256R1Point.pas',
+  ClpSecP256R1Point in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Point.pas',
+  ClpISecP256R1Curve in '..\..\CryptoLib\src\Interfaces\ClpISecP256R1Curve.pas',
+  ClpSecP256R1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256R1Curve.pas',
+  SecP256R1FieldTests in '..\src\Math\EC\Custom\Sec\SecP256R1FieldTests.pas';
 
 begin
 

+ 5 - 1
CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi

@@ -36,7 +36,7 @@
         <PackageName Value="FCL"/>
       </Item4>
     </RequiredPackages>
-    <Units Count="41">
+    <Units Count="42">
       <Unit0>
         <Filename Value="CryptoLib.lpr"/>
         <IsPartOfProject Value="True"/>
@@ -202,6 +202,10 @@
         <Filename Value="..\src\Crypto\RIPEMD160HMacTests.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit40>
+      <Unit41>
+        <Filename Value="..\src\Math\EC\Custom\Sec\SecP256R1FieldTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit41>
     </Units>
   </ProjectOptions>
   <CompilerOptions>

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

@@ -13,6 +13,7 @@ uses
   BigIntegerTests,
   ECAlgorithmsTests,
   ECPointTests,
+  SecP256R1FieldTests,
   SecP384R1FieldTests,
   ECDsa5Tests,
   ECTests,

+ 5 - 4
CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.Tests.lpi

@@ -17,9 +17,6 @@
       <Version Value="2"/>
     </PublishOptions>
     <RunParams>
-      <local>
-        <CommandLineParams Value="--format=plain --all --progress"/>
-      </local>
       <FormatVersion Value="2"/>
       <Modes Count="1">
         <Mode0 Name="default">
@@ -37,7 +34,7 @@
         <PackageName Value="FCL"/>
       </Item2>
     </RequiredPackages>
-    <Units Count="41">
+    <Units Count="42">
       <Unit0>
         <Filename Value="CryptoLibConsole.lpr"/>
         <IsPartOfProject Value="True"/>
@@ -202,6 +199,10 @@
         <Filename Value="..\src\Crypto\RIPEMD160HMacTests.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit40>
+      <Unit41>
+        <Filename Value="..\src\Math\EC\Custom\Sec\SecP256R1FieldTests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit41>
     </Units>
   </ProjectOptions>
   <CompilerOptions>

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

@@ -11,6 +11,7 @@ uses
   BigIntegerTests,
   ECAlgorithmsTests,
   ECPointTests,
+  SecP256R1FieldTests,
   SecP384R1FieldTests,
   ECDsa5Tests,
   ECTests,

+ 355 - 0
CryptoLib.Tests/src/Math/EC/Custom/Sec/SecP256R1FieldTests.pas

@@ -0,0 +1,355 @@
+{ *********************************************************************************** }
+{ *                              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 SecP256R1FieldTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpCryptoLibTypes,
+  ClpIX9ECParameters,
+  ClpSecObjectIdentifiers,
+  ClpConverters,
+  ClpCustomNamedCurves,
+  ClpIECFieldElement,
+  ClpBigInteger;
+
+type
+
+  TCryptoLibTestCase = class abstract(TTestCase)
+
+  end;
+
+type
+
+  TTestSecP256R1Field = class(TCryptoLibTestCase)
+  private
+  var
+    FRandom: ISecureRandom;
+    FDP: IX9ECParameters;
+    FQ: TBigInteger;
+
+    procedure AssertAreBigIntegersEqual(const a, b: TBigInteger);
+    function FE(const x: TBigInteger): IECFieldElement;
+    function GenerateMultiplyInput_Random(): IECFieldElement;
+    function GenerateSquareInput_OpenSSLBug(): IECFieldElement;
+    function GenerateMultiplyInputA_OpenSSLBug(): IECFieldElement;
+    function GenerateMultiplyInputB_OpenSSLBug(): IECFieldElement;
+    function Nat256_Create(): TCryptoLibUInt32Array;
+    function Nat256_ToBigInteger(const x: TCryptoLibUInt32Array): TBigInteger;
+
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+    procedure TestMultiply1();
+    procedure TestMultiply2();
+    procedure TestSquare();
+
+    /// <summary>
+    /// <para>
+    /// Test squaring with specifically selected values that triggered a
+    /// bug in the modular reduction <br />in OpenSSL (last affected
+    /// version 0.9.8g).
+    /// </para>
+    /// <para>
+    /// See "Practical realisation and elimination of an ECC-related
+    /// software bug attack", B. B. <br />Brumley, M. Barbarosa, D. Page,
+    /// F. Vercauteren.
+    /// </para>
+    /// </summary>
+    procedure TestSquare_OpenSSLBug();
+
+    /// <summary>
+    /// <para>
+    /// Test multiplication with specifically selected values that
+    /// triggered a bug in the modular <br />reduction in OpenSSL (last
+    /// affected version 0.9.8g).
+    /// </para>
+    /// <para>
+    /// See "Practical realisation and elimination of an ECC-related
+    /// software bug attack", B. B. <br />Brumley, M. Barbarosa, D. Page,
+    /// F. Vercauteren.
+    /// </para>
+    /// </summary>
+    procedure TestMultiply_OpenSSLBug();
+
+  end;
+
+implementation
+
+{ TTestSecP256R1Field }
+
+procedure TTestSecP256R1Field.AssertAreBigIntegersEqual(const a,
+  b: TBigInteger);
+begin
+  CheckEquals(True, a.Equals(b));
+end;
+
+function TTestSecP256R1Field.FE(const x: TBigInteger): IECFieldElement;
+begin
+  result := FDP.Curve.FromBigInteger(x);
+end;
+
+function TTestSecP256R1Field.GenerateMultiplyInputA_OpenSSLBug: IECFieldElement;
+var
+  x: TCryptoLibUInt32Array;
+begin
+  x := Nat256_Create();
+  x[0] := UInt32(FRandom.NextInt32()) shr 1;
+  x[4] := 3;
+  x[7] := $FFFFFFFF;
+
+  result := FE(Nat256_ToBigInteger(x));
+end;
+
+function TTestSecP256R1Field.GenerateMultiplyInputB_OpenSSLBug: IECFieldElement;
+var
+  x: TCryptoLibUInt32Array;
+begin
+  x := Nat256_Create();
+  x[0] := UInt32(FRandom.NextInt32()) shr 1;
+  x[3] := 1;
+  x[7] := $FFFFFFFF;
+
+  result := FE(Nat256_ToBigInteger(x));
+end;
+
+function TTestSecP256R1Field.GenerateMultiplyInput_Random: IECFieldElement;
+begin
+  result := FE(TBigInteger.Create(FDP.Curve.FieldSize + 32, FRandom).&Mod(FQ));
+end;
+
+function TTestSecP256R1Field.GenerateSquareInput_OpenSSLBug: IECFieldElement;
+var
+  x: TCryptoLibUInt32Array;
+begin
+  x := Nat256_Create();
+  x[0] := UInt32(FRandom.NextInt32()) shr 1;
+  x[4] := 2;
+  x[7] := $FFFFFFFF;
+
+  result := FE(Nat256_ToBigInteger(x));
+end;
+
+function TTestSecP256R1Field.Nat256_Create(): TCryptoLibUInt32Array;
+begin
+  System.SetLength(result, 8);
+end;
+
+function TTestSecP256R1Field.Nat256_ToBigInteger(const x: TCryptoLibUInt32Array)
+  : TBigInteger;
+var
+  bs, temp: TCryptoLibByteArray;
+  i: Int32;
+  x_i: UInt32;
+begin
+  System.SetLength(bs, 32);
+  for i := 0 to System.Pred(8) do
+
+  begin
+    x_i := x[i];
+    if (x_i <> 0) then
+    begin
+      temp := TConverters.ReadUInt32AsBytesBE(x_i);
+      System.Move(temp[0], bs[(7 - i) shl 2], System.Length(temp) *
+        SizeOf(Byte));
+
+    end;
+  end;
+  result := TBigInteger.Create(1, bs);
+end;
+
+procedure TTestSecP256R1Field.SetUp;
+begin
+  inherited;
+  FRandom := TSecureRandom.Create();
+  FDP := TCustomNamedCurves.GetByOid(TSecObjectIdentifiers.SecP256r1);
+
+  FQ := FDP.Curve.Field.Characteristic;
+end;
+
+procedure TTestSecP256R1Field.TearDown;
+begin
+  inherited;
+
+end;
+
+procedure TTestSecP256R1Field.TestMultiply1;
+var
+  Count, i: Int32;
+  x, y, z: IECFieldElement;
+  bigX, bigY, bigR, bigZ: TBigInteger;
+begin
+  Count := 1000;
+
+  i := 0;
+
+  while i < Count do
+  begin
+
+    x := GenerateMultiplyInput_Random();
+    y := GenerateMultiplyInput_Random();
+
+    bigX := x.ToBigInteger();
+    bigY := y.ToBigInteger();
+    bigR := bigX.Multiply(bigY).&Mod(FQ);
+
+    z := x.Multiply(y);
+    bigZ := z.ToBigInteger();
+
+    AssertAreBigIntegersEqual(bigR, bigZ);
+
+    System.Inc(i);
+  end;
+
+end;
+
+procedure TTestSecP256R1Field.TestMultiply2;
+var
+  Count, i, J, K: Int32;
+  ecFieldElements: TCryptoLibGenericArray<IECFieldElement>;
+  bigIntegers: TCryptoLibGenericArray<TBigInteger>;
+  bigR, bigZ: TBigInteger;
+  z: IECFieldElement;
+begin
+  Count := 100;
+  System.SetLength(ecFieldElements, Count);
+  System.SetLength(bigIntegers, Count);
+
+  for i := 0 to System.Pred(System.Length(ecFieldElements)) do
+
+  begin
+    ecFieldElements[i] := GenerateMultiplyInput_Random();
+    bigIntegers[i] := ecFieldElements[i].ToBigInteger();
+  end;
+
+  for J := 0 to System.Pred(System.Length(ecFieldElements)) do
+  begin
+    for K := 0 to System.Pred(System.Length(ecFieldElements)) do
+    begin
+      bigR := bigIntegers[J].Multiply(bigIntegers[K]).&Mod(FQ);
+
+      z := ecFieldElements[J].Multiply(ecFieldElements[K]);
+      bigZ := z.ToBigInteger();
+
+      AssertAreBigIntegersEqual(bigR, bigZ);
+    end;
+  end;
+end;
+
+procedure TTestSecP256R1Field.TestSquare;
+var
+  Count, i: Int32;
+  x, z: IECFieldElement;
+  bigX, bigY, bigZ: TBigInteger;
+begin
+  Count := 1000;
+  i := 0;
+
+  while i < Count do
+
+  begin
+    x := GenerateMultiplyInput_Random();
+
+    bigX := x.ToBigInteger();
+    bigY := bigX.Multiply(bigX).&Mod(FQ);
+
+    z := x.Square();
+    bigZ := z.ToBigInteger();
+
+    AssertAreBigIntegersEqual(bigY, bigZ);
+    System.Inc(i);
+  end;
+end;
+
+procedure TTestSecP256R1Field.TestSquare_OpenSSLBug;
+var
+  Count, i: Int32;
+  x, z: IECFieldElement;
+  bigX, bigR, bigZ: TBigInteger;
+begin
+  Count := 100;
+  i := 0;
+
+  while i < Count do
+
+  begin
+    x := GenerateSquareInput_OpenSSLBug();
+
+    bigX := x.ToBigInteger();
+    bigR := bigX.Multiply(bigX).&Mod(FQ);
+
+    z := x.Square();
+    bigZ := z.ToBigInteger();
+
+    AssertAreBigIntegersEqual(bigR, bigZ);
+    System.Inc(i);
+  end;
+end;
+
+procedure TTestSecP256R1Field.TestMultiply_OpenSSLBug;
+var
+  x, y, z: IECFieldElement;
+  bigR, bigX, bigY, bigZ: TBigInteger;
+  Count, i: Int32;
+begin
+
+  Count := 100;
+  i := 0;
+
+  while i < Count do
+  begin
+    x := GenerateMultiplyInputA_OpenSSLBug();
+    y := GenerateMultiplyInputB_OpenSSLBug();
+
+    bigX := x.ToBigInteger();
+    bigY := y.ToBigInteger();
+    bigR := bigX.Multiply(bigY).&Mod(FQ);
+
+    z := x.Multiply(y);
+    bigZ := z.ToBigInteger();
+
+    AssertAreBigIntegersEqual(bigR, bigZ);
+    System.Inc(i);
+  end;
+
+end;
+
+initialization
+
+// Register any test cases with the test runner
+
+{$IFDEF FPC}
+  RegisterTest(TTestSecP256R1Field);
+{$ELSE}
+  RegisterTest(TTestSecP256R1Field.Suite);
+{$ENDIF FPC}
+
+end.

+ 0 - 2
CryptoLib.Tests/src/Math/EC/Custom/Sec/SecP384R1FieldTests.pas

@@ -24,8 +24,6 @@ interface
 {$ENDIF FPC}
 
 uses
-  Classes,
-  SysUtils,
 {$IFDEF FPC}
   fpcunit,
   testregistry,

+ 45 - 0
CryptoLib/src/Crypto/EC/ClpCustomNamedCurves.pas

@@ -33,6 +33,8 @@ uses
   ClpECCurve,
   ClpSecP256K1Curve,
   ClpISecP256K1Curve,
+  ClpSecP256R1Curve,
+  ClpISecP256R1Curve,
   ClpSecP384R1Curve,
   ClpISecP384R1Curve,
   ClpSecP521R1Curve,
@@ -133,6 +135,22 @@ type
 
     end;
 
+  type
+
+    /// <summary>
+    /// secp256r1
+    /// </summary>
+    TSecP256R1Holder = class sealed(TX9ECParametersHolder,
+      IX9ECParametersHolder)
+
+    strict protected
+      function CreateParameters(): IX9ECParameters; override;
+
+    public
+      class function Instance(): IX9ECParametersHolder; static;
+
+    end;
+
   type
 
     /// <summary>
@@ -325,6 +343,9 @@ begin
     DefineCurveWithOid('secp256k1', TSecObjectIdentifiers.SecP256k1,
       TSecP256K1Holder.Instance);
 
+    DefineCurveWithOid('secp256r1', TSecObjectIdentifiers.SecP256r1,
+      TSecP256R1Holder.Instance);
+
     DefineCurveWithOid('secp384r1', TSecObjectIdentifiers.SecP384r1,
       TSecP384R1Holder.Instance);
 
@@ -336,6 +357,7 @@ begin
 
     DefineCurveAlias('K-283', TSecObjectIdentifiers.SecT283k1);
 
+    DefineCurveAlias('P-256', TSecObjectIdentifiers.SecP256r1);
     DefineCurveAlias('P-384', TSecObjectIdentifiers.SecP384r1);
     DefineCurveAlias('P-521', TSecObjectIdentifiers.SecP521r1);
 
@@ -452,4 +474,27 @@ begin
   result := TSecT283K1Holder.Create();
 end;
 
+{ TCustomNamedCurves.TSecP256R1Holder }
+
+function TCustomNamedCurves.TSecP256R1Holder.CreateParameters: IX9ECParameters;
+var
+  S: TCryptoLibByteArray;
+  curve: IECCurve;
+  G: IX9ECPoint;
+begin
+  S := THex.Decode('C49D360886E704936A6678E1139D26B7819F7E90');
+  curve := ConfigureCurve(TSecP256R1Curve.Create() as ISecP256R1Curve);
+  G := TX9ECPoint.Create(curve,
+    THex.Decode('04' +
+    '6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296' +
+    '4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5'));
+  result := TX9ECParameters.Create(curve, G, curve.Order, curve.Cofactor, S);
+end;
+
+class function TCustomNamedCurves.TSecP256R1Holder.Instance
+  : IX9ECParametersHolder;
+begin
+  result := TSecP256R1Holder.Create();
+end;
+
 end.

+ 44 - 0
CryptoLib/src/Interfaces/ClpISecP256R1Curve.pas

@@ -0,0 +1,44 @@
+{ *********************************************************************************** }
+{ *                              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 ClpISecP256R1Curve;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIECInterface,
+  ClpBigInteger;
+
+type
+  ISecP256R1LookupTable = Interface(IECLookupTable)
+    ['{87BF97BA-18D2-4248-ABEB-8E429998E9D9}']
+  end;
+
+type
+  ISecP256R1Curve = Interface(IAbstractFpCurve)
+    ['{D6B64687-91B2-4281-B099-3B3DCFB330DB}']
+
+    function GetQ: TBigInteger;
+    property Q: TBigInteger read GetQ;
+
+  end;
+
+implementation
+
+end.

+ 38 - 0
CryptoLib/src/Interfaces/ClpISecP256R1FieldElement.pas

@@ -0,0 +1,38 @@
+{ *********************************************************************************** }
+{ *                              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 ClpISecP256R1FieldElement;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIECFieldElement,
+  ClpCryptoLibTypes;
+
+type
+  ISecP256R1FieldElement = Interface(IAbstractFpFieldElement)
+    ['{963E19D3-B86F-4F78-8C10-54BF82030F09}']
+
+    function GetX: TCryptoLibUInt32Array;
+    property X: TCryptoLibUInt32Array read GetX;
+  end;
+
+implementation
+
+end.

+ 35 - 0
CryptoLib/src/Interfaces/ClpISecP256R1Point.pas

@@ -0,0 +1,35 @@
+{ *********************************************************************************** }
+{ *                              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 ClpISecP256R1Point;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIECInterface;
+
+type
+  ISecP256R1Point = Interface(IAbstractFpPoint)
+    ['{EDD8CEBA-B86F-41F0-96B3-958525EF3272}']
+
+  end;
+
+implementation
+
+end.

+ 264 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Curve.pas

@@ -0,0 +1,264 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256R1Curve;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpHex,
+  ClpBits,
+  ClpNat256,
+  ClpECCurve,
+  ClpIECInterface,
+  ClpISecP256R1FieldElement,
+  ClpSecP256R1Point,
+  ClpISecP256R1Curve,
+  ClpISecP256R1Point,
+  ClpIECFieldElement,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
+
+type
+  TSecP256R1Curve = class sealed(TAbstractFpCurve, ISecP256R1Curve)
+
+  strict private
+
+  type
+    TSecP256R1LookupTable = class sealed(TInterfacedObject,
+      ISecP256R1LookupTable, IECLookupTable)
+
+    strict private
+    var
+      Fm_outer: ISecP256R1Curve;
+      Fm_table: TCryptoLibUInt32Array;
+      Fm_size: Int32;
+
+      function GetSize: Int32; virtual;
+
+    public
+
+      constructor Create(const outer: ISecP256R1Curve;
+        const table: TCryptoLibUInt32Array; size: Int32);
+
+      function Lookup(index: Int32): IECPoint; virtual;
+
+      property size: Int32 read GetSize;
+
+    end;
+
+  const
+    SECP256R1_DEFAULT_COORDS = Int32(TECCurve.COORD_JACOBIAN);
+    SECP256R1_FE_INTS = Int32(8);
+
+    class var
+
+      Fq: TBigInteger;
+
+    class function GetSecP256R1Curve_Q: TBigInteger; static; inline;
+    class constructor SecP256R1Curve();
+
+  strict protected
+  var
+    Fm_infinity: ISecP256R1Point;
+
+    function GetQ: TBigInteger; virtual;
+    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;
+
+    class property SecP256R1Curve_Q: TBigInteger read GetSecP256R1Curve_Q;
+
+  end;
+
+implementation
+
+uses
+  // included here to avoid circular dependency :)
+  ClpSecP256R1FieldElement;
+
+{ TSecP256R1Curve }
+
+class function TSecP256R1Curve.GetSecP256R1Curve_Q: TBigInteger;
+begin
+  result := Fq;
+end;
+
+class constructor TSecP256R1Curve.SecP256R1Curve;
+begin
+  Fq := TBigInteger.Create(1,
+    THex.Decode
+    ('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF'));
+end;
+
+constructor TSecP256R1Curve.Create;
+begin
+  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;
+end;
+
+function TSecP256R1Curve.CloneCurve: IECCurve;
+begin
+  result := TSecP256R1Curve.Create();
+end;
+
+function TSecP256R1Curve.CreateCacheSafeLookupTable(const points
+  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
+var
+  table: TCryptoLibUInt32Array;
+  pos, i: Int32;
+  p: IECPoint;
+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);
+end;
+
+function TSecP256R1Curve.CreateRawPoint(const x, y: IECFieldElement;
+  withCompression: Boolean): IECPoint;
+begin
+  result := TSecP256R1Point.Create(Self as IECCurve, x, y, withCompression);
+end;
+
+function TSecP256R1Curve.CreateRawPoint(const x, y: IECFieldElement;
+  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
+  : IECPoint;
+begin
+  result := TSecP256R1Point.Create(Self as IECCurve, x, y, zs, withCompression);
+end;
+
+function TSecP256R1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
+begin
+  result := TSecP256R1FieldElement.Create(x);
+end;
+
+function TSecP256R1Curve.GetFieldSize: Int32;
+begin
+  result := Fq.BitLength;
+end;
+
+function TSecP256R1Curve.GetInfinity: IECPoint;
+begin
+  result := Fm_infinity;
+end;
+
+function TSecP256R1Curve.GetQ: TBigInteger;
+begin
+  result := Fq;
+end;
+
+function TSecP256R1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
+begin
+  case coord of
+    COORD_JACOBIAN:
+      result := True
+  else
+    result := False;
+  end;
+end;
+
+{ TSecP256R1Curve.TSecP256R1LookupTable }
+
+constructor TSecP256R1Curve.TSecP256R1LookupTable.Create
+  (const outer: ISecP256R1Curve; const table: TCryptoLibUInt32Array;
+  size: Int32);
+begin
+  Inherited Create();
+  Fm_outer := outer;
+  Fm_table := table;
+  Fm_size := size;
+end;
+
+function TSecP256R1Curve.TSecP256R1LookupTable.GetSize: Int32;
+begin
+  result := Fm_size;
+end;
+
+function TSecP256R1Curve.TSecP256R1LookupTable.Lookup(index: Int32): IECPoint;
+var
+  x, y: TCryptoLibUInt32Array;
+  pos, i, J: Int32;
+  MASK: UInt32;
+begin
+  x := TNat256.Create();
+  y := TNat256.Create();
+  pos := 0;
+
+  for i := 0 to System.Pred(Fm_size) do
+  begin
+    MASK := UInt32(TBits.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 := Fm_outer.CreateRawPoint(TSecP256R1FieldElement.Create(x)
+    as ISecP256R1FieldElement, TSecP256R1FieldElement.Create(y)
+    as ISecP256R1FieldElement, False);
+end;
+
+end.

+ 442 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Field.pas

@@ -0,0 +1,442 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256R1Field;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpNat,
+  ClpBits,
+  ClpNat256,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
+
+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 constructor SecP256R1Field();
+
+  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;
+  end;
+
+implementation
+
+{ TSecP256R1Field }
+
+class constructor TSecP256R1Field.SecP256R1Field;
+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);
+
+end;
+
+class function TSecP256R1Field.GetP: TCryptoLibUInt32Array;
+begin
+  result := FP;
+end;
+
+class procedure TSecP256R1Field.Add(const x, y, z: TCryptoLibUInt32Array);
+var
+  c: UInt32;
+begin
+  c := TNat256.Add(x, y, z);
+  if ((c <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
+  begin
+    AddPInvTo(z);
+  end;
+end;
+
+class procedure TSecP256R1Field.AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
+var
+  c: UInt32;
+begin
+  c := TNat.Add(16, xx, yy, zz);
+  if ((c <> 0) or ((zz[15] >= PExt15) and (TNat.Gte(16, zz, FPExt)))) then
+  begin
+    TNat.SubFrom(16, FPExt, zz);
+  end;
+end;
+
+class procedure TSecP256R1Field.AddOne(const x, z: TCryptoLibUInt32Array);
+var
+  c: 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;
+end;
+
+class procedure TSecP256R1Field.AddPInvTo(const z: TCryptoLibUInt32Array);
+var
+  c: Int64;
+begin
+  c := Int64(z[0]) + 1;
+  z[0] := UInt32(c);
+  c := TBits.Asr64(c, 32);
+  if (c <> 0) then
+  begin
+    c := c + Int64(z[1]);
+    z[1] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+    c := c + Int64(z[2]);
+    z[2] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+  end;
+  c := c + (Int64(z[3]) - 1);
+  z[3] := UInt32(c);
+  c := TBits.Asr64(c, 32);
+  if (c <> 0) then
+  begin
+    c := c + Int64(z[4]);
+    z[4] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+    c := c + Int64(z[5]);
+    z[5] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+  end;
+  c := c + (Int64(z[6]) - 1);
+  z[6] := UInt32(c);
+  c := TBits.Asr64(c, 32);
+  c := c + (Int64(z[7]) + 1);
+  z[7] := UInt32(c);
+  // c := TBits.Asr64(c, 32);
+end;
+
+class function TSecP256R1Field.FromBigInteger(const x: TBigInteger)
+  : TCryptoLibUInt32Array;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.FromBigInteger(x);
+  if ((z[7] = P7) and (TNat256.Gte(z, FP))) then
+  begin
+    TNat256.SubFrom(FP, z);
+  end;
+  result := z;
+end;
+
+class procedure TSecP256R1Field.Half(const x, z: TCryptoLibUInt32Array);
+var
+  c: UInt32;
+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;
+end;
+
+class procedure TSecP256R1Field.Reduce(const xx, z: TCryptoLibUInt32Array);
+const
+  n = Int64(6);
+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 := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[1]) + t1 - t4 - t6);
+  z[1] := UInt32(cc);
+  cc := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[2]) + t2 - t5);
+  z[2] := UInt32(cc);
+  cc := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[3]) + (t3 shl 1) + t7 - t6);
+  z[3] := UInt32(cc);
+  cc := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[4]) + (t4 shl 1) + xx14 - t1);
+  z[4] := UInt32(cc);
+  cc := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[5]) + (t5 shl 1) - t2);
+  z[5] := UInt32(cc);
+  cc := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[6]) + (t6 shl 1) + t7);
+  z[6] := UInt32(cc);
+  cc := TBits.Asr64(cc, 32);
+  cc := cc + (Int64(xx[7]) + (xx15 shl 1) + xx08 - t2 - t4);
+  z[7] := UInt32(cc);
+  cc := TBits.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);
+var
+  tt: TCryptoLibUInt32Array;
+begin
+  tt := TNat256.CreateExt();
+  TNat256.Mul(x, y, tt);
+  Reduce(tt, z);
+end;
+
+class procedure TSecP256R1Field.MultiplyAddToExt(const x, y,
+  zz: TCryptoLibUInt32Array);
+var
+  c: 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;
+end;
+
+class procedure TSecP256R1Field.Negate(const x, z: TCryptoLibUInt32Array);
+begin
+  if (TNat256.IsZero(x)) then
+  begin
+    TNat256.Zero(z);
+  end
+  else
+  begin
+    TNat256.Sub(FP, x, z);
+  end;
+end;
+
+class procedure TSecP256R1Field.Reduce32(x: UInt32;
+  const z: TCryptoLibUInt32Array);
+var
+  cc, xx08: Int64;
+begin
+  cc := 0;
+
+  if (x <> 0) then
+  begin
+    xx08 := x;
+
+    cc := cc + (Int64(z[0]) + xx08);
+    z[0] := UInt32(cc);
+    cc := TBits.Asr64(cc, 32);
+    if (cc <> 0) then
+    begin
+      cc := cc + Int64(z[1]);
+      z[1] := UInt32(cc);
+      cc := TBits.Asr64(cc, 32);
+      cc := cc + Int64(z[2]);
+      z[2] := UInt32(cc);
+      cc := TBits.Asr64(cc, 32);
+    end;
+    cc := cc + (Int64(z[3]) - xx08);
+    z[3] := UInt32(cc);
+    cc := TBits.Asr64(cc, 32);
+    if (cc <> 0) then
+    begin
+      cc := cc + Int64(z[4]);
+      z[4] := UInt32(cc);
+      cc := TBits.Asr64(cc, 32);
+      cc := cc + Int64(z[5]);
+      z[5] := UInt32(cc);
+      cc := TBits.Asr64(cc, 32);
+    end;
+    cc := cc + (Int64(z[6]) - xx08);
+    z[6] := UInt32(cc);
+    cc := TBits.Asr64(cc, 32);
+    cc := cc + (Int64(z[7]) + xx08);
+    z[7] := UInt32(cc);
+    cc := TBits.Asr64(cc, 32);
+
+{$IFDEF DEBUG}
+    System.Assert((cc = 0) or (cc = 1));
+{$ENDIF DEBUG}
+  end;
+
+  if ((cc <> 0) or ((z[7] = P7) and (TNat256.Gte(z, FP)))) then
+  begin
+    AddPInvTo(z);
+  end;
+end;
+
+class procedure TSecP256R1Field.Square(const x, z: TCryptoLibUInt32Array);
+var
+  tt: TCryptoLibUInt32Array;
+begin
+  tt := TNat256.CreateExt();
+  TNat256.Square(x, tt);
+  Reduce(tt, z);
+end;
+
+class procedure TSecP256R1Field.SquareN(const x: TCryptoLibUInt32Array;
+  n: Int32; const z: TCryptoLibUInt32Array);
+var
+  tt: TCryptoLibUInt32Array;
+begin
+{$IFDEF DEBUG}
+  System.Assert(n > 0);
+{$ENDIF DEBUG}
+  tt := TNat256.CreateExt();
+  TNat256.Square(x, tt);
+  Reduce(tt, z);
+
+  System.Dec(n);
+  while (n > 0) do
+  begin
+    TNat256.Square(z, tt);
+    Reduce(tt, z);
+    System.Dec(n);
+  end;
+end;
+
+class procedure TSecP256R1Field.SubPInvFrom(const z: TCryptoLibUInt32Array);
+var
+  c: Int64;
+begin
+  c := Int64(z[0]) - 1;
+  z[0] := UInt32(c);
+  c := TBits.Asr64(c, 32);
+  if (c <> 0) then
+  begin
+    c := c + Int64(z[1]);
+    z[1] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+    c := c + Int64(z[2]);
+    z[2] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+  end;
+  c := c + (Int64(z[3]) + 1);
+  z[3] := UInt32(c);
+  c := TBits.Asr64(c, 32);
+  if (c <> 0) then
+  begin
+    c := c + Int64(z[4]);
+    z[4] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+    c := c + Int64(z[5]);
+    z[5] := UInt32(c);
+    c := TBits.Asr64(c, 32);
+  end;
+  c := c + (Int64(z[6]) + 1);
+  z[6] := UInt32(c);
+  c := TBits.Asr64(c, 32);
+  c := c + (Int64(z[7]) - 1);
+  z[7] := UInt32(c);
+  // c := TBits.Asr64(c, 32);
+end;
+
+class procedure TSecP256R1Field.Subtract(const x, y, z: TCryptoLibUInt32Array);
+var
+  c: Int32;
+begin
+  c := TNat256.Sub(x, y, z);
+  if (c <> 0) then
+  begin
+    SubPInvFrom(z);
+  end;
+end;
+
+class procedure TSecP256R1Field.SubtractExt(const xx, yy,
+  zz: TCryptoLibUInt32Array);
+var
+  c: Int32;
+begin
+  c := TNat.Sub(16, xx, yy, zz);
+  if (c <> 0) then
+  begin
+    TNat.AddTo(16, FPExt, zz);
+  end;
+end;
+
+class procedure TSecP256R1Field.Twice(const x, z: TCryptoLibUInt32Array);
+var
+  c: 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;
+end;
+
+end.

+ 321 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1FieldElement.pas

@@ -0,0 +1,321 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256R1FieldElement;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpNat256,
+  ClpMod,
+  ClpSecP256R1Curve,
+  ClpECFieldElement,
+  ClpIECFieldElement,
+  ClpSecP256R1Field,
+  ClpISecP256R1FieldElement,
+  ClpBigInteger,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidValueForSecP256R1FieldElement =
+    'Value Invalid for SecP256R1FieldElement "%s"';
+
+type
+  TSecP256R1FieldElement = class(TAbstractFpFieldElement,
+    ISecP256R1FieldElement)
+
+  strict private
+
+    function Equals(const other: ISecP256R1FieldElement): Boolean;
+      reintroduce; overload;
+
+    class function GetQ: TBigInteger; static; inline;
+
+  strict protected
+  var
+    Fx: TCryptoLibUInt32Array;
+
+    function GetFieldName: string; override;
+    function GetFieldSize: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+
+    function GetX: TCryptoLibUInt32Array; inline;
+    property X: TCryptoLibUInt32Array read GetX;
+
+  public
+    constructor Create(); overload;
+    constructor Create(const X: TBigInteger); overload;
+    constructor Create(const X: TCryptoLibUInt32Array); 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 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 other: 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;
+  end;
+
+implementation
+
+{ TSecP256R1FieldElement }
+
+class function TSecP256R1FieldElement.GetQ: TBigInteger;
+begin
+  result := TSecP256R1Curve.SecP256R1Curve_Q;
+end;
+
+function TSecP256R1FieldElement.GetX: TCryptoLibUInt32Array;
+begin
+  result := Fx;
+end;
+
+constructor TSecP256R1FieldElement.Create;
+begin
+  Inherited Create();
+  Fx := TNat256.Create();
+end;
+
+constructor TSecP256R1FieldElement.Create(const X: 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);
+end;
+
+constructor TSecP256R1FieldElement.Create(const X: TCryptoLibUInt32Array);
+begin
+  Inherited Create();
+  Fx := X;
+end;
+
+function TSecP256R1FieldElement.GetFieldName: string;
+begin
+  result := 'SecP256R1Field';
+end;
+
+function TSecP256R1FieldElement.GetFieldSize: Int32;
+begin
+  result := Q.BitLength;
+end;
+
+function TSecP256R1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
+{$ENDIF DELPHI}
+begin
+  result := Q.GetHashCode() xor TArrayUtils.GetArrayHashCode(Fx, 0, 8);
+end;
+
+function TSecP256R1FieldElement.GetIsOne: Boolean;
+begin
+  result := TNat256.IsOne(Fx);
+end;
+
+function TSecP256R1FieldElement.GetIsZero: Boolean;
+begin
+  result := TNat256.IsZero(Fx);
+end;
+
+function TSecP256R1FieldElement.Invert: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TMod.Invert(TSecP256R1Field.P, Fx, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.Multiply(const b: IECFieldElement)
+  : IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256R1Field.Multiply(Fx, (b as ISecP256R1FieldElement).X, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.Negate: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256R1Field.Negate(Fx, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.Sqrt: IECFieldElement;
+var
+  x1, t1, t2: 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;
+end;
+
+function TSecP256R1FieldElement.Square: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256R1Field.Square(Fx, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.Subtract(const b: IECFieldElement)
+  : IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256R1Field.Subtract(Fx, (b as ISecP256R1FieldElement).X, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.TestBitZero: Boolean;
+begin
+  result := TNat256.GetBit(Fx, 0) = 1;
+end;
+
+function TSecP256R1FieldElement.ToBigInteger: TBigInteger;
+begin
+  result := TNat256.ToBigInteger(Fx);
+end;
+
+function TSecP256R1FieldElement.Add(const b: IECFieldElement): IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256R1Field.Add(Fx, (b as ISecP256R1FieldElement).X, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.AddOne: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256R1Field.AddOne(Fx, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.Divide(const b: IECFieldElement)
+  : IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TMod.Invert(TSecP256R1Field.P, (b as ISecP256R1FieldElement).X, z);
+  TSecP256R1Field.Multiply(z, Fx, z);
+  result := TSecP256R1FieldElement.Create(z);
+end;
+
+function TSecP256R1FieldElement.Equals(const other
+  : ISecP256R1FieldElement): Boolean;
+begin
+  if ((Self as ISecP256R1FieldElement) = other) then
+  begin
+    result := true;
+    Exit;
+  end;
+  if (other = Nil) then
+  begin
+    result := false;
+    Exit;
+  end;
+  result := TNat256.Eq(Fx, other.X);
+end;
+
+function TSecP256R1FieldElement.Equals(const other: IECFieldElement): Boolean;
+begin
+  result := Equals(other as ISecP256R1FieldElement);
+end;
+
+end.

+ 406 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Point.pas

@@ -0,0 +1,406 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256R1Point;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpNat,
+  ClpNat256,
+  ClpECPoint,
+  ClpSecP256R1Field,
+  ClpISecP256R1Point,
+  ClpISecP256R1FieldElement,
+  ClpIECFieldElement,
+  ClpIECInterface,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
+
+type
+  TSecP256R1Point = class sealed(TAbstractFpPoint, ISecP256R1Point)
+
+  strict protected
+    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;
+
+  end;
+
+implementation
+
+uses
+  // included here to avoid circular dependency :)
+  ClpSecP256R1FieldElement;
+
+{ TSecP256R1Point }
+
+constructor TSecP256R1Point.Create(const curve: IECCurve;
+  const x, y: IECFieldElement);
+begin
+  Create(curve, x, y, false);
+end;
+
+constructor TSecP256R1Point.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;
+
+constructor TSecP256R1Point.Create(const curve: IECCurve;
+  const x, y: IECFieldElement;
+  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
+begin
+  Inherited Create(curve, x, y, zs, withCompression);
+end;
+
+function TSecP256R1Point.Add(const b: 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
+  begin
+    result := b;
+    Exit;
+  end;
+  if (b.IsInfinity) then
+  begin
+    result := Self as IECPoint;
+    Exit;
+  end;
+  if ((Self as IECPoint) = b) then
+  begin
+    result := Twice();
+    Exit;
+  end;
+
+  Lcurve := curve;
+
+  X1 := RawXCoord as ISecP256R1FieldElement;
+  Y1 := RawYCoord as ISecP256R1FieldElement;
+  X2 := b.RawXCoord as ISecP256R1FieldElement;
+  Y2 := b.RawYCoord as ISecP256R1FieldElement;
+
+  Z1 := RawZCoords[0] as ISecP256R1FieldElement;
+  Z2 := b.RawZCoords[0] as ISecP256R1FieldElement;
+
+  tt1 := TNat256.CreateExt();
+  t2 := TNat256.Create();
+  t3 := TNat256.Create();
+  t4 := TNat256.Create();
+
+  Z1IsOne := Z1.IsOne;
+
+  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);
+
+    TSecP256R1Field.Multiply(S2, Z1.x, S2);
+    TSecP256R1Field.Multiply(S2, Y2.x, S2);
+  end;
+
+  Z2IsOne := Z2.IsOne;
+  if (Z2IsOne) then
+  begin
+    U1 := X1.x;
+    S1 := Y1.x;
+  end
+  else
+  begin
+    S1 := t4;
+    TSecP256R1Field.Square(Z2.x, S1);
+
+    U1 := tt1;
+    TSecP256R1Field.Multiply(S1, X1.x, U1);
+
+    TSecP256R1Field.Multiply(S1, Z2.x, S1);
+    TSecP256R1Field.Multiply(S1, Y1.x, S1);
+  end;
+
+  H := TNat256.Create();
+  TSecP256R1Field.Subtract(U1, U2, H);
+
+  R := t2;
+  TSecP256R1Field.Subtract(S1, S2, R);
+
+  // 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;
+
+    // Self = -b, i.e. the result is the point at infinity
+    result := Lcurve.Infinity;
+    Exit;
+  end;
+
+  HSquared := t3;
+  TSecP256R1Field.Square(H, HSquared);
+
+  G := TNat256.Create();
+  TSecP256R1Field.Multiply(HSquared, H, G);
+
+  V := t3;
+  TSecP256R1Field.Multiply(HSquared, U1, V);
+
+  TSecP256R1Field.Negate(G, G);
+  TNat256.Mul(S1, G, tt1);
+
+  c := TNat256.AddBothTo(V, V, G);
+  TSecP256R1Field.Reduce32(c, G);
+
+  X3 := TSecP256R1FieldElement.Create(t4);
+  TSecP256R1Field.Square(R, X3.x);
+  TSecP256R1Field.Subtract(X3.x, G, X3.x);
+
+  Y3 := TSecP256R1FieldElement.Create(G);
+  TSecP256R1Field.Subtract(V, X3.x, Y3.x);
+  TSecP256R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+  TSecP256R1Field.Reduce(tt1, Y3.x);
+
+  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);
+
+  result := TSecP256R1Point.Create(Lcurve, X3, Y3, zs, IsCompressed)
+    as IECPoint;
+end;
+
+function TSecP256R1Point.Detach: IECPoint;
+begin
+  result := TSecP256R1Point.Create(Nil, AffineXCoord, AffineYCoord) as IECPoint;
+end;
+
+function TSecP256R1Point.Negate: IECPoint;
+begin
+  if (IsInfinity) then
+  begin
+    result := Self as IECPoint;
+    Exit;
+  end;
+
+  result := TSecP256R1Point.Create(curve, RawXCoord, RawYCoord.Negate(),
+    RawZCoords, IsCompressed) as IECPoint;
+end;
+
+function TSecP256R1Point.ThreeTimes: IECPoint;
+begin
+  if ((IsInfinity) or (RawYCoord.IsZero)) then
+  begin
+    result := Self as IECPoint;
+    Exit;
+  end;
+
+  // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+  result := Twice().Add(Self as IECPoint);
+end;
+
+function TSecP256R1Point.Twice: IECPoint;
+var
+  Lcurve: IECCurve;
+  Y1, X1, Z1, X3, Y3, Z3: ISecP256R1FieldElement;
+  c: UInt32;
+  Y1Squared, Z1Squared, t1, t2, T, M, S: TCryptoLibUInt32Array;
+  Z1IsOne: Boolean;
+begin
+
+  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
+  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);
+
+  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);
+
+  Z3 := TSecP256R1FieldElement.Create(M);
+  TSecP256R1Field.Twice(Y1.x, Z3.x);
+  if (not(Z1IsOne)) then
+  begin
+    TSecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+  end;
+
+  result := TSecP256R1Point.Create(Lcurve, X3, Y3,
+    TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed)
+    as IECPoint;
+end;
+
+function TSecP256R1Point.TwicePlus(const b: IECPoint): IECPoint;
+var
+  Y1: IECFieldElement;
+begin
+  if ((Self as IECPoint) = b) then
+  begin
+    result := ThreeTimes();
+    Exit;
+  end;
+  if (IsInfinity) then
+  begin
+    result := b;
+    Exit;
+  end;
+  if (b.IsInfinity) then
+  begin
+    result := Twice();
+    Exit;
+  end;
+
+  Y1 := RawYCoord;
+  if (Y1.IsZero) then
+  begin
+    result := b;
+    Exit;
+  end;
+
+  result := Twice().Add(b);
+end;
+
+end.

+ 29 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk

@@ -25,7 +25,7 @@
  Acknowledgements: 
 Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the development of this library "/>
     <Version Major="2" Minor="4"/>
-    <Files Count="446">
+    <Files Count="453">
       <Item1>
         <Filename Value="..\..\Asn1\ClpAsn1Encodable.pas"/>
         <UnitName Value="ClpAsn1Encodable"/>
@@ -1812,6 +1812,34 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecT283K1Curve.pas"/>
         <UnitName Value="ClpSecT283K1Curve"/>
       </Item446>
+      <Item447>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256R1Field.pas"/>
+        <UnitName Value="ClpSecP256R1Field"/>
+      </Item447>
+      <Item448>
+        <Filename Value="..\..\Interfaces\ClpISecP256R1FieldElement.pas"/>
+        <UnitName Value="ClpISecP256R1FieldElement"/>
+      </Item448>
+      <Item449>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256R1FieldElement.pas"/>
+        <UnitName Value="ClpSecP256R1FieldElement"/>
+      </Item449>
+      <Item450>
+        <Filename Value="..\..\Interfaces\ClpISecP256R1Point.pas"/>
+        <UnitName Value="ClpISecP256R1Point"/>
+      </Item450>
+      <Item451>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256R1Point.pas"/>
+        <UnitName Value="ClpSecP256R1Point"/>
+      </Item451>
+      <Item452>
+        <Filename Value="..\..\Interfaces\ClpISecP256R1Curve.pas"/>
+        <UnitName Value="ClpISecP256R1Curve"/>
+      </Item452>
+      <Item453>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256R1Curve.pas"/>
+        <UnitName Value="ClpSecP256R1Curve"/>
+      </Item453>
     </Files>
     <RequiredPkgs Count="3">
       <Item1>

+ 3 - 1
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas

@@ -146,7 +146,9 @@ uses
   ClpSecP521R1Point, ClpISecP521R1Point, ClpSecP521R1Curve, 
   ClpISecP521R1Curve, ClpInterleave, ClpSecT283Field, ClpSecT283FieldElement, 
   ClpISecT283FieldElement, ClpSecT283K1Point, ClpISecT283K1Point, 
-  ClpISecT283K1Curve, ClpSecT283K1Curve;
+  ClpISecT283K1Curve, ClpSecT283K1Curve, ClpSecP256R1Field, 
+  ClpISecP256R1FieldElement, ClpSecP256R1FieldElement, ClpISecP256R1Point, 
+  ClpSecP256R1Point, ClpISecP256R1Curve, ClpSecP256R1Curve;
 
 implementation