Browse Source

add SecP256K1 custom curve.

Ugochukwu Mmaduekwe 7 years ago
parent
commit
180fb4e5d2

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

@@ -467,7 +467,15 @@ uses
   SHA384HMacTests in '..\src\Crypto\SHA384HMacTests.pas',
   SHA512HMacTests in '..\src\Crypto\SHA512HMacTests.pas',
   RIPEMD128HMacTests in '..\src\Crypto\RIPEMD128HMacTests.pas',
-  RIPEMD160HMacTests in '..\src\Crypto\RIPEMD160HMacTests.pas';
+  RIPEMD160HMacTests in '..\src\Crypto\RIPEMD160HMacTests.pas',
+  ClpCustomNamedCurves in '..\..\CryptoLib\src\Crypto\EC\ClpCustomNamedCurves.pas',
+  ClpSecP256K1Field in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256K1Field.pas',
+  ClpSecP256K1FieldElement in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256K1FieldElement.pas',
+  ClpISecP256K1FieldElement in '..\..\CryptoLib\src\Interfaces\ClpISecP256K1FieldElement.pas',
+  ClpSecP256K1Point in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256K1Point.pas',
+  ClpISecP256K1Point in '..\..\CryptoLib\src\Interfaces\ClpISecP256K1Point.pas',
+  ClpSecP256K1Curve in '..\..\CryptoLib\src\Math\EC\Custom\Sec\ClpSecP256K1Curve.pas',
+  ClpISecP256K1Curve in '..\..\CryptoLib\src\Interfaces\ClpISecP256K1Curve.pas';
 
 begin
 

+ 18 - 17
CryptoLib.Tests/src/Math/EC/FixedPointTests.pas

@@ -36,6 +36,7 @@ uses
   ClpIECInterface,
   ClpBigInteger,
   ClpECNamedCurveTable,
+  ClpCustomNamedCurves,
   ClpFixedPointCombMultiplier,
   ClpIFixedPointCombMultiplier,
   ClpECAlgorithms,
@@ -89,10 +90,10 @@ var
   tempList: TList<String>;
   tempDict: TDictionary<String, String>;
   names: TCryptoLibStringArray;
-  x9, X9A: IX9ECParameters;
+  x9, X9A, X9B: IX9ECParameters;
   M: IFixedPointCombMultiplier;
   k: TBigInteger;
-  pRef, pA: IECPoint;
+  pRef, pA, pB: IECPoint;
 
 begin
   M := TFixedPointCombMultiplier.Create();
@@ -100,7 +101,7 @@ begin
   tempList := TList<String>.Create();
   try
     tempList.AddRange(TECNamedCurveTable.names); // get all collections
-    // tempList.AddRange(TCustomNamedCurves.Names);
+    tempList.AddRange(TCustomNamedCurves.names);
     tempDict := TDictionary<String, String>.Create();
     try
       for s in tempList do
@@ -118,15 +119,15 @@ begin
   for name in names do
   begin
     X9A := TECNamedCurveTable.GetByName(name);
-    // x9B := CustomNamedCurves.GetByName(name);
-    // if (x9B <> Nil) then
-    // begin
-    // x9 := x9B
-    // end
-    // else
-    // begin
-    x9 := X9A;
-    // end;
+    X9B := TCustomNamedCurves.GetByName(name);
+    if (X9B <> Nil) then
+    begin
+      x9 := X9B
+    end
+    else
+    begin
+      x9 := X9A;
+    end;
 
     i := 0;
     while i < TestsPerCurve do
@@ -140,11 +141,11 @@ begin
         AssertPointsEqual('Standard curve fixed-point failure', pRef, pA);
       end;
 
-      // if (x9B <> Nil) then
-      // begin
-      // pB := M.Multiply(x9B.G, k);
-      // AssertPointsEqual('Custom curve fixed-point failure', pRef, pB);
-      // end;
+      if (X9B <> Nil) then
+      begin
+        pB := M.Multiply(X9B.G, k);
+        AssertPointsEqual('Custom curve fixed-point failure', pRef, pB);
+      end;
       System.Inc(i);
     end;
 

+ 11 - 8
CryptoLib.Tests/src/Math/ECAlgorithmsTests.pas

@@ -42,6 +42,7 @@ uses
   ClpIECInterface,
   ClpBigInteger,
   ClpECNamedCurveTable,
+  ClpCustomNamedCurves,
   ClpECAlgorithms,
   ClpX9ECParameters,
   ClpIX9ECParameters,
@@ -243,7 +244,7 @@ begin
     tempList := TList<String>.Create();
     try
       tempList.AddRange(TECNamedCurveTable.names); // get all collections
-      // tempList.AddRange(TCustomNamedCurves.Names);
+      tempList.AddRange(TCustomNamedCurves.names);
       tempDict := TDictionary<String, String>.Create();
       try
         for s in tempList do
@@ -266,11 +267,11 @@ begin
         AddTestCurves(x9s, x9);
       end;
 
-      // x9 := TCustomNamedCurves.GetByName(name);
-      // if (x9 <> Nil) then
-      // begin
-      // AddTestCurves(x9s, x9);
-      // end;
+      x9 := TCustomNamedCurves.GetByName(name);
+      if (x9 <> Nil) then
+      begin
+        AddTestCurves(x9s, x9);
+      end;
     end;
     Result := x9s.ToArray;
   finally
@@ -294,7 +295,8 @@ var
   x9: IX9ECParameters;
 begin
   // x9 := TCustomNamedCurves.GetByName('secp256r1'); // original
-  x9 := TECNamedCurveTable.GetByName('secp256k1');
+  // x9 := TECNamedCurveTable.GetByName('secp256k1');
+  x9 := TCustomNamedCurves.GetByName('secp256k1');
   CheckNotNull(x9);
   DoTestSumOfMultiplies(x9);
 end;
@@ -314,7 +316,8 @@ var
   x9: IX9ECParameters;
 begin
   // x9 := TCustomNamedCurves.GetByName('secp256r1');  // original
-  x9 := TECNamedCurveTable.GetByName('secp256k1');
+  // x9 := TECNamedCurveTable.GetByName('secp256k1');
+  x9 := TCustomNamedCurves.GetByName('secp256k1');
   CheckNotNull(x9);
   DoTestSumOfTwoMultiplies(x9);
 end;

+ 62 - 59
CryptoLib.Tests/src/Math/ECPointTests.pas

@@ -33,6 +33,7 @@ uses
   TestFramework,
 {$ENDIF FPC}
   Generics.Collections,
+  ClpCustomNamedCurves,
   ClpECNamedCurveTable,
   ClpCryptoLibTypes,
   ClpSecureRandom,
@@ -44,7 +45,8 @@ uses
   ClpIFiniteField,
   ClpIX9ECParameters,
   ClpIECFieldElement,
-  ClpIECInterface;
+  ClpIECInterface,
+  ClpArrayUtils;
 
 type
 
@@ -111,10 +113,10 @@ type
     F2mInstance: TF2m;
 
     procedure AssertPointsEqual(const msg: String; const a, b: IECPoint);
-    // procedure AssertBigIntegersEqual(a, b: TBigInteger);
-    // procedure AssertIFiniteFieldsEqual(a, b: IFiniteField);
-    // procedure AssertOptionalValuesAgree(a, b: TBigInteger); overload;
-    // procedure AssertOptionalValuesAgree(a, b: TCryptoLibByteArray); overload;
+    procedure AssertBigIntegersEqual(a, b: TBigInteger);
+    procedure AssertIFiniteFieldsEqual(a, b: IFiniteField);
+    procedure AssertOptionalValuesAgree(a, b: TBigInteger); overload;
+    procedure AssertOptionalValuesAgree(a, b: TCryptoLibByteArray); overload;
 
     procedure AssertECFieldElementsEqual(const a, b: IECFieldElement);
 
@@ -261,31 +263,32 @@ begin
   CheckEquals(True, a.Equals(b));
 end;
 
-// procedure TTestECPoint.AssertBigIntegersEqual(a, b: TBigInteger);
-// begin
-// CheckEquals(True, a.Equals(b));
-// end;
+procedure TTestECPoint.AssertBigIntegersEqual(a, b: TBigInteger);
+begin
+  CheckEquals(True, a.Equals(b));
+end;
 
-// procedure TTestECPoint.AssertIFiniteFieldsEqual(a, b: IFiniteField);
-// begin
-// CheckEquals(True, (a as TObject).Equals(b as TObject));
-// end;
 //
-// procedure TTestECPoint.AssertOptionalValuesAgree(a, b: TBigInteger);
-// begin
-// if ((a.IsInitialized) and (b.IsInitialized)) then
-// begin
-// AssertBigIntegersEqual(a, b);
-// end;
-// end;
-//
-// procedure TTestECPoint.AssertOptionalValuesAgree(a, b: TCryptoLibByteArray);
-// begin
-// if ((a <> Nil) and (b <> Nil)) then
-// begin
-// CheckTrue(TArrayUtils.AreEqual(a, b));
-// end;
-// end;
+procedure TTestECPoint.AssertIFiniteFieldsEqual(a, b: IFiniteField);
+begin
+  CheckEquals(True, (a as TObject).Equals(b as TObject));
+end;
+
+procedure TTestECPoint.AssertOptionalValuesAgree(a, b: TBigInteger);
+begin
+  if ((a.IsInitialized) and (b.IsInitialized)) then
+  begin
+    AssertBigIntegersEqual(a, b);
+  end;
+end;
+
+procedure TTestECPoint.AssertOptionalValuesAgree(a, b: TCryptoLibByteArray);
+begin
+  if ((a <> Nil) and (b <> Nil)) then
+  begin
+    CheckTrue(TArrayUtils.AreEqual(a, b));
+  end;
+end;
 
 procedure TTestECPoint.AssertPointsEqual(const msg: String;
   const a, b: IECPoint);
@@ -581,15 +584,15 @@ var
   tempDict: TDictionary<String, String>;
   uniqNames: TCryptoLibStringArray;
   s, name: string;
-  x9A { , x9B } : IX9ECParameters;
-  // pA, pB: IECPoint;
-  // k: TBigInteger;
+  x9A, x9B: IX9ECParameters;
+  pA, pB: IECPoint;
+  k: TBigInteger;
 begin
 
   tempList := TList<String>.Create();
   try
     tempList.AddRange(TECNamedCurveTable.names); // get all collections
-    // tempList.AddRange(CustomNamedCurves.Names);
+    tempList.AddRange(TCustomNamedCurves.names);
     tempDict := TDictionary<String, String>.Create();
     try
       for s in tempList do
@@ -607,39 +610,39 @@ begin
   for name in uniqNames do
   begin
     x9A := TECNamedCurveTable.GetByName(name);
-    // x9B := TCustomNamedCurves.GetByName(name);
-
-    // if ((x9A <> Nil) and (x9B <> Nil)) then
-    // begin
-    // AssertIFiniteFieldsEqual(x9A.curve.Field, x9B.curve.Field);
-    // AssertBigIntegersEqual(x9A.curve.a.ToBigInteger(),
-    // x9B.curve.a.ToBigInteger());
-    // AssertBigIntegersEqual(x9A.curve.b.ToBigInteger(),
-    // x9B.curve.b.ToBigInteger());
-    // AssertOptionalValuesAgree(x9A.curve.Cofactor, x9B.curve.Cofactor);
-    // AssertOptionalValuesAgree(x9A.curve.Order, x9B.curve.Order);
-    //
-    // AssertPointsEqual('Custom curve base-point inconsistency', x9A.G, x9B.G);
-    //
-    // AssertBigIntegersEqual(x9A.H, x9B.H);
-    // AssertBigIntegersEqual(x9A.n, x9B.n);
-    // AssertOptionalValuesAgree(x9A.GetSeed(), x9B.GetSeed());
-    //
-    // k := TBigInteger.Create(x9A.n.BitLength, FRandom);
-    // pA := x9A.G.Multiply(k);
-    // pB := x9B.G.Multiply(k);
-    // AssertPointsEqual('Custom curve multiplication inconsistency', pA, pB);
-    // end;
+    x9B := TCustomNamedCurves.GetByName(name);
+
+    if ((x9A <> Nil) and (x9B <> Nil)) then
+    begin
+      AssertIFiniteFieldsEqual(x9A.curve.Field, x9B.curve.Field);
+      AssertBigIntegersEqual(x9A.curve.a.ToBigInteger(),
+        x9B.curve.a.ToBigInteger());
+      AssertBigIntegersEqual(x9A.curve.b.ToBigInteger(),
+        x9B.curve.b.ToBigInteger());
+      AssertOptionalValuesAgree(x9A.curve.Cofactor, x9B.curve.Cofactor);
+      AssertOptionalValuesAgree(x9A.curve.Order, x9B.curve.Order);
+
+      AssertPointsEqual('Custom curve base-point inconsistency', x9A.g, x9B.g);
+
+      AssertBigIntegersEqual(x9A.h, x9B.h);
+      AssertBigIntegersEqual(x9A.n, x9B.n);
+      AssertOptionalValuesAgree(x9A.GetSeed(), x9B.GetSeed());
+
+      k := TBigInteger.Create(x9A.n.BitLength, FRandom);
+      pA := x9A.g.Multiply(k);
+      pB := x9B.g.Multiply(k);
+      AssertPointsEqual('Custom curve multiplication inconsistency', pA, pB);
+    end;
 
     if (x9A <> Nil) then
     begin
       ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9A);
     end;
 
-    // if (x9B <> Nil) then
-    // begin
-    // ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9B);
-    // end;
+    if (x9B <> Nil) then
+    begin
+      ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9B);
+    end;
   end;
 end;
 

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

@@ -0,0 +1,303 @@
+{ *********************************************************************************** }
+{ *                              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 ClpCustomNamedCurves;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  Generics.Collections,
+  ClpHex,
+  ClpGlvTypeBParameters,
+  ClpIGlvTypeBEndomorphism,
+  ClpSecObjectIdentifiers,
+  ClpCryptoLibTypes,
+  ClpBigInteger,
+  ClpECCurve,
+  ClpSecP256K1Curve,
+  ClpISecP256K1Curve,
+  ClpIECInterface,
+  ClpX9ECPoint,
+  ClpIX9ECPoint,
+  ClpIDerObjectIdentifier,
+  ClpGlvTypeBEndomorphism,
+  ClpX9ECParameters,
+  ClpIX9ECParameters,
+  ClpX9ECParametersHolder,
+  ClpIX9ECParametersHolder,
+  ClpIGlvTypeBParameters;
+
+type
+  TCustomNamedCurves = class sealed(TObject)
+
+  strict private
+
+  class var
+
+    FnameToCurve: TDictionary<String, IX9ECParametersHolder>;
+    FnameToOid: TDictionary<String, IDerObjectIdentifier>;
+    FoidToCurve: TDictionary<IDerObjectIdentifier, IX9ECParametersHolder>;
+    FoidToName: TDictionary<IDerObjectIdentifier, String>;
+
+    Fnames: TList<String>;
+
+    class function GetNames: TCryptoLibStringArray; static; inline;
+
+    // class procedure DefineCurve(const name: String;
+    // const holder: IX9ECParametersHolder); static; inline;
+
+    class procedure DefineCurveWithOid(const name: String;
+      const oid: IDerObjectIdentifier; const holder: IX9ECParametersHolder);
+      static; inline;
+
+    // class procedure DefineCurveAlias(const name: String;
+    // const oid: IDerObjectIdentifier); static; inline;
+
+    // class function ConfigureCurve(const curve: IECCurve): IECCurve;
+    // static; inline;
+    class function ConfigureCurveGlv(const c: IECCurve;
+      const p: IGlvTypeBParameters): IECCurve; static; inline;
+
+    class constructor CreateSecNamedCurves();
+    class destructor DestroySecNamedCurves();
+
+  public
+    class function GetByName(const name: String): IX9ECParameters;
+      static; inline;
+    // /**
+    // * return the X9ECParameters object for the named curve represented by
+    // * the passed in object identifier. Null if the curve isn't present.
+    // *
+    // * @param oid an object identifier representing a named curve, if present.
+    // */
+    class function GetByOid(const oid: IDerObjectIdentifier): IX9ECParameters;
+      static; inline;
+    // /**
+    // * return the object identifier signified by the passed in name. Null
+    // * if there is no object identifier associated with name.
+    // *
+    // * @return the object identifier associated with name, if present.
+    // */
+    class function GetOid(const name: String): IDerObjectIdentifier;
+      static; inline;
+    // /**
+    // * return the named curve name represented by the given object identifier.
+    // */
+    class function GetName(const oid: IDerObjectIdentifier): String;
+      static; inline;
+    // /**
+    // * returns an enumeration containing the name strings for curves
+    // * contained in this structure.
+    // */
+    class property Names: TCryptoLibStringArray read GetNames;
+
+  type
+
+    /// <summary>
+    /// secp256k1
+    /// </summary>
+    TSecP256k1Holder = class sealed(TX9ECParametersHolder,
+      IX9ECParametersHolder)
+
+    strict protected
+      function CreateParameters(): IX9ECParameters; override;
+
+    public
+      class function Instance(): IX9ECParametersHolder; static;
+
+    end;
+
+  end;
+
+implementation
+
+{ TCustomNamedCurves }
+
+// class procedure TCustomNamedCurves.DefineCurve(const name: String;
+// const holder: IX9ECParametersHolder);
+// var
+// LName: string;
+// begin
+// LName := name;
+// Fnames.Add(LName);
+// LName := UpperCase(LName);
+// FnameToCurve.Add(LName, holder);
+// end;
+
+class procedure TCustomNamedCurves.DefineCurveWithOid(const name: String;
+  const oid: IDerObjectIdentifier; const holder: IX9ECParametersHolder);
+var
+  LName: string;
+begin
+  LName := name;
+  Fnames.Add(LName);
+  FoidToName.Add(oid, LName);
+  FoidToCurve.Add(oid, holder);
+  LName := UpperCase(LName);
+  FnameToOid.Add(LName, oid);
+  FnameToCurve.Add(LName, holder);
+end;
+
+// class procedure TCustomNamedCurves.DefineCurveAlias(const name: String;
+// const oid: IDerObjectIdentifier);
+// var
+// curve: IX9ECParametersHolder;
+// LName: string;
+// begin
+// LName := name;
+// if not(FoidToCurve.TryGetValue(oid, curve)) then
+// begin
+// raise EInvalidOperationCryptoLibException.Create('');
+// end;
+// LName := UpperCase(LName);
+// FnameToOid.Add(LName, oid);
+// FnameToCurve.Add(LName, curve);
+// end;
+//
+// class function TCustomNamedCurves.ConfigureCurve(const curve: IECCurve)
+// : IECCurve;
+// begin
+// result := curve;
+// end;
+
+class function TCustomNamedCurves.ConfigureCurveGlv(const c: IECCurve;
+  const p: IGlvTypeBParameters): IECCurve;
+var
+  glv: IGlvTypeBEndomorphism;
+begin
+  glv := TGlvTypeBEndomorphism.Create(c, p);
+  result := c.Configure().SetEndomorphism(glv).CreateCurve();
+end;
+
+class function TCustomNamedCurves.GetByOid(const oid: IDerObjectIdentifier)
+  : IX9ECParameters;
+var
+  holder: IX9ECParametersHolder;
+begin
+  if FoidToCurve.TryGetValue(oid, holder) then
+  begin
+    result := holder.Parameters
+  end
+  else
+  begin
+    result := Nil;
+  end;
+end;
+
+class function TCustomNamedCurves.GetOid(const name: String)
+  : IDerObjectIdentifier;
+begin
+  if not(FnameToOid.TryGetValue(UpperCase(name), result)) then
+  begin
+    result := Nil;
+  end;
+end;
+
+class function TCustomNamedCurves.GetByName(const name: String)
+  : IX9ECParameters;
+var
+  holder: IX9ECParametersHolder;
+begin
+  if FnameToCurve.TryGetValue(UpperCase(name), holder) then
+  begin
+    result := holder.Parameters
+  end
+  else
+  begin
+    result := Nil;
+  end;
+end;
+
+class function TCustomNamedCurves.GetName
+  (const oid: IDerObjectIdentifier): String;
+begin
+  if not(FoidToName.TryGetValue(oid, result)) then
+  begin
+    result := '';
+  end;
+end;
+
+class function TCustomNamedCurves.GetNames: TCryptoLibStringArray;
+begin
+  result := Fnames.ToArray();
+end;
+
+class constructor TCustomNamedCurves.CreateSecNamedCurves;
+begin
+  FnameToCurve := TDictionary<String, IX9ECParametersHolder>.Create();
+  FnameToOid := TDictionary<String, IDerObjectIdentifier>.Create();
+  FoidToCurve := TDictionary<IDerObjectIdentifier,
+    IX9ECParametersHolder>.Create();
+  FoidToName := TDictionary<IDerObjectIdentifier, String>.Create();
+
+  Fnames := TList<String>.Create();
+
+  DefineCurveWithOid('secp256k1', TSecObjectIdentifiers.SecP256k1,
+    TSecP256k1Holder.Instance);
+
+end;
+
+class destructor TCustomNamedCurves.DestroySecNamedCurves;
+begin
+  FnameToCurve.Free;
+  FnameToOid.Free;
+  FoidToCurve.Free;
+  FoidToName.Free;
+  Fnames.Free;
+end;
+
+{ TCustomNamedCurves.TSecP256k1Holder }
+
+function TCustomNamedCurves.TSecP256k1Holder.CreateParameters: IX9ECParameters;
+var
+  curve: IECCurve;
+  G: IX9ECPoint;
+  S: TCryptoLibByteArray;
+  glv: IGlvTypeBParameters;
+begin
+  S := Nil;
+  glv := TGlvTypeBParameters.Create
+    (TBigInteger.Create
+    ('7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', 16),
+    TBigInteger.Create
+    ('5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', 16),
+    TCryptoLibGenericArray<TBigInteger>.Create
+    (TBigInteger.Create('3086d221a7d46bcde86c90e49284eb15', 16),
+    TBigInteger.Create('-e4437ed6010e88286f547fa90abfe4c3', 16)),
+    TCryptoLibGenericArray<TBigInteger>.Create
+    (TBigInteger.Create('114ca50f7a8e2f3f657c1108d9d44cfd8', 16),
+    TBigInteger.Create('3086d221a7d46bcde86c90e49284eb15', 16)),
+    TBigInteger.Create('3086d221a7d46bcde86c90e49284eb153dab', 16),
+    TBigInteger.Create('e4437ed6010e88286f547fa90abfe4c42212', 16), 272);
+  curve := ConfigureCurveGlv(TSecP256K1Curve.Create() as ISecP256K1Curve, glv);
+  G := TX9ECPoint.Create(curve,
+    THex.Decode('04' +
+    '79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798' +
+    '483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8'));
+  result := TX9ECParameters.Create(curve, G, curve.Order, curve.Cofactor, S);
+end;
+
+class function TCustomNamedCurves.TSecP256k1Holder.Instance
+  : IX9ECParametersHolder;
+begin
+  result := TSecP256k1Holder.Create();
+end;
+
+end.

+ 6 - 6
CryptoLib/src/Crypto/Generators/ClpECKeyPairGenerator.pas

@@ -37,7 +37,7 @@ uses
   ClpIECInterface,
   ClpIFixedPointCombMultiplier,
   ClpSecObjectIdentifiers,
-  // ClpCustomNamedCurves,
+  ClpCustomNamedCurves,
   ClpECNamedCurveTable,
   ClpX9ObjectIdentifiers,
   ClpIX9ECParameters,
@@ -119,11 +119,11 @@ var
 begin
   // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
 
-  // ecP := TCustomNamedCurves.GetByOid(oid);
-  // if (ecP = Nil) then
-  // begin
-  ecP := TECNamedCurveTable.GetByOid(oid);
-  // end;
+  ecP := TCustomNamedCurves.GetByOid(oid);
+  if (ecP = Nil) then
+  begin
+    ecP := TECNamedCurveTable.GetByOid(oid);
+  end;
 
   result := ecP;
 end;

+ 2 - 2
CryptoLib/src/Interfaces/ClpIECInterface.pas

@@ -294,8 +294,8 @@ type
     function DecompressPoint(yTilde: Int32; X1: TBigInteger): IECPoint;
 
     property FieldSize: Int32 read GetFieldSize;
-    function FromBigInteger(x: TBigInteger): IECFieldElement;
-    function IsValidFieldElement(x: TBigInteger): Boolean;
+    function FromBigInteger(const x: TBigInteger): IECFieldElement;
+    function IsValidFieldElement(const x: TBigInteger): Boolean;
 
     function Configure(): IConfig;
     function ValidatePoint(const x, y: TBigInteger): IECPoint; overload;

+ 46 - 0
CryptoLib/src/Interfaces/ClpISecP256K1Curve.pas

@@ -0,0 +1,46 @@
+{ *********************************************************************************** }
+{ *                              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 ClpISecP256K1Curve;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIECInterface,
+  ClpIECFieldElement,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
+
+type
+  ISecP256K1LookupTable = Interface(IECLookupTable)
+    ['{0E204483-F303-49FD-AF66-0F30CF855CA9}']
+  end;
+
+type
+  ISecP256K1Curve = Interface(IAbstractFpCurve)
+    ['{BBE4D704-8562-4C17-9149-CA33CFE7611F}']
+
+    function GetQ: TBigInteger;
+    property Q: TBigInteger read GetQ;
+
+  end;
+
+implementation
+
+end.

+ 38 - 0
CryptoLib/src/Interfaces/ClpISecP256K1FieldElement.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 ClpISecP256K1FieldElement;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIECFieldElement,
+  ClpCryptoLibTypes;
+
+type
+  ISecP256K1FieldElement = Interface(IAbstractFpFieldElement)
+    ['{F283DDDA-CB65-45E0-9239-2A202F2F1462}']
+
+    function GetX: TCryptoLibUInt32Array;
+    property X: TCryptoLibUInt32Array read GetX;
+  end;
+
+implementation
+
+end.

+ 35 - 0
CryptoLib/src/Interfaces/ClpISecP256K1Point.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 ClpISecP256K1Point;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpIECInterface;
+
+type
+  ISecP256K1Point = Interface(IAbstractFpPoint)
+    ['{E3B94BCB-F6A0-4140-A04E-7C26B1D81B7F}']
+
+  end;
+
+implementation
+
+end.

+ 20 - 21
CryptoLib/src/Math/EC/ClpECCurve.pas

@@ -112,6 +112,9 @@ type
 
     constructor Create(const field: IFiniteField);
 
+    function GetFieldSize: Int32; virtual; abstract;
+    function GetInfinity: IECPoint; virtual; abstract;
+
     function CloneCurve(): IECCurve; virtual; abstract;
 
     function CreateRawPoint(const x, y: IECFieldElement;
@@ -172,11 +175,8 @@ type
 
     end;
 
-  function GetFieldSize: Int32; virtual; abstract;
-  function GetInfinity: IECPoint; virtual; abstract;
-
-  function FromBigInteger(x: TBigInteger): IECFieldElement; virtual; abstract;
-  function IsValidFieldElement(x: TBigInteger): Boolean; virtual; abstract;
+  function FromBigInteger(const x: TBigInteger): IECFieldElement; virtual; abstract;
+  function IsValidFieldElement(const x: TBigInteger): Boolean; virtual; abstract;
 
   function Configure(): IConfig; virtual;
   function ValidatePoint(const x, y: TBigInteger): IECPoint; overload; virtual;
@@ -339,7 +339,7 @@ type
 
   public
     destructor Destroy; override;
-    function IsValidFieldElement(x: TBigInteger): Boolean; override;
+    function IsValidFieldElement(const x: TBigInteger): Boolean; override;
 
   end;
 
@@ -368,8 +368,6 @@ type
   const
     FP_DEFAULT_COORDS = Int32(TECCurve.COORD_JACOBIAN_MODIFIED);
 
-    function GetQ: TBigInteger; virtual;
-
   strict protected
   var
     Fm_q, Fm_r: TBigInteger;
@@ -381,6 +379,10 @@ type
     constructor Create(const q, r: TBigInteger; const A, B: IECFieldElement;
       const Order, Cofactor: TBigInteger); overload;
 
+    function GetQ: TBigInteger; virtual;
+    function GetInfinity: IECPoint; override;
+    function GetFieldSize: Int32; override;
+
     function CloneCurve(): IECCurve; override;
     function CreateRawPoint(const x, y: IECFieldElement;
       withCompression: Boolean): IECPoint; overload; override;
@@ -396,10 +398,7 @@ type
 
     destructor Destroy; override;
 
-    function GetInfinity: IECPoint; override;
-    function GetFieldSize: Int32; override;
-
-    function FromBigInteger(x: TBigInteger): IECFieldElement; override;
+    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
     function ImportPoint(const p: IECPoint): IECPoint; override;
 
     function SupportsCoordinateSystem(coord: Int32): Boolean; override;
@@ -452,7 +451,7 @@ type
 
     destructor Destroy; override;
 
-    function IsValidFieldElement(x: TBigInteger): Boolean; override;
+    function IsValidFieldElement(const x: TBigInteger): Boolean; override;
 
     function CreatePoint(const x, y: TBigInteger; withCompression: Boolean)
       : IECPoint; override;
@@ -529,6 +528,9 @@ type
     function GetK3: Int32; inline;
 
   strict protected
+    function GetFieldSize: Int32; override;
+    function GetInfinity: IECPoint; override;
+
     function CloneCurve(): IECCurve; override;
     function CreateDefaultMultiplier(): IECMultiplier; override;
 
@@ -627,11 +629,8 @@ type
 
     destructor Destroy; override;
 
-    function GetFieldSize: Int32; override;
-    function GetInfinity: IECPoint; override;
-
     function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-    function FromBigInteger(x: TBigInteger): IECFieldElement; override;
+    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
 
     /// <summary>
     /// Return true if curve uses a Trinomial basis.
@@ -1253,7 +1252,7 @@ begin
   inherited Destroy;
 end;
 
-function TAbstractFpCurve.IsValidFieldElement(x: TBigInteger): Boolean;
+function TAbstractFpCurve.IsValidFieldElement(const x: TBigInteger): Boolean;
 begin
   Result := (x.IsInitialized) and (x.SignValue >= 0) and
     (x.CompareTo(field.Characteristic) < 0);
@@ -1324,7 +1323,7 @@ begin
   Result := TFpPoint.Create(Self as IECCurve, x, y, withCompression);
 end;
 
-function TFpCurve.FromBigInteger(x: TBigInteger): IECFieldElement;
+function TFpCurve.FromBigInteger(const x: TBigInteger): IECFieldElement;
 begin
   Result := TFpFieldElement.Create(Fm_q, Fm_r, x);
 end;
@@ -1528,7 +1527,7 @@ begin
   Result := TLongArray.Create(x).ModInverse(m, ks).ToBigInteger();
 end;
 
-function TAbstractF2mCurve.IsValidFieldElement(x: TBigInteger): Boolean;
+function TAbstractF2mCurve.IsValidFieldElement(const x: TBigInteger): Boolean;
 begin
   Result := (x.IsInitialized) and (x.SignValue >= 0) and
     (x.BitLength <= FieldSize);
@@ -1745,7 +1744,7 @@ begin
   inherited Destroy;
 end;
 
-function TF2mCurve.FromBigInteger(x: TBigInteger): IECFieldElement;
+function TF2mCurve.FromBigInteger(const x: TBigInteger): IECFieldElement;
 begin
   Result := TF2mFieldElement.Create(Fm, Fk1, Fk2, Fk3, x);
 end;

+ 27 - 20
CryptoLib/src/Math/EC/ClpECFieldElement.pas

@@ -51,16 +51,20 @@ resourcestring
 type
   TECFieldElement = class abstract(TInterfacedObject, IECFieldElement)
 
-  public
-
-    constructor Create();
-    destructor Destroy; override;
+  strict protected
 
     function GetBitLength: Int32; virtual;
     function GetIsOne: Boolean; virtual;
     function GetIsZero: Boolean; virtual;
+
     function GetFieldName: String; virtual; abstract;
     function GetFieldSize: Int32; virtual; abstract;
+
+  public
+
+    constructor Create();
+    destructor Destroy; override;
+
     function ToBigInteger(): TBigInteger; virtual; abstract;
     function Add(const b: IECFieldElement): IECFieldElement; virtual; abstract;
     function AddOne(): IECFieldElement; virtual; abstract;
@@ -91,7 +95,8 @@ type
 
     function TestBitZero(): Boolean; virtual;
 
-    function Equals(const other: IECFieldElement): Boolean; reintroduce;
+    function Equals(const other: IECFieldElement): Boolean;
+      reintroduce; virtual;
 
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -136,14 +141,6 @@ type
     function ModReduce(x: TBigInteger): TBigInteger; virtual;
     function ModSubtract(const x1, x2: TBigInteger): TBigInteger; virtual;
 
-  public
-    constructor Create(const Q, x: TBigInteger); overload;
-      deprecated 'Use ECCurve.FromBigInteger to construct field elements';
-
-    constructor Create(const Q, r, x: TBigInteger); overload;
-
-    destructor Destroy; override;
-
     /// <summary>
     /// return the field name for this field.
     /// </summary>
@@ -153,6 +150,14 @@ type
     function GetFieldName: String; override;
     function GetFieldSize: Int32; override;
 
+  public
+    constructor Create(const Q, x: TBigInteger); overload;
+      deprecated 'Use ECCurve.FromBigInteger to construct field elements';
+
+    constructor Create(const Q, r, x: TBigInteger); overload;
+
+    destructor Destroy; override;
+
     function ToBigInteger(): TBigInteger; override;
 
     function Add(const b: IECFieldElement): IECFieldElement; override;
@@ -240,6 +245,15 @@ type
     function GetK2: Int32; inline;
     function GetK3: Int32; inline;
 
+  strict protected
+
+    function GetBitLength: Int32; override;
+    function GetIsOne: Boolean; override;
+    function GetIsZero: Boolean; override;
+
+    function GetFieldName: String; override;
+    function GetFieldSize: Int32; override;
+
   public
 
     const
@@ -296,13 +310,6 @@ type
 
     destructor Destroy; override;
 
-    function GetBitLength: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
-    function GetFieldName: String; override;
-    function GetFieldSize: Int32; override;
-
     function TestBitZero(): Boolean; override;
     function ToBigInteger(): TBigInteger; override;
 

+ 259 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Curve.pas

@@ -0,0 +1,259 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256K1Curve;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpHex,
+  ClpBits,
+  ClpNat256,
+  ClpECCurve,
+  ClpIECInterface,
+  ClpISecP256K1FieldElement,
+  ClpSecP256K1Point,
+  ClpISecP256K1Curve,
+  ClpISecP256K1Point,
+  ClpIECFieldElement,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
+
+type
+  TSecP256K1Curve = class sealed(TAbstractFpCurve, ISecP256K1Curve)
+
+  strict private
+
+  type
+    TSecP256K1LookupTable = class sealed(TInterfacedObject,
+      ISecP256K1LookupTable, IECLookupTable)
+
+    strict private
+    var
+      Fm_outer: ISecP256K1Curve;
+      Fm_table: TCryptoLibUInt32Array;
+      Fm_size: Int32;
+
+      function GetSize: Int32; virtual;
+
+    public
+
+      constructor Create(const outer: ISecP256K1Curve;
+        table: TCryptoLibUInt32Array; size: Int32);
+
+      function Lookup(index: Int32): IECPoint; virtual;
+
+      property size: Int32 read GetSize;
+
+    end;
+
+  const
+    SECP256K1_DEFAULT_COORDS = Int32(TECCurve.COORD_JACOBIAN);
+    SECP256K1_FE_INTS = Int32(8);
+
+    class var
+
+      Fq: TBigInteger;
+
+    class function GetSecP256K1Curve_Q: TBigInteger; static; inline;
+    class constructor SecP256K1Curve();
+
+  strict protected
+  var
+    Fm_infinity: ISecP256K1Point;
+
+    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;
+      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
+      (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 SecP256K1Curve_Q: TBigInteger read GetSecP256K1Curve_Q;
+
+  end;
+
+implementation
+
+uses
+  // included here to avoid circular dependency :)
+  ClpSecP256K1FieldElement;
+
+{ TSecP256K1Curve }
+
+class function TSecP256K1Curve.GetSecP256K1Curve_Q: TBigInteger;
+begin
+  result := Fq;
+end;
+
+class constructor TSecP256K1Curve.SecP256K1Curve;
+begin
+  Fq := TBigInteger.Create(1,
+    THex.Decode
+    ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'));
+end;
+
+constructor TSecP256K1Curve.Create;
+begin
+  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;
+end;
+
+function TSecP256K1Curve.CloneCurve: IECCurve;
+begin
+  result := TSecP256K1Curve.Create();
+end;
+
+function TSecP256K1Curve.CreateCacheSafeLookupTable
+  (points: TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
+var
+  table: TCryptoLibUInt32Array;
+  pos, i: Int32;
+  p: IECPoint;
+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);
+end;
+
+function TSecP256K1Curve.CreateRawPoint(const x, y: IECFieldElement;
+  withCompression: Boolean): IECPoint;
+begin
+  result := TSecP256K1Point.Create(Self as IECCurve, x, y, withCompression);
+end;
+
+function TSecP256K1Curve.CreateRawPoint(const x, y: IECFieldElement;
+  zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
+  : IECPoint;
+begin
+  result := TSecP256K1Point.Create(Self as IECCurve, x, y, zs, withCompression);
+end;
+
+function TSecP256K1Curve.FromBigInteger(const x: TBigInteger): IECFieldElement;
+begin
+  result := TSecP256K1FieldElement.Create(x);
+end;
+
+function TSecP256K1Curve.GetFieldSize: Int32;
+begin
+  result := Fq.BitLength;
+end;
+
+function TSecP256K1Curve.GetInfinity: IECPoint;
+begin
+  result := Fm_infinity;
+end;
+
+function TSecP256K1Curve.GetQ: TBigInteger;
+begin
+  result := Fq;
+end;
+
+function TSecP256K1Curve.SupportsCoordinateSystem(coord: Int32): Boolean;
+begin
+  case coord of
+    COORD_JACOBIAN:
+      result := True
+  else
+    result := False;
+  end;
+end;
+
+{ TSecP256K1Curve.TSecP256K1LookupTable }
+
+constructor TSecP256K1Curve.TSecP256K1LookupTable.Create
+  (const outer: ISecP256K1Curve; table: TCryptoLibUInt32Array; size: Int32);
+begin
+  Inherited Create();
+  Fm_outer := outer;
+  Fm_table := table;
+  Fm_size := size;
+end;
+
+function TSecP256K1Curve.TSecP256K1LookupTable.GetSize: Int32;
+begin
+  result := Fm_size;
+end;
+
+function TSecP256K1Curve.TSecP256K1LookupTable.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(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 := Fm_outer.CreateRawPoint(TSecP256K1FieldElement.Create(x)
+    as ISecP256K1FieldElement, TSecP256K1FieldElement.Create(y)
+    as ISecP256K1FieldElement, False);
+end;
+
+end.

+ 285 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Field.pas

@@ -0,0 +1,285 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256K1Field;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpNat,
+  ClpNat256,
+  ClpBigInteger,
+  ClpCryptoLibTypes;
+
+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 constructor CreateSecP256K1Field();
+
+  public
+    class procedure Add(x, y, z: TCryptoLibUInt32Array); static; inline;
+    class procedure AddExt(xx, yy, zz: TCryptoLibUInt32Array); static; inline;
+    class procedure AddOne(x, z: TCryptoLibUInt32Array); static; inline;
+    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt32Array;
+      static; inline;
+    class procedure Half(x, z: TCryptoLibUInt32Array); static; inline;
+    class procedure Multiply(x, y, z: TCryptoLibUInt32Array); static; inline;
+    class procedure MultiplyAddToExt(x, y, zz: TCryptoLibUInt32Array);
+      static; inline;
+    class procedure Negate(x, z: TCryptoLibUInt32Array); static; inline;
+    class procedure Reduce(xx, z: TCryptoLibUInt32Array); static; inline;
+    class procedure Reduce32(x: UInt32; z: TCryptoLibUInt32Array);
+      static; inline;
+    class procedure Square(x, z: TCryptoLibUInt32Array); static; inline;
+    class procedure SquareN(x: TCryptoLibUInt32Array; n: Int32;
+      z: TCryptoLibUInt32Array); static; inline;
+    class procedure Subtract(x, y, z: TCryptoLibUInt32Array); static; inline;
+    class procedure SubtractExt(xx, yy, zz: TCryptoLibUInt32Array);
+      static; inline;
+    class procedure Twice(x, z: TCryptoLibUInt32Array); static; inline;
+
+    class property P: TCryptoLibUInt32Array read GetP;
+  end;
+
+implementation
+
+{ TSecP256K1Field }
+
+class constructor TSecP256K1Field.CreateSecP256K1Field;
+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);
+end;
+
+class function TSecP256K1Field.GetP: TCryptoLibUInt32Array;
+begin
+  result := FP;
+end;
+
+class procedure TSecP256K1Field.Add(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
+    TNat.Add33To(8, PInv33, z);
+  end;
+end;
+
+class procedure TSecP256K1Field.AddExt(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
+    if (TNat.AddTo(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
+    begin
+      TNat.IncAt(16, zz, System.Length(FPExtInv));
+    end;
+  end;
+end;
+
+class procedure TSecP256K1Field.AddOne(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
+    TNat.Add33To(8, PInv33, z);
+  end;
+end;
+
+class function TSecP256K1Field.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 TSecP256K1Field.Half(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 TSecP256K1Field.Reduce(xx, z: TCryptoLibUInt32Array);
+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;
+end;
+
+class procedure TSecP256K1Field.Multiply(x, y, z: TCryptoLibUInt32Array);
+var
+  tt: TCryptoLibUInt32Array;
+begin
+  tt := TNat256.CreateExt();
+  TNat256.Mul(x, y, tt);
+  Reduce(tt, z);
+end;
+
+class procedure TSecP256K1Field.MultiplyAddToExt(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
+    if (TNat.AddTo(System.Length(FPExtInv), FPExtInv, zz) <> 0) then
+    begin
+      TNat.IncAt(16, zz, System.Length(FPExtInv));
+    end;
+  end;
+end;
+
+class procedure TSecP256K1Field.Negate(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 TSecP256K1Field.Reduce32(x: UInt32; z: TCryptoLibUInt32Array);
+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;
+end;
+
+class procedure TSecP256K1Field.Square(x, z: TCryptoLibUInt32Array);
+var
+  tt: TCryptoLibUInt32Array;
+begin
+  tt := TNat256.CreateExt();
+  TNat256.Square(x, tt);
+  Reduce(tt, z);
+end;
+
+class procedure TSecP256K1Field.SquareN(x: TCryptoLibUInt32Array; n: Int32;
+  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 TSecP256K1Field.Subtract(x, y, z: TCryptoLibUInt32Array);
+var
+  c: Int32;
+begin
+  c := TNat256.Sub(x, y, z);
+  if (c <> 0) then
+  begin
+    TNat.Sub33From(8, PInv33, z);
+  end;
+end;
+
+class procedure TSecP256K1Field.SubtractExt(xx, yy, zz: TCryptoLibUInt32Array);
+var
+  c: 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;
+end;
+
+class procedure TSecP256K1Field.Twice(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
+    TNat.Add33To(8, PInv33, z);
+  end;
+end;
+
+end.

+ 347 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1FieldElement.pas

@@ -0,0 +1,347 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256K1FieldElement;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpNat256,
+  ClpMod,
+  ClpSecP256K1Curve,
+  ClpECFieldElement,
+  ClpIECFieldElement,
+  ClpSecP256K1Field,
+  ClpISecP256K1FieldElement,
+  ClpBigInteger,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SInvalidValueForSecP256K1FieldElement =
+    'Value Invalid for SecP256K1FieldElement "%s"';
+
+type
+  TSecP256K1FieldElement = class(TAbstractFpFieldElement,
+    ISecP256K1FieldElement)
+
+  strict private
+
+    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(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 Equals(const other: ISecP256K1FieldElement): Boolean;
+      reintroduce; overload;
+
+    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
+
+{ TSecP256K1FieldElement }
+
+class function TSecP256K1FieldElement.GetQ: TBigInteger;
+begin
+  result := TSecP256K1Curve.SecP256K1Curve_Q;
+end;
+
+function TSecP256K1FieldElement.GetX: TCryptoLibUInt32Array;
+begin
+  result := Fx;
+end;
+
+constructor TSecP256K1FieldElement.Create;
+begin
+  Inherited Create();
+  Fx := TNat256.Create();
+end;
+
+constructor TSecP256K1FieldElement.Create(const X: TBigInteger);
+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);
+end;
+
+constructor TSecP256K1FieldElement.Create(X: TCryptoLibUInt32Array);
+begin
+  Inherited Create();
+  Fx := X;
+end;
+
+function TSecP256K1FieldElement.GetFieldName: string;
+begin
+  result := 'SecP256K1Field';
+end;
+
+function TSecP256K1FieldElement.GetFieldSize: Int32;
+begin
+  result := Q.BitLength;
+end;
+
+function TSecP256K1FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
+{$ENDIF DELPHI}
+begin
+  result := Q.GetHashCode() xor TArrayUtils.GetArrayHashCode(Fx, 0, 8);
+end;
+
+function TSecP256K1FieldElement.GetIsOne: Boolean;
+begin
+  result := TNat256.IsOne(Fx);
+end;
+
+function TSecP256K1FieldElement.GetIsZero: Boolean;
+begin
+  result := TNat256.IsZero(Fx);
+end;
+
+function TSecP256K1FieldElement.Invert: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TMod.Invert(TSecP256K1Field.P, Fx, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.Multiply(const b: IECFieldElement)
+  : IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256K1Field.Multiply(Fx, (b as ISecP256K1FieldElement).X, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.Negate: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256K1Field.Negate(Fx, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.Sqrt: 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;
+end;
+
+function TSecP256K1FieldElement.Square: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256K1Field.Square(Fx, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.Subtract(const b: IECFieldElement)
+  : IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256K1Field.Subtract(Fx, (b as ISecP256K1FieldElement).X, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.TestBitZero: Boolean;
+begin
+  result := TNat256.GetBit(Fx, 0) = 1;
+end;
+
+function TSecP256K1FieldElement.ToBigInteger: TBigInteger;
+begin
+  result := TNat256.ToBigInteger(Fx);
+end;
+
+function TSecP256K1FieldElement.Add(const b: IECFieldElement): IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256K1Field.Add(Fx, (b as ISecP256K1FieldElement).X, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.AddOne: IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TSecP256K1Field.AddOne(Fx, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.Divide(const b: IECFieldElement)
+  : IECFieldElement;
+var
+  z: TCryptoLibUInt32Array;
+begin
+  z := TNat256.Create();
+  TMod.Invert(TSecP256K1Field.P, (b as ISecP256K1FieldElement).X, z);
+  TSecP256K1Field.Multiply(z, Fx, z);
+  result := TSecP256K1FieldElement.Create(z);
+end;
+
+function TSecP256K1FieldElement.Equals(const other
+  : ISecP256K1FieldElement): Boolean;
+begin
+  if ((Self as ISecP256K1FieldElement) = other) then
+  begin
+    result := true;
+    Exit;
+  end;
+  if (other = Nil) then
+  begin
+    result := false;
+    Exit;
+  end;
+  result := TNat256.Eq(Fx, other.X);
+end;
+
+function TSecP256K1FieldElement.Equals(const other: IECFieldElement): Boolean;
+begin
+  result := Equals(other as ISecP256K1FieldElement);
+end;
+
+end.

+ 391 - 0
CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Point.pas

@@ -0,0 +1,391 @@
+{ *********************************************************************************** }
+{ *                              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 ClpSecP256K1Point;
+
+{$I ..\..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpNat,
+  ClpNat256,
+  ClpECPoint,
+  ClpSecP256K1Field,
+  ClpISecP256K1Point,
+  ClpISecP256K1FieldElement,
+  ClpIECFieldElement,
+  ClpIECInterface,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
+
+type
+  TSecP256K1Point = class sealed(TAbstractFpPoint, ISecP256K1Point)
+
+  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;
+      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 :)
+  ClpSecP256K1FieldElement;
+
+{ TSecP256K1Point }
+
+constructor TSecP256K1Point.Create(const curve: IECCurve;
+  const x, y: IECFieldElement);
+begin
+  Create(curve, x, y, false);
+end;
+
+constructor TSecP256K1Point.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 TSecP256K1Point.Create(const curve: IECCurve;
+  const x, y: IECFieldElement; zs: TCryptoLibGenericArray<IECFieldElement>;
+  withCompression: Boolean);
+begin
+  Inherited Create(curve, x, y, zs, withCompression);
+end;
+
+function TSecP256K1Point.Add(const b: 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
+  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 ISecP256K1FieldElement;
+  Y1 := RawYCoord as ISecP256K1FieldElement;
+  X2 := b.RawXCoord as ISecP256K1FieldElement;
+  Y2 := b.RawYCoord as ISecP256K1FieldElement;
+
+  Z1 := RawZCoords[0] as ISecP256K1FieldElement;
+  Z2 := b.RawZCoords[0] as ISecP256K1FieldElement;
+
+  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;
+    TSecP256K1Field.Square(Z1.x, S2);
+
+    U2 := t2;
+    TSecP256K1Field.Multiply(S2, X2.x, U2);
+
+    TSecP256K1Field.Multiply(S2, Z1.x, S2);
+    TSecP256K1Field.Multiply(S2, Y2.x, S2);
+  end;
+
+  Z2IsOne := Z2.IsOne;
+  if (Z2IsOne) then
+  begin
+    U1 := X1.x;
+    S1 := Y1.x;
+  end
+  else
+  begin
+    S1 := t4;
+    TSecP256K1Field.Square(Z2.x, S1);
+
+    U1 := tt1;
+    TSecP256K1Field.Multiply(S1, X1.x, U1);
+
+    TSecP256K1Field.Multiply(S1, Z2.x, S1);
+    TSecP256K1Field.Multiply(S1, Y1.x, S1);
+  end;
+
+  H := TNat256.Create();
+  TSecP256K1Field.Subtract(U1, U2, H);
+
+  R := t2;
+  TSecP256K1Field.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;
+  TSecP256K1Field.Square(H, HSquared);
+
+  G := TNat256.Create();
+  TSecP256K1Field.Multiply(HSquared, H, G);
+
+  V := t3;
+  TSecP256K1Field.Multiply(HSquared, U1, V);
+
+  TSecP256K1Field.Negate(G, G);
+  TNat256.Mul(S1, G, tt1);
+
+  c := TNat256.AddBothTo(V, V, G);
+  TSecP256K1Field.Reduce32(c, G);
+
+  X3 := TSecP256K1FieldElement.Create(t4);
+  TSecP256K1Field.Square(R, X3.x);
+  TSecP256K1Field.Subtract(X3.x, G, X3.x);
+
+  Y3 := TSecP256K1FieldElement.Create(G);
+  TSecP256K1Field.Subtract(V, X3.x, Y3.x);
+  TSecP256K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+  TSecP256K1Field.Reduce(tt1, Y3.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;
+
+  zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3);
+
+  result := TSecP256K1Point.Create(Lcurve, X3, Y3, zs, IsCompressed)
+    as IECPoint;
+end;
+
+function TSecP256K1Point.Detach: IECPoint;
+begin
+  result := TSecP256K1Point.Create(Nil, AffineXCoord, AffineYCoord) as IECPoint;
+end;
+
+function TSecP256K1Point.Negate: IECPoint;
+begin
+  if (IsInfinity) then
+  begin
+    result := Self as IECPoint;
+    Exit;
+  end;
+
+  result := TSecP256K1Point.Create(curve, RawXCoord, RawYCoord.Negate(),
+    RawZCoords, IsCompressed) as IECPoint;
+end;
+
+function TSecP256K1Point.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 TSecP256K1Point.Twice: IECPoint;
+var
+  Lcurve: IECCurve;
+  Y1, X1, Z1, X3, Y3, Z3: ISecP256K1FieldElement;
+  c: UInt32;
+  Y1Squared, T, M, S, t1: TCryptoLibUInt32Array;
+begin
+
+  if (IsInfinity) then
+  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;
+
+  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);
+
+  Z3 := TSecP256K1FieldElement.Create(M);
+  TSecP256K1Field.Twice(Y1.x, Z3.x);
+  if (not(Z1.IsOne)) then
+  begin
+    TSecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+  end;
+
+  result := TSecP256K1Point.Create(Lcurve, X3, Y3,
+    TCryptoLibGenericArray<IECFieldElement>.Create(Z3), IsCompressed)
+    as IECPoint;
+end;
+
+function TSecP256K1Point.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.

+ 34 - 2
CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk

@@ -10,7 +10,7 @@
       <PathDelim Value="\"/>
       <SearchPaths>
         <IncludeFiles Value="..\..\Include"/>
-        <OtherUnitFiles Value="..\..\Asn1;..\..\Asn1\CryptoPro;..\..\Asn1\Nist;..\..\Asn1\Oiw;..\..\Asn1\Pkcs;..\..\Asn1\RossStandart;..\..\Asn1\Sec;..\..\Asn1\TeleTrust;..\..\Asn1\X9;..\..\Crypto;..\..\Crypto\Generators;..\..\Crypto\Parameters;..\..\Crypto\Prng;..\..\Crypto\Signers;..\..\Interfaces;..\..\Math;..\..\Math\EC;..\..\Math\EC\Abc;..\..\Math\EC\Endo;..\..\Math\EC\Multiplier;..\..\Math\Field;..\..\Math\Raw;..\..\Security;..\..\Utils;..\..\Utils\Collections;..\..\Utils\Encoders;..\..\Utils\Helpers;..\..\Utils\IO;..\..\Utils\Randoms;..\..\Utils\Rng;..\..\Crypto\Modes;..\..\Crypto\Paddings;..\..\Crypto\Engines;..\..\Crypto\Parsers;..\..\Crypto\Agreement;..\..\Crypto\Macs;..\..\Asn1\Misc;..\..\Asn1\Iana;..\..\Crypto\Digests;..\..\Asn1\X509"/>
+        <OtherUnitFiles Value="..\..\Asn1;..\..\Asn1\CryptoPro;..\..\Asn1\Nist;..\..\Asn1\Oiw;..\..\Asn1\Pkcs;..\..\Asn1\RossStandart;..\..\Asn1\Sec;..\..\Asn1\TeleTrust;..\..\Asn1\X9;..\..\Crypto;..\..\Crypto\Generators;..\..\Crypto\Parameters;..\..\Crypto\Prng;..\..\Crypto\Signers;..\..\Interfaces;..\..\Math;..\..\Math\EC;..\..\Math\EC\Abc;..\..\Math\EC\Endo;..\..\Math\EC\Multiplier;..\..\Math\Field;..\..\Math\Raw;..\..\Security;..\..\Utils;..\..\Utils\Collections;..\..\Utils\Encoders;..\..\Utils\Helpers;..\..\Utils\IO;..\..\Utils\Randoms;..\..\Utils\Rng;..\..\Crypto\Modes;..\..\Crypto\Paddings;..\..\Crypto\Engines;..\..\Crypto\Parsers;..\..\Crypto\Agreement;..\..\Crypto\Macs;..\..\Asn1\Misc;..\..\Asn1\Iana;..\..\Crypto\Digests;..\..\Asn1\X509;..\..\Crypto\EC;..\..\Math\EC\Custom\Sec"/>
         <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
       </SearchPaths>
       <CodeGeneration>
@@ -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="3"/>
-    <Files Count="413">
+    <Files Count="421">
       <Item1>
         <Filename Value="..\..\Asn1\ClpAsn1Encodable.pas"/>
         <UnitName Value="ClpAsn1Encodable"/>
@@ -1680,6 +1680,38 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel
         <Filename Value="..\..\Interfaces\ClpIAesLightEngine.pas"/>
         <UnitName Value="ClpIAesLightEngine"/>
       </Item413>
+      <Item414>
+        <Filename Value="..\..\Crypto\EC\ClpCustomNamedCurves.pas"/>
+        <UnitName Value="ClpCustomNamedCurves"/>
+      </Item414>
+      <Item415>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256K1Field.pas"/>
+        <UnitName Value="ClpSecP256K1Field"/>
+      </Item415>
+      <Item416>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256K1FieldElement.pas"/>
+        <UnitName Value="ClpSecP256K1FieldElement"/>
+      </Item416>
+      <Item417>
+        <Filename Value="..\..\Interfaces\ClpISecP256K1FieldElement.pas"/>
+        <UnitName Value="ClpISecP256K1FieldElement"/>
+      </Item417>
+      <Item418>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256K1Point.pas"/>
+        <UnitName Value="ClpSecP256K1Point"/>
+      </Item418>
+      <Item419>
+        <Filename Value="..\..\Interfaces\ClpISecP256K1Point.pas"/>
+        <UnitName Value="ClpISecP256K1Point"/>
+      </Item419>
+      <Item420>
+        <Filename Value="..\..\Math\EC\Custom\Sec\ClpSecP256K1Curve.pas"/>
+        <UnitName Value="ClpSecP256K1Curve"/>
+      </Item420>
+      <Item421>
+        <Filename Value="..\..\Interfaces\ClpISecP256K1Curve.pas"/>
+        <UnitName Value="ClpISecP256K1Curve"/>
+      </Item421>
     </Files>
     <RequiredPkgs Count="3">
       <Item1>

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

@@ -136,7 +136,9 @@ uses
   ClpIValidityPrecompInfo, ClpDsaParametersGenerator, ClpDsaParameter, 
   ClpIDsaParameter, ClpIKeyEncoder, ClpIDsaParametersGenerator, 
   ClpIPreCompCallBack, ClpNistNamedCurves, ClpNat256, ClpNat320, 
-  ClpAesLightEngine, ClpIAesLightEngine;
+  ClpAesLightEngine, ClpIAesLightEngine, ClpCustomNamedCurves, 
+  ClpSecP256K1Field, ClpSecP256K1FieldElement, ClpISecP256K1FieldElement, 
+  ClpSecP256K1Point, ClpISecP256K1Point, ClpSecP256K1Curve, ClpISecP256K1Curve;
 
 implementation
 

+ 54 - 0
CryptoLib/src/Utils/ClpArrayUtils.pas

@@ -59,6 +59,12 @@ type
     class function GetArrayHashCode(const data: TCryptoLibInt32Array): Int32;
       overload; static;
 
+    class function GetArrayHashCode(const data: TCryptoLibUInt32Array): Int32;
+      overload; static;
+
+    class function GetArrayHashCode(const data: TCryptoLibUInt32Array;
+      off, len: Int32): Int32; overload; static;
+
     class function Prepend(const A: TCryptoLibByteArray; B: Byte)
       : TCryptoLibByteArray; static;
 
@@ -262,6 +268,54 @@ begin
   Result := hc;
 end;
 
+class function TArrayUtils.GetArrayHashCode(const data
+  : TCryptoLibUInt32Array): Int32;
+var
+  i, hc: Int32;
+begin
+  if data = Nil then
+  begin
+    Result := 0;
+    Exit;
+  end;
+
+  i := System.Length(data);
+  hc := i + 1;
+
+  System.Dec(i);
+  while (i >= 0) do
+  begin
+    hc := hc * 257;
+    hc := hc xor data[i];
+    System.Dec(i);
+  end;
+  Result := hc;
+end;
+
+class function TArrayUtils.GetArrayHashCode(const data: TCryptoLibUInt32Array;
+  off, len: Int32): Int32;
+var
+  i, hc: Int32;
+begin
+  if data = Nil then
+  begin
+    Result := 0;
+    Exit;
+  end;
+
+  i := len;
+  hc := i + 1;
+
+  System.Dec(i);
+  while (i >= 0) do
+  begin
+    hc := hc * 257;
+    hc := hc xor data[off + i];
+    System.Dec(i);
+  end;
+  Result := hc;
+end;
+
 class function TArrayUtils.Prepend(const A: TCryptoLibByteArray; B: Byte)
   : TCryptoLibByteArray;
 var