diff --git a/CryptoLib.Benchmark/Delphi/CryptoLib.BenchmarkConsole.dpr b/CryptoLib.Benchmark/Delphi/CryptoLib.BenchmarkConsole.dpr index c36af03c..3bdc610e 100644 --- a/CryptoLib.Benchmark/Delphi/CryptoLib.BenchmarkConsole.dpr +++ b/CryptoLib.Benchmark/Delphi/CryptoLib.BenchmarkConsole.dpr @@ -389,6 +389,12 @@ uses ClpMacUtilities in '..\..\CryptoLib\src\Crypto\Macs\ClpMacUtilities.pas', ClpMiscObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Misc\ClpMiscObjectIdentifiers.pas', ClpMultipliers in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpMultipliers.pas', + ClpIFpFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIFpFieldOps.pas', + ClpHomogeneousPoint in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpHomogeneousPoint.pas', + ClpFixedWindowCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpFixedWindowCTMultiplier.pas', + ClpIF2mFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIF2mFieldOps.pas', + ClpLopezDahabLadder in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpLopezDahabLadder.pas', + ClpF2mMontgomeryLadderCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpF2mMontgomeryLadderCTMultiplier.pas', ClpNistNamedCurves in '..\..\CryptoLib\src\Asn1\Nist\ClpNistNamedCurves.pas', ClpNistObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Nist\ClpNistObjectIdentifiers.pas', ClpNoOpDigest in '..\..\CryptoLib\src\Crypto\Digests\ClpNoOpDigest.pas', diff --git a/CryptoLib.Examples/Delphi.Examples/CryptoLib.Examples.dpr b/CryptoLib.Examples/Delphi.Examples/CryptoLib.Examples.dpr index ce023fd7..af1217c3 100644 --- a/CryptoLib.Examples/Delphi.Examples/CryptoLib.Examples.dpr +++ b/CryptoLib.Examples/Delphi.Examples/CryptoLib.Examples.dpr @@ -406,6 +406,12 @@ uses ClpMacUtilities in '..\..\CryptoLib\src\Crypto\Macs\ClpMacUtilities.pas', ClpMiscObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Misc\ClpMiscObjectIdentifiers.pas', ClpMultipliers in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpMultipliers.pas', + ClpIFpFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIFpFieldOps.pas', + ClpHomogeneousPoint in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpHomogeneousPoint.pas', + ClpFixedWindowCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpFixedWindowCTMultiplier.pas', + ClpIF2mFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIF2mFieldOps.pas', + ClpLopezDahabLadder in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpLopezDahabLadder.pas', + ClpF2mMontgomeryLadderCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpF2mMontgomeryLadderCTMultiplier.pas', ClpNistNamedCurves in '..\..\CryptoLib\src\Asn1\Nist\ClpNistNamedCurves.pas', ClpNistObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Nist\ClpNistObjectIdentifiers.pas', ClpNoOpDigest in '..\..\CryptoLib\src\Crypto\Digests\ClpNoOpDigest.pas', diff --git a/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dpr b/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dpr index 1118f259..14080409 100644 --- a/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dpr +++ b/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dpr @@ -383,6 +383,12 @@ uses ClpMacUtilities in '..\..\CryptoLib\src\Crypto\Macs\ClpMacUtilities.pas', ClpMiscObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Misc\ClpMiscObjectIdentifiers.pas', ClpMultipliers in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpMultipliers.pas', + ClpIFpFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIFpFieldOps.pas', + ClpHomogeneousPoint in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpHomogeneousPoint.pas', + ClpFixedWindowCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpFixedWindowCTMultiplier.pas', + ClpIF2mFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIF2mFieldOps.pas', + ClpLopezDahabLadder in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpLopezDahabLadder.pas', + ClpF2mMontgomeryLadderCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpF2mMontgomeryLadderCTMultiplier.pas', ClpNistNamedCurves in '..\..\CryptoLib\src\Asn1\Nist\ClpNistNamedCurves.pas', ClpNistObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Nist\ClpNistObjectIdentifiers.pas', ClpNoOpDigest in '..\..\CryptoLib\src\Crypto\Digests\ClpNoOpDigest.pas', @@ -929,6 +935,8 @@ uses //FixedPointTests in '..\src\Math\EC\FixedPointTests.pas', AESTests in '..\src\Crypto\AESTests.pas', AesBitSlicedTests in '..\src\Crypto\AesBitSlicedTests.pas', + ECDHPrimeConstantTimeTests in '..\src\Crypto\ECDHPrimeConstantTimeTests.pas', + ECDHBinaryConstantTimeTests in '..\src\Crypto\ECDHBinaryConstantTimeTests.pas', BlockCipherTestBase in '..\src\Crypto\BlockCipherTestBase.pas', AesBlockCipherTestBase in '..\src\Crypto\AesBlockCipherTestBase.pas', AesLightTests in '..\src\Crypto\AesLightTests.pas', diff --git a/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dproj b/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dproj index 660cb15e..433ea020 100644 --- a/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dproj +++ b/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.Mobile.dproj @@ -726,6 +726,12 @@ + + + + + + @@ -1268,6 +1274,8 @@ + + diff --git a/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr b/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr index 7d0f5f1f..1bea3bb2 100644 --- a/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr +++ b/CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr @@ -402,6 +402,12 @@ uses ClpMacUtilities in '..\..\CryptoLib\src\Crypto\Macs\ClpMacUtilities.pas', ClpMiscObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Misc\ClpMiscObjectIdentifiers.pas', ClpMultipliers in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpMultipliers.pas', + ClpIFpFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIFpFieldOps.pas', + ClpHomogeneousPoint in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpHomogeneousPoint.pas', + ClpFixedWindowCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpFixedWindowCTMultiplier.pas', + ClpIF2mFieldOps in '..\..\CryptoLib\src\Interfaces\Math\EC\Multiplier\ClpIF2mFieldOps.pas', + ClpLopezDahabLadder in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpLopezDahabLadder.pas', + ClpF2mMontgomeryLadderCTMultiplier in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpF2mMontgomeryLadderCTMultiplier.pas', ClpNistNamedCurves in '..\..\CryptoLib\src\Asn1\Nist\ClpNistNamedCurves.pas', ClpNistObjectIdentifiers in '..\..\CryptoLib\src\Asn1\Nist\ClpNistObjectIdentifiers.pas', ClpNoOpDigest in '..\..\CryptoLib\src\Crypto\Digests\ClpNoOpDigest.pas', @@ -950,6 +956,8 @@ uses FixedPointTests in '..\src\Math\EC\FixedPointTests.pas', AESTests in '..\src\Crypto\AESTests.pas', AesBitSlicedTests in '..\src\Crypto\AesBitSlicedTests.pas', + ECDHPrimeConstantTimeTests in '..\src\Crypto\ECDHPrimeConstantTimeTests.pas', + ECDHBinaryConstantTimeTests in '..\src\Crypto\ECDHBinaryConstantTimeTests.pas', BlockCipherTestBase in '..\src\Crypto\BlockCipherTestBase.pas', AesBlockCipherTestBase in '..\src\Crypto\AesBlockCipherTestBase.pas', AesLightTests in '..\src\Crypto\AesLightTests.pas', diff --git a/CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi b/CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi index f5889648..182f6106 100644 --- a/CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi +++ b/CryptoLib.Tests/FreePascal.Tests/CryptoLib.Tests.lpi @@ -79,7 +79,7 @@ - + @@ -901,6 +901,14 @@ + + + + + + + + diff --git a/CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr b/CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr index 94960e3e..9673bdb0 100644 --- a/CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr +++ b/CryptoLib.Tests/FreePascal.Tests/CryptoLib.lpr @@ -40,9 +40,10 @@ AeadTestUtilities, GcmReorderTests, GCMTests, GcmSivTests, GMacTests, Pkcs12Tests, Bip327MuSig2Tests, Bip340SchnorrTests, AlgorithmFinderTests, MlKemTests, MlDsaTests, PqcPkcsTests, SlhDsaTests, Lib25519Tests, - Asn1CipherBuilderWithKeyTests, AesBitSlicedTests, CryptoLibTestBase, - PkixFoundationTests, PkixNameConstraintTests, PkixComparerTests, - CertPathTests, CertPathValidatorTests, PkixPolicyMappingTests, OcspTests, + Asn1CipherBuilderWithKeyTests, AesBitSlicedTests, ECDHPrimeConstantTimeTests, + ECDHBinaryConstantTimeTests, CryptoLibTestBase, PkixFoundationTests, + PkixNameConstraintTests, PkixComparerTests, CertPathTests, + CertPathValidatorTests, PkixPolicyMappingTests, OcspTests, CryptoLibHashSetTests, PkitsTestBase, NistCertPathTests, AttrCertPathTests, CtrDrbgTests, DrbgTestSupport, HashDrbgTests, HMacDrbgTests, SimdSelectSlotTests, BinaryPrimitivesTests, PkcsEncryptedPrivateKeyInfoTests, diff --git a/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpi b/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpi index a7d39284..05a88bf2 100644 --- a/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpi +++ b/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpi @@ -39,7 +39,7 @@ - + @@ -860,6 +860,14 @@ + + + + + + + + diff --git a/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr b/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr index ff73c72d..a5845554 100644 --- a/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr +++ b/CryptoLib.Tests/FreePascal.Tests/CryptoLibConsole.lpr @@ -57,7 +57,8 @@ OpenSslVectors, PkcsVectors, CertVectors, PkitsVectors, PqcSampleCredentials, CsvVectorLoaderBase, TestKeyBuilders, PemDerCodec, PemReaderVectors, Argon2Vectors, PqcTestVectors, DrbgTestVectors, Int32Tests, Int64Tests, - ByteUtilitiesTests, IPAddressUtilitiesTests, PemReaderTests; + ByteUtilitiesTests, IPAddressUtilitiesTests, PemReaderTests, + ECDHPrimeConstantTimeTests, ECDHBinaryConstantTimeTests; type diff --git a/CryptoLib.Tests/src/Crypto/AesBitSlicedTests.pas b/CryptoLib.Tests/src/Crypto/AesBitSlicedTests.pas index ac44671a..43dc1451 100644 --- a/CryptoLib.Tests/src/Crypto/AesBitSlicedTests.pas +++ b/CryptoLib.Tests/src/Crypto/AesBitSlicedTests.pas @@ -79,6 +79,8 @@ TTestAesBitSliced = class(TAesBlockCipherTestBase) procedure TestAesGcmEndToEnd; procedure TestInvalidKeyLength; procedure TestResetAndReInit; + procedure TestReInitDifferentKeySize; + procedure TestCallerKeyPreserved; end; implementation @@ -444,6 +446,57 @@ procedure TTestAesBitSliced.TestResetAndReInit; Fail('ProcessBlock after re-Init produced a different result'); end; +procedure TTestAesBitSliced.TestReInitDifferentKeySize; +var + LBlock, LOut: TBytes; + LEngine: IBlockCipher; +begin + LBlock := DecodeHex(KAT_PLAIN); + System.SetLength(LOut, 16); + LEngine := TAesBitSlicedEngine.Create(); + + LEngine.Init(True, TKeyParameter.Create(DecodeHex(KAT_KEY_128)) as ICipherParameters); + LEngine.ProcessBlock(LBlock, 0, LOut, 0); + if not AreEqual(LOut, DecodeHex(KAT_CIPHER_128)) then + Fail('AES-128 encrypt wrong before re-key'); + + // Re-Init the same instance with a larger key: exercises the FSkey pre-wipe + realloc. + LEngine.Init(True, TKeyParameter.Create(DecodeHex(KAT_KEY_256)) as ICipherParameters); + LEngine.ProcessBlock(LBlock, 0, LOut, 0); + if not AreEqual(LOut, DecodeHex(KAT_CIPHER_256)) then + Fail('AES-256 encrypt wrong after cross-key-size re-Init'); +end; + +procedure TTestAesBitSliced.TestCallerKeyPreserved; +var + LKey, LKeyBefore, LBad: TBytes; + LEngine: IBlockCipher; + LI: Int32; + LRaised: Boolean; +begin + // A successful Init must not mutate the caller's key bytes. + LKey := DecodeHex(KAT_KEY_128); + LKeyBefore := System.Copy(LKey); + LEngine := TAesBitSlicedEngine.Create(); + LEngine.Init(True, TKeyParameter.Create(LKey) as ICipherParameters); + if not AreEqual(LKey, LKeyBefore) then + Fail('caller key buffer was mutated on a successful Init'); + + // An invalid key length must raise (matching TAesEngine). + System.SetLength(LBad, 20); + for LI := 0 to System.Length(LBad) - 1 do + LBad[LI] := Byte($AA); + LRaised := False; + try + LEngine := TAesBitSlicedEngine.Create(); + LEngine.Init(True, TKeyParameter.Create(LBad) as ICipherParameters); + except + on E: EArgumentCryptoLibException do + LRaised := True; + end; + CheckTrue(LRaised, 'invalid key length did not raise'); +end; + initialization {$IFDEF FPC} diff --git a/CryptoLib.Tests/src/Crypto/ECDHBinaryConstantTimeTests.pas b/CryptoLib.Tests/src/Crypto/ECDHBinaryConstantTimeTests.pas new file mode 100644 index 00000000..f27471ec --- /dev/null +++ b/CryptoLib.Tests/src/Crypto/ECDHBinaryConstantTimeTests.pas @@ -0,0 +1,198 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ECDHBinaryConstantTimeTests; + +interface + +{$IFDEF FPC} +{$MODE DELPHI} +{$ENDIF FPC} + +uses + SysUtils, +{$IFDEF FPC} + fpcunit, + testregistry, +{$ELSE} + TestFramework, +{$ENDIF FPC} + ClpSecureRandom, + ClpISecureRandom, + ClpBigInteger, + ClpCustomNamedCurves, + ClpIX9ECAsn1Objects, + ClpMultipliers, + ClpIECCommon, + ClpPlatformUtilities, + ClpCryptoLibTypes, + CryptoLibTestBase; + +type + + /// + /// Verifies the constant-time López–Dahab ladder wired as the default + /// multiplier for the custom sect283k1 binary curve. + /// + TTestECDHBinaryConstantTime = class(TCryptoLibAlgorithmTestCase) + private + const + CurveName = String('sect283k1'); + TestRounds = Int32(8); + var + FRandom: ISecureRandom; + function GetCurve: IX9ECParameters; + function RandomScalar(const AN: TBigInteger): TBigInteger; + procedure AssertPointsEqual(const AMsg: String; const AA, AB: IECPoint); + protected + procedure SetUp; override; + procedure TearDown; override; + published + procedure TestDefaultMultiplierIsConstantTime; + procedure TestParityWithWNaf; + procedure TestEdgeScalars; + procedure TestBlindingTransparency; + end; + +implementation + +{ TTestECDHBinaryConstantTime } + +procedure TTestECDHBinaryConstantTime.SetUp; +begin + FRandom := TSecureRandom.Create(); +end; + +procedure TTestECDHBinaryConstantTime.TearDown; +begin + inherited; +end; + +function TTestECDHBinaryConstantTime.GetCurve: IX9ECParameters; +begin + Result := TCustomNamedCurves.GetByName(CurveName); +end; + +function TTestECDHBinaryConstantTime.RandomScalar(const AN: TBigInteger): TBigInteger; +begin + Result := TBigInteger.Create(AN.BitLength, FRandom).&Mod(AN); + if Result.SignValue = 0 then + Result := TBigInteger.One; +end; + +procedure TTestECDHBinaryConstantTime.AssertPointsEqual(const AMsg: String; + const AA, AB: IECPoint); +begin + CheckEquals(True, AA.Equals(AB), AMsg); + CheckEquals(True, AB.Equals(AA), AMsg); +end; + +procedure TTestECDHBinaryConstantTime.TestDefaultMultiplierIsConstantTime; +var + LX9: IX9ECParameters; + LMul: IECMultiplier; +begin + LX9 := GetCurve; + CheckTrue(LX9 <> nil, CurveName + ' not found'); + LMul := LX9.Curve.Multiplier; + CheckEquals('TF2mMontgomeryLadderCTMultiplier', TPlatformUtilities.GetTypeName(LMul as TObject), + 'default multiplier for ' + CurveName + ' is not the constant-time ladder'); +end; + +procedure TTestECDHBinaryConstantTime.TestParityWithWNaf; +var + LJ: Int32; + LX9: IX9ECParameters; + LCurve: IECCurve; + LWNaf, LCT: IECMultiplier; + LN, LR, LK: TBigInteger; + LQ, LRef, LGot: IECPoint; +begin + LWNaf := TWNafL2RMultiplier.Create() as IECMultiplier; + LX9 := GetCurve; + LCurve := LX9.Curve; + LN := LX9.N; + LCT := LCurve.Multiplier; + for LJ := 0 to TestRounds - 1 do + begin + LR := RandomScalar(LN); + LQ := LWNaf.Multiply(LX9.G, LR).Normalize(); + LK := RandomScalar(LN); + LRef := LWNaf.Multiply(LQ, LK).Normalize(); + LGot := LCT.Multiply(LQ, LK).Normalize(); + AssertPointsEqual('parity ' + CurveName, LRef, LGot); + end; +end; + +procedure TTestECDHBinaryConstantTime.TestEdgeScalars; +var + LJ: Int32; + LX9: IX9ECParameters; + LCurve: IECCurve; + LWNaf, LCT: IECMultiplier; + LN: TBigInteger; + LScalars: TCryptoLibGenericArray; + LRef, LGot: IECPoint; +begin + LWNaf := TWNafL2RMultiplier.Create() as IECMultiplier; + LX9 := GetCurve; + LCurve := LX9.Curve; + LN := LX9.N; + LCT := LCurve.Multiplier; + LScalars := TCryptoLibGenericArray.Create( + TBigInteger.One, + TBigInteger.Two, + TBigInteger.ValueOf(7), + LN.Subtract(TBigInteger.One), + LN.Subtract(TBigInteger.Two)); + for LJ := 0 to System.Length(LScalars) - 1 do + begin + LRef := LWNaf.Multiply(LX9.G, LScalars[LJ]).Normalize(); + LGot := LCT.Multiply(LX9.G, LScalars[LJ]).Normalize(); + AssertPointsEqual('edge idx ' + IntToStr(LJ), LRef, LGot); + end; +end; + +procedure TTestECDHBinaryConstantTime.TestBlindingTransparency; +var + LX9: IX9ECParameters; + LCT: IECMultiplier; + LN, LK: TBigInteger; + LI: Int32; + LFirst, LAgain: IECPoint; +begin + // Randomized internals (scalar blind + projective coordinate) must not change the result. + LX9 := GetCurve; + LCT := LX9.Curve.Multiplier; + LN := LX9.N; + for LI := 0 to 5 do + begin + LK := RandomScalar(LN); + LFirst := LCT.Multiply(LX9.G, LK).Normalize(); + LAgain := LCT.Multiply(LX9.G, LK).Normalize(); + AssertPointsEqual('transparency', LFirst, LAgain); + end; +end; + +initialization + +{$IFDEF FPC} + RegisterTest(TTestECDHBinaryConstantTime); +{$ELSE} + RegisterTest(TTestECDHBinaryConstantTime.Suite); +{$ENDIF FPC} + +end. diff --git a/CryptoLib.Tests/src/Crypto/ECDHPrimeConstantTimeTests.pas b/CryptoLib.Tests/src/Crypto/ECDHPrimeConstantTimeTests.pas new file mode 100644 index 00000000..b33f4715 --- /dev/null +++ b/CryptoLib.Tests/src/Crypto/ECDHPrimeConstantTimeTests.pas @@ -0,0 +1,427 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ECDHPrimeConstantTimeTests; + +interface + +{$IFDEF FPC} +{$MODE DELPHI} +{$ENDIF FPC} + +uses + SysUtils, +{$IFDEF FPC} + fpcunit, + testregistry, +{$ELSE} + TestFramework, +{$ENDIF FPC} + ClpSecureRandom, + ClpISecureRandom, + ClpBigInteger, + ClpNat, + ClpCustomNamedCurves, + ClpIX9ECAsn1Objects, + ClpMultipliers, + ClpECAlgorithms, + ClpIFpFieldOps, + ClpHomogeneousPoint, + ClpFixedWindowCTMultiplier, + ClpSecP256R1Custom, + ClpSecP256K1Custom, + ClpSecP384R1Custom, + ClpSecP521R1Custom, + ClpECParameters, + ClpIECParameters, + ClpECGenerators, + ClpIECGenerators, + ClpECDHBasicAgreement, + ClpIBasicAgreement, + ClpIAsymmetricCipherKeyPair, + ClpIAsymmetricCipherKeyPairGenerator, + ClpIKeyGenerationParameters, + ClpICipherParameters, + ClpIECCommon, + ClpIECFieldElement, + ClpPlatformUtilities, + ClpCryptoLibTypes, + ClpCryptoLibExceptions, + CryptoLibTestBase; + +type + TTestECDHPrimeConstantTime = class(TCryptoLibAlgorithmTestCase) + private + const + TestsPerCurve = Int32(16); + var + FRandom: ISecureRandom; + function CurveNames: TCryptoLibStringArray; + function MakeFieldOps(const AName: String; const ACurve: IECCurve): IFpFieldOps; + function RandomScalar(const AN: TBigInteger): TBigInteger; + procedure AssertPointsEqual(const AMsg: String; const AA, AB: IECPoint); + function HomogFromAffine(const AFO: IFpFieldOps; const AP: IECPoint): TCTHomogPoint; + function HomogToPoint(const AFO: IFpFieldOps; const ACurve: IECCurve; + const AP: TCTHomogPoint): IECPoint; + protected + procedure SetUp; override; + procedure TearDown; override; + published + procedure TestDefaultMultiplierIsConstantTime; + procedure TestParityWithWNaf; + procedure TestEdgeScalars; + procedure TestBlindingTransparency; + procedure TestExceptionalFormulas; + procedure TestECDHAgreement; + procedure TestScalarRangeGuard; + procedure TestBlindBitsValidation; + end; + +implementation + +{ TTestECDHPrimeConstantTime } + +procedure TTestECDHPrimeConstantTime.SetUp; +begin + FRandom := TSecureRandom.Create(); +end; + +procedure TTestECDHPrimeConstantTime.TearDown; +begin + inherited; +end; + +function TTestECDHPrimeConstantTime.CurveNames: TCryptoLibStringArray; +begin + Result := TCryptoLibStringArray.Create('secp256r1', 'secp384r1', 'secp521r1', 'secp256k1'); +end; + +function TTestECDHPrimeConstantTime.MakeFieldOps(const AName: String; + const ACurve: IECCurve): IFpFieldOps; +begin + if AName = 'secp256r1' then + Result := TSecP256R1FpFieldOps.Create(ACurve.A, ACurve.B, ACurve.Order) + else if AName = 'secp384r1' then + Result := TSecP384R1FpFieldOps.Create(ACurve.A, ACurve.B, ACurve.Order) + else if AName = 'secp521r1' then + Result := TSecP521R1FpFieldOps.Create(ACurve.A, ACurve.B, ACurve.Order) + else + Result := TSecP256K1FpFieldOps.Create(ACurve.A, ACurve.B, ACurve.Order); +end; + +function TTestECDHPrimeConstantTime.RandomScalar(const AN: TBigInteger): TBigInteger; +begin + Result := TBigInteger.Create(AN.BitLength, FRandom).&Mod(AN); + if Result.SignValue = 0 then + Result := TBigInteger.One; +end; + +procedure TTestECDHPrimeConstantTime.AssertPointsEqual(const AMsg: String; + const AA, AB: IECPoint); +begin + CheckEquals(True, AA.Equals(AB), AMsg); + CheckEquals(True, AB.Equals(AA), AMsg); +end; + +function TTestECDHPrimeConstantTime.HomogFromAffine(const AFO: IFpFieldOps; + const AP: IECPoint): TCTHomogPoint; +var + LN: Int32; + LX, LY: TCryptoLibUInt32Array; + LQ: IECPoint; +begin + LN := AFO.GetFieldInts; + LQ := AP.Normalize(); + LX := TNat.Create(LN); + LY := TNat.Create(LN); + AFO.FieldFromBigInteger(LQ.AffineXCoord.ToBigInteger(), LX); + AFO.FieldFromBigInteger(LQ.AffineYCoord.ToBigInteger(), LY); + Result := TCTHomogeneousMath.FromAffine(AFO, LX, LY); +end; + +function TTestECDHPrimeConstantTime.HomogToPoint(const AFO: IFpFieldOps; + const ACurve: IECCurve; const AP: TCTHomogPoint): IECPoint; +var + LX, LY: TCryptoLibUInt32Array; + LIsInfinity: Boolean; +begin + TCTHomogeneousMath.ToAffine(AFO, AP, LX, LY, LIsInfinity); + if LIsInfinity then + Result := ACurve.Infinity + else + Result := ACurve.CreateRawPoint(AFO.CreateFieldElement(LX), AFO.CreateFieldElement(LY)); +end; + +procedure TTestECDHPrimeConstantTime.TestDefaultMultiplierIsConstantTime; +var + LNames: TCryptoLibStringArray; + LI: Int32; + LX9: IX9ECParameters; + LMul: IECMultiplier; +begin + LNames := CurveNames; + for LI := 0 to System.Length(LNames) - 1 do + begin + LX9 := TCustomNamedCurves.GetByName(LNames[LI]); + CheckTrue(LX9 <> nil, LNames[LI] + ' not found'); + LMul := LX9.Curve.Multiplier; + CheckEquals('TFixedWindowCTMultiplier', TPlatformUtilities.GetTypeName(LMul as TObject), + 'default multiplier for ' + LNames[LI] + ' is not constant-time'); + end; +end; + +procedure TTestECDHPrimeConstantTime.TestParityWithWNaf; +var + LNames: TCryptoLibStringArray; + LI, LJ: Int32; + LX9: IX9ECParameters; + LCurve: IECCurve; + LWNaf, LCT: IECMultiplier; + LN, LR, LK: TBigInteger; + LQ, LRef, LGot: IECPoint; +begin + LWNaf := TWNafL2RMultiplier.Create() as IECMultiplier; + LNames := CurveNames; + for LI := 0 to System.Length(LNames) - 1 do + begin + LX9 := TCustomNamedCurves.GetByName(LNames[LI]); + LCurve := LX9.Curve; + LN := LX9.N; + LCT := LCurve.Multiplier; + for LJ := 0 to TestsPerCurve - 1 do + begin + LR := RandomScalar(LN); + LQ := LWNaf.Multiply(LX9.G, LR).Normalize(); + LK := RandomScalar(LN); + LRef := LWNaf.Multiply(LQ, LK).Normalize(); + LGot := LCT.Multiply(LQ, LK).Normalize(); + AssertPointsEqual('parity ' + LNames[LI], LRef, LGot); + end; + end; +end; + +procedure TTestECDHPrimeConstantTime.TestEdgeScalars; +var + LNames: TCryptoLibStringArray; + LI, LJ: Int32; + LX9: IX9ECParameters; + LCurve: IECCurve; + LWNaf, LCT: IECMultiplier; + LN: TBigInteger; + LScalars: TCryptoLibGenericArray; + LRef, LGot: IECPoint; +begin + LWNaf := TWNafL2RMultiplier.Create() as IECMultiplier; + LNames := CurveNames; + for LI := 0 to System.Length(LNames) - 1 do + begin + LX9 := TCustomNamedCurves.GetByName(LNames[LI]); + LCurve := LX9.Curve; + LN := LX9.N; + LCT := LCurve.Multiplier; + LScalars := TCryptoLibGenericArray.Create( + TBigInteger.One, + TBigInteger.Two, + TBigInteger.ValueOf(7), + LN.Subtract(TBigInteger.One), + LN.Subtract(TBigInteger.Two)); + for LJ := 0 to System.Length(LScalars) - 1 do + begin + LRef := LWNaf.Multiply(LX9.G, LScalars[LJ]).Normalize(); + LGot := LCT.Multiply(LX9.G, LScalars[LJ]).Normalize(); + AssertPointsEqual('edge ' + LNames[LI] + ' idx ' + IntToStr(LJ), LRef, LGot); + end; + end; +end; + +procedure TTestECDHPrimeConstantTime.TestBlindingTransparency; +var + LX9: IX9ECParameters; + LCT: IECMultiplier; + LN, LK: TBigInteger; + LI: Int32; + LFirst, LAgain: IECPoint; +begin + // Randomized internals (scalar blind + projective coordinate) must not change the result. + LX9 := TCustomNamedCurves.GetByName('secp256r1'); + LCT := LX9.Curve.Multiplier; + LN := LX9.N; + for LI := 0 to 7 do + begin + LK := RandomScalar(LN); + LFirst := LCT.Multiply(LX9.G, LK).Normalize(); + LAgain := LCT.Multiply(LX9.G, LK).Normalize(); + AssertPointsEqual('transparency', LFirst, LAgain); + end; +end; + +procedure TTestECDHPrimeConstantTime.TestExceptionalFormulas; +var + LX9: IX9ECParameters; + LCurve: IECCurve; + LFO: IFpFieldOps; + LWNaf: IECMultiplier; + LN: Int32; + LP, LDbl, LNeg, LSum, LInf: TCTHomogPoint; + LNegY, LZeroArr: TCryptoLibUInt32Array; + LG, LNegG, LRef2G: IECPoint; +begin + LWNaf := TWNafL2RMultiplier.Create() as IECMultiplier; + LX9 := TCustomNamedCurves.GetByName('secp256r1'); + LCurve := LX9.Curve; + LFO := MakeFieldOps('secp256r1', LCurve); + LN := LFO.GetFieldInts; + + LG := LX9.G.Normalize(); + LP := HomogFromAffine(LFO, LG); + + // complete Add must handle P == Q (doubling): Add(P,P) == Double(P) == 2G + LDbl := TCTHomogeneousMath.Double(LFO, LP); + LSum := TCTHomogeneousMath.Add(LFO, LP, LP); + LRef2G := LWNaf.Multiply(LX9.G, TBigInteger.Two).Normalize(); + AssertPointsEqual('Double(P)=2G', LRef2G, HomogToPoint(LFO, LCurve, LDbl)); + AssertPointsEqual('Add(P,P)=2G', LRef2G, HomogToPoint(LFO, LCurve, LSum)); + + // P + (-P) == O + LZeroArr := TNat.Create(LN); + LNegY := TNat.Create(LN); + LFO.Sub(LZeroArr, HomogFromAffine(LFO, LG).Y, LNegY); + LNeg.X := HomogFromAffine(LFO, LG).X; + LNeg.Y := LNegY; + LNeg.Z := HomogFromAffine(LFO, LG).Z; + LSum := TCTHomogeneousMath.Add(LFO, LP, LNeg); + CheckEquals(True, HomogToPoint(LFO, LCurve, LSum).IsInfinity, 'P+(-P)=O'); + // cross-check the affine (-P) really is the curve negation of P + LNegG := LX9.G.Negate().Normalize(); + AssertPointsEqual('(-P) affine', LNegG, HomogToPoint(LFO, LCurve, LNeg)); + + // P + O == P and O + P == P + LInf := TCTHomogeneousMath.Infinity(LFO); + AssertPointsEqual('P+O=P', LG, HomogToPoint(LFO, LCurve, TCTHomogeneousMath.Add(LFO, LP, LInf))); + AssertPointsEqual('O+P=P', LG, HomogToPoint(LFO, LCurve, TCTHomogeneousMath.Add(LFO, LInf, LP))); + + // O + O == O + CheckEquals(True, HomogToPoint(LFO, LCurve, + TCTHomogeneousMath.Add(LFO, LInf, LInf)).IsInfinity, 'O+O=O'); +end; + +procedure TTestECDHPrimeConstantTime.TestECDHAgreement; +var + LNames: TCryptoLibStringArray; + LI: Int32; + LX9: IX9ECParameters; + LEC: IECDomainParameters; + LKpg: IAsymmetricCipherKeyPairGenerator; + LP1, LP2: IAsymmetricCipherKeyPair; + LE1, LE2: IBasicAgreement; + LK1, LK2: TBigInteger; +begin + LNames := CurveNames; + for LI := 0 to System.Length(LNames) - 1 do + begin + LX9 := TCustomNamedCurves.GetByName(LNames[LI]); + LEC := TECDomainParameters.Create(LX9.Curve, LX9.G, LX9.N, LX9.H); + LKpg := TECKeyPairGenerator.Create(); + LKpg.Init(TECKeyGenerationParameters.Create(LEC, FRandom) as IECKeyGenerationParameters); + LP1 := LKpg.GenerateKeyPair(); + LP2 := LKpg.GenerateKeyPair(); + + LE1 := TECDHBasicAgreement.Create(); + LE2 := TECDHBasicAgreement.Create(); + LE1.Init(LP1.Private); + LE2.Init(LP2.Private); + + LK1 := LE1.CalculateAgreement(LP2.Public as ICipherParameters); + LK2 := LE2.CalculateAgreement(LP1.Public as ICipherParameters); + CheckEquals(True, LK1.Equals(LK2), 'ECDH agreement mismatch ' + LNames[LI]); + end; +end; + +procedure TTestECDHPrimeConstantTime.TestScalarRangeGuard; +var + LNames: TCryptoLibStringArray; + LI, LOrderBits: Int32; + LX9: IX9ECParameters; + LMul: IECMultiplier; + LN: TBigInteger; + + function Raises(const AK: TBigInteger): Boolean; + begin + Result := False; + try + LMul.Multiply(LX9.G, AK); + except + on E: EInvalidOperationCryptoLibException do + Result := True; + end; + end; + +begin + LNames := CurveNames; + for LI := 0 to System.Length(LNames) - 1 do + begin + LX9 := TCustomNamedCurves.GetByName(LNames[LI]); + LMul := LX9.Curve.Multiplier; + LN := LX9.N; + LOrderBits := LN.BitLength; + // k = n (BitLength = order bits) is in range and must not raise + CheckFalse(Raises(LN), 'k = n unexpectedly rejected for ' + LNames[LI]); + // scalars wider than the order must raise + CheckTrue(Raises(TBigInteger.One.ShiftLeft(LOrderBits)), + 'k = 2^orderbits not rejected for ' + LNames[LI]); + CheckTrue(Raises(TBigInteger.One.ShiftLeft(LOrderBits + 1)), + 'k = 2^(orderbits+1) not rejected for ' + LNames[LI]); + end; +end; + +procedure TTestECDHPrimeConstantTime.TestBlindBitsValidation; +var + LX9: IX9ECParameters; + LFO: IFpFieldOps; + + function Rejects(ABlindBits: Int32): Boolean; + var + LMul: IECMultiplier; + begin + Result := False; + try + LMul := TFixedWindowCTMultiplier.Create(LFO, ABlindBits) as IECMultiplier; + except + on E: EArgumentCryptoLibException do + Result := True; + end; + end; + +begin + LX9 := TCustomNamedCurves.GetByName('secp256r1'); + LFO := MakeFieldOps('secp256r1', LX9.Curve); + CheckTrue(Rejects(0), '0 accepted'); + CheckTrue(Rejects(32), '32 (below floor) accepted'); + CheckTrue(Rejects(48), '48 (non-multiple of 32) accepted'); + CheckTrue(Rejects(544), '544 (above cap) accepted'); + CheckFalse(Rejects(64), '64 rejected'); + CheckFalse(Rejects(128), '128 rejected'); +end; + +initialization + +{$IFDEF FPC} + RegisterTest(TTestECDHPrimeConstantTime); +{$ELSE} + RegisterTest(TTestECDHPrimeConstantTime.Suite); +{$ENDIF FPC} + +end. diff --git a/CryptoLib/src/Crypto/Engines/ClpAesBitSlicedEngine.pas b/CryptoLib/src/Crypto/Engines/ClpAesBitSlicedEngine.pas index 19515ea1..f30e351d 100644 --- a/CryptoLib/src/Crypto/Engines/ClpAesBitSlicedEngine.pas +++ b/CryptoLib/src/Crypto/Engines/ClpAesBitSlicedEngine.pas @@ -133,6 +133,9 @@ TAesBitSlicedEngine = class sealed(TInterfacedObject, IAesEngine, IBlockCipher /// Reset the cipher back to its post-Init state. procedure Reset(); virtual; + /// Zeroize the expanded round-key schedule on teardown. + destructor Destroy; override; + /// The cipher name (AES[BitSliced]). property AlgorithmName: String read GetAlgorithmName; end; @@ -602,87 +605,92 @@ procedure TAesBitSlicedEngine.KeySchedule(const AKey: TCryptoLibByteArray); end; end; - LNk := LKeyLen shr 2; - LNkf := (FRounds + 1) shl 2; + try + LNk := LKeyLen shr 2; + LNkf := (FRounds + 1) shl 2; - LTmp := 0; - for LI := 0 to LNk - 1 do - begin - LTmp := TPack.LE_To_UInt32(AKey, LI shl 2); - LSkey32[LI] := LTmp; - end; - - LJ := 0; - LK := 0; - for LI := LNk to LNkf - 1 do - begin - if LJ = 0 then + LTmp := 0; + for LI := 0 to LNk - 1 do begin - LTmp := TBitOperations.RotateLeft32(LTmp, 24); - LTmp := SubWord(LTmp) xor RCon[LK]; - end - else if (LNk > 6) and (LJ = 4) then - begin - LTmp := SubWord(LTmp); + LTmp := TPack.LE_To_UInt32(AKey, LI shl 2); + LSkey32[LI] := LTmp; end; - LTmp := LTmp xor LSkey32[LI - LNk]; - LSkey32[LI] := LTmp; - System.Inc(LJ); - if LJ = LNk then + + LJ := 0; + LK := 0; + for LI := LNk to LNkf - 1 do begin - LJ := 0; - System.Inc(LK); + if LJ = 0 then + begin + LTmp := TBitOperations.RotateLeft32(LTmp, 24); + LTmp := SubWord(LTmp) xor RCon[LK]; + end + else if (LNk > 6) and (LJ = 4) then + begin + LTmp := SubWord(LTmp); + end; + LTmp := LTmp xor LSkey32[LI - LNk]; + LSkey32[LI] := LTmp; + System.Inc(LJ); + if LJ = LNk then + begin + LJ := 0; + System.Inc(LK); + end; end; - end; - // Compress round keys into two words per round key (one bit per nibble). - System.SetLength(LCompSkey, (FRounds + 1) * 2); - LI := 0; - LJ := 0; - while LI < LNkf do - begin - InterleaveIn(LSkey32[LI], LSkey32[LI + 1], LSkey32[LI + 2], - LSkey32[LI + 3], LQ[0], LQ[4]); - LQ[1] := LQ[0]; - LQ[2] := LQ[0]; - LQ[3] := LQ[0]; - LQ[5] := LQ[4]; - LQ[6] := LQ[4]; - LQ[7] := LQ[4]; - Ortho(LQ); - LCompSkey[LJ + 0] := (LQ[0] and M1) or (LQ[1] and M2) or (LQ[2] and M4) - or (LQ[3] and M8); - LCompSkey[LJ + 1] := (LQ[4] and M1) or (LQ[5] and M2) or (LQ[6] and M4) - or (LQ[7] and M8); - System.Inc(LI, 4); - System.Inc(LJ, 2); - end; + // Compress round keys into two words per round key (one bit per nibble). + System.SetLength(LCompSkey, (FRounds + 1) * 2); + LI := 0; + LJ := 0; + while LI < LNkf do + begin + InterleaveIn(LSkey32[LI], LSkey32[LI + 1], LSkey32[LI + 2], + LSkey32[LI + 3], LQ[0], LQ[4]); + LQ[1] := LQ[0]; + LQ[2] := LQ[0]; + LQ[3] := LQ[0]; + LQ[5] := LQ[4]; + LQ[6] := LQ[4]; + LQ[7] := LQ[4]; + Ortho(LQ); + LCompSkey[LJ + 0] := (LQ[0] and M1) or (LQ[1] and M2) or (LQ[2] and M4) + or (LQ[3] and M8); + LCompSkey[LJ + 1] := (LQ[4] and M1) or (LQ[5] and M2) or (LQ[6] and M4) + or (LQ[7] and M8); + System.Inc(LI, 4); + System.Inc(LJ, 2); + end; - // Expand the compressed round keys to the full bit-sliced form. - System.SetLength(FSkey, (FRounds + 1) * 8); - LN := (FRounds + 1) * 2; - LV := 0; - for LI := 0 to LN - 1 do - begin - LX0 := LCompSkey[LI]; - LX1 := LX0; - LX2 := LX0; - LX3 := LX0; - LX0 := LX0 and M1; - LX1 := LX1 and M2; - LX2 := LX2 and M4; - LX3 := LX3 and M8; - LX1 := LX1 shr 1; - LX2 := LX2 shr 2; - LX3 := LX3 shr 3; - FSkey[LV + 0] := (LX0 shl 4) - LX0; - FSkey[LV + 1] := (LX1 shl 4) - LX1; - FSkey[LV + 2] := (LX2 shl 4) - LX2; - FSkey[LV + 3] := (LX3 shl 4) - LX3; - System.Inc(LV, 4); + // Expand the compressed round keys to the full bit-sliced form. + TArrayUtilities.Fill(FSkey, 0, System.Length(FSkey), UInt64(0)); + System.SetLength(FSkey, (FRounds + 1) * 8); + LN := (FRounds + 1) * 2; + LV := 0; + for LI := 0 to LN - 1 do + begin + LX0 := LCompSkey[LI]; + LX1 := LX0; + LX2 := LX0; + LX3 := LX0; + LX0 := LX0 and M1; + LX1 := LX1 and M2; + LX2 := LX2 and M4; + LX3 := LX3 and M8; + LX1 := LX1 shr 1; + LX2 := LX2 shr 2; + LX3 := LX3 shr 3; + FSkey[LV + 0] := (LX0 shl 4) - LX0; + FSkey[LV + 1] := (LX1 shl 4) - LX1; + FSkey[LV + 2] := (LX2 shl 4) - LX2; + FSkey[LV + 3] := (LX3 shl 4) - LX3; + System.Inc(LV, 4); + end; + finally + TArrayUtilities.Fill(LCompSkey, 0, System.Length(LCompSkey), UInt64(0)); + System.FillChar(LSkey32, System.SizeOf(LSkey32), 0); + System.FillChar(LQ, System.SizeOf(LQ), 0); end; - - TArrayUtilities.Fill(AKey, 0, System.Length(AKey), Byte(0)); end; procedure TAesBitSlicedEngine.BitsliceEncrypt(var AQ: TBitSliceState); @@ -749,6 +757,12 @@ procedure TAesBitSlicedEngine.Reset; // The bit-sliced engine keeps no per-block chaining state; nothing to reset. end; +destructor TAesBitSlicedEngine.Destroy; +begin + TArrayUtilities.Fill(FSkey, 0, System.Length(FSkey), UInt64(0)); + inherited Destroy; +end; + function TAesBitSlicedEngine.ProcessBlock(const AInput: TCryptoLibByteArray; AInOff: Int32; const AOutput: TCryptoLibByteArray; AOutOff: Int32): Int32; var diff --git a/CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIF2mFieldOps.pas b/CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIF2mFieldOps.pas new file mode 100644 index 00000000..ea4acb66 --- /dev/null +++ b/CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIF2mFieldOps.pas @@ -0,0 +1,55 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ClpIF2mFieldOps; + +{$I ..\..\..\..\Include\CryptoLib.inc} + +interface + +uses + ClpBigInteger, + ClpISecureRandom, + ClpIECFieldElement, + ClpCryptoLibTypes; + +type + /// + /// Constant-time GF(2^m) field arithmetic over a specific binary curve, exposing + /// only what the López–Dahab Montgomery ladder needs. + /// Each curve supplies an adapter over its existing (constant-time) binary field. + /// + IF2mFieldOps = interface(IInterface) + ['{2A9C7E14-6B3D-4F81-A0C5-7E2D9B4F1836}'] + function GetFieldLongs: Int32; + function GetCardinalityBits: Int32; + procedure GetCardinality(const AZ: TCryptoLibUInt32Array; AInts: Int32); + + procedure Mul(const AX, AY, AZ: TCryptoLibUInt64Array); + procedure Square(const AX, AZ: TCryptoLibUInt64Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt64Array); + procedure MulByB(const AX, AZ: TCryptoLibUInt64Array); + procedure Inv(const AX, AZ: TCryptoLibUInt64Array); + function IsZeroMask(const AX: TCryptoLibUInt64Array): UInt64; + + procedure RandomNonZero(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt64Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt64Array); + function CreateFieldElement(const AX: TCryptoLibUInt64Array): IECFieldElement; + end; + +implementation + +end. diff --git a/CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIFpFieldOps.pas b/CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIFpFieldOps.pas new file mode 100644 index 00000000..ba2a24a7 --- /dev/null +++ b/CryptoLib/src/Interfaces/Math/EC/Multiplier/ClpIFpFieldOps.pas @@ -0,0 +1,58 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ClpIFpFieldOps; + +{$I ..\..\..\..\Include\CryptoLib.inc} + +interface + +uses + ClpBigInteger, + ClpISecureRandom, + ClpIECFieldElement, + ClpCryptoLibTypes; + +type + /// + /// Constant-time field arithmetic over a specific prime-field short-Weierstrass + /// curve, exposing only what the homogeneous complete-formula layer needs. Each + /// curve supplies an adapter over its existing (constant-time) Nat field. + /// + IFpFieldOps = interface(IInterface) + ['{6F1B2A34-5C8D-4E90-B1A2-7C3D4E5F6A7B}'] + function GetFieldInts: Int32; + function GetOrderBits: Int32; + procedure GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); + + procedure Mul(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Square(const AX, AZ: TCryptoLibUInt32Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Sub(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure MulByB3(const AX, AZ: TCryptoLibUInt32Array); + procedure MulByA(const AX, AZ: TCryptoLibUInt32Array); + procedure Inv(const AX, AZ: TCryptoLibUInt32Array); + function IsZero(const AX: TCryptoLibUInt32Array): Boolean; + + procedure RandomMult(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt32Array); + function CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; + procedure FieldOne(const AZ: TCryptoLibUInt32Array); + end; + +implementation + +end. diff --git a/CryptoLib/src/Math/EC/ClpECAlgorithms.pas b/CryptoLib/src/Math/EC/ClpECAlgorithms.pas index 0e75d4c4..b39ea61c 100644 --- a/CryptoLib/src/Math/EC/ClpECAlgorithms.pas +++ b/CryptoLib/src/Math/EC/ClpECAlgorithms.pas @@ -257,13 +257,18 @@ class function TECAlgorithms.SumOfTwoMultiplies(const AP: IECPoint; const AK: TB LQ: IECPoint; LF2mCurve: IAbstractF2mCurve; LGlv: IGlvEndomorphism; + LTau: IECMultiplier; begin LCurve := AP.Curve; LQ := ImportPoint(LCurve, AQ); + // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick if Supports(LCurve, IAbstractF2mCurve, LF2mCurve) and LF2mCurve.IsKoblitz then begin - Result := ImplCheckResult(AP.Multiply(AK).Add(LQ.Multiply(AL))); + //Result := ImplCheckResult(AP.Multiply(AK).Add(LQ.Multiply(AL))); + // name tau-NAF explicitly so it is not routed through the (constant-time) curve default + LTau := TWTauNafMultiplier.Create(); + Result := ImplCheckResult(LTau.Multiply(AP, AK).Add(LTau.Multiply(LQ, AL))); Exit; end; if Supports(LCurve.GetEndomorphism(), IGlvEndomorphism, LGlv) then diff --git a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas index 4646e7cb..0f2e40cb 100644 --- a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas +++ b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256K1Custom.pas @@ -36,6 +36,8 @@ interface ClpECFieldElement, ClpECPoint, ClpECLookupTables, + ClpIFpFieldOps, + ClpFixedWindowCTMultiplier, ClpIECCommon, ClpIECFieldElement, ClpISecP256K1Custom, @@ -191,11 +193,39 @@ TSecP256K1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable, function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override; function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override; function SupportsCoordinateSystem(ACoord: Int32): Boolean; override; + function CreateDefaultMultiplier: IECMultiplier; override; class property Q: TBigInteger read FQ; class property SecP256K1AffineZs: TCryptoLibGenericArray read FSecP256K1AffineZs; end; +type + TSecP256K1FpFieldOps = class sealed(TInterfacedObject, IFpFieldOps) + strict private + const + FE_INTS = Int32(8); + var + FA, FB3, FOne, FN: TCryptoLibUInt32Array; + FOrderBits: Int32; + public + constructor Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); + function GetFieldInts: Int32; + function GetOrderBits: Int32; + procedure GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); + procedure Mul(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Square(const AX, AZ: TCryptoLibUInt32Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Sub(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure MulByB3(const AX, AZ: TCryptoLibUInt32Array); + procedure MulByA(const AX, AZ: TCryptoLibUInt32Array); + procedure Inv(const AX, AZ: TCryptoLibUInt32Array); + function IsZero(const AX: TCryptoLibUInt32Array): Boolean; + procedure RandomMult(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt32Array); + function CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; + procedure FieldOne(const AZ: TCryptoLibUInt32Array); + end; + implementation { TSecP256K1Field } @@ -1049,6 +1079,111 @@ function TSecP256K1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean; end; end; +function TSecP256K1Curve.CreateDefaultMultiplier: IECMultiplier; +var + LCurve: IECCurve; + LFieldOps: IFpFieldOps; +begin + LCurve := Self as IECCurve; + LFieldOps := TSecP256K1FpFieldOps.Create(LCurve.A, LCurve.B, LCurve.Order); + Result := TFixedWindowCTMultiplier.Create(LFieldOps) as IECMultiplier; +end; + +{ TSecP256K1FpFieldOps } + +constructor TSecP256K1FpFieldOps.Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); +var + LB, LB3: TCryptoLibUInt32Array; +begin + Inherited Create; + FOrderBits := AOrder.BitLength; + FN := TNat.FromBigInteger(FE_INTS * 32, AOrder); + FOne := TSecP256K1Field.FromBigInteger(TBigInteger.One); + FA := TNat.Copy(FE_INTS, (AA as ISecP256K1FieldElement).X); + LB := (AB as ISecP256K1FieldElement).X; + LB3 := TNat256.Create(); + TSecP256K1Field.Add(LB, LB, LB3); + TSecP256K1Field.Add(LB3, LB, LB3); + FB3 := LB3; +end; + +function TSecP256K1FpFieldOps.GetFieldInts: Int32; +begin + Result := FE_INTS; +end; + +function TSecP256K1FpFieldOps.GetOrderBits: Int32; +begin + Result := FOrderBits; +end; + +procedure TSecP256K1FpFieldOps.GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); +begin + TNat.Copy(FE_INTS, FN, 0, AZ, 0); +end; + +procedure TSecP256K1FpFieldOps.Mul(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Multiply(AX, AY, AZ); +end; + +procedure TSecP256K1FpFieldOps.Square(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Square(AX, AZ); +end; + +procedure TSecP256K1FpFieldOps.Add(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Add(AX, AY, AZ); +end; + +procedure TSecP256K1FpFieldOps.Sub(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Subtract(AX, AY, AZ); +end; + +procedure TSecP256K1FpFieldOps.MulByB3(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Multiply(AX, FB3, AZ); +end; + +procedure TSecP256K1FpFieldOps.MulByA(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Multiply(AX, FA, AZ); +end; + +procedure TSecP256K1FpFieldOps.Inv(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.Inv(AX, AZ); +end; + +function TSecP256K1FpFieldOps.IsZero(const AX: TCryptoLibUInt32Array): Boolean; +begin + Result := TSecP256K1Field.IsZero(AX) <> 0; +end; + +procedure TSecP256K1FpFieldOps.RandomMult(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt32Array); +begin + TSecP256K1Field.RandomMult(ARandom, AZ); +end; + +procedure TSecP256K1FpFieldOps.FieldFromBigInteger(const AX: TBigInteger; + const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, TSecP256K1Field.FromBigInteger(AX), 0, AZ, 0); +end; + +function TSecP256K1FpFieldOps.CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; +begin + Result := TSecP256K1FieldElement.Create(AX) as IECFieldElement; +end; + +procedure TSecP256K1FpFieldOps.FieldOne(const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, FOne, 0, AZ, 0); +end; + class function TSecP256K1FieldElement.GetQ: TBigInteger; begin Result := FQ; diff --git a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas index 8ef501c3..86ea10b4 100644 --- a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas +++ b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP256R1Custom.pas @@ -36,6 +36,8 @@ interface ClpECFieldElement, ClpECPoint, ClpECLookupTables, + ClpIFpFieldOps, + ClpFixedWindowCTMultiplier, ClpIECCommon, ClpIECFieldElement, ClpISecP256R1Custom, @@ -192,11 +194,39 @@ TSecP256R1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable, function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override; function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override; function SupportsCoordinateSystem(ACoord: Int32): Boolean; override; + function CreateDefaultMultiplier: IECMultiplier; override; class property Q: TBigInteger read FQ; class property SecP256R1AffineZs: TCryptoLibGenericArray read FSecP256R1AffineZs; end; +type + TSecP256R1FpFieldOps = class sealed(TInterfacedObject, IFpFieldOps) + strict private + const + FE_INTS = Int32(8); + var + FA, FB3, FOne, FN: TCryptoLibUInt32Array; + FOrderBits: Int32; + public + constructor Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); + function GetFieldInts: Int32; + function GetOrderBits: Int32; + procedure GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); + procedure Mul(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Square(const AX, AZ: TCryptoLibUInt32Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Sub(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure MulByB3(const AX, AZ: TCryptoLibUInt32Array); + procedure MulByA(const AX, AZ: TCryptoLibUInt32Array); + procedure Inv(const AX, AZ: TCryptoLibUInt32Array); + function IsZero(const AX: TCryptoLibUInt32Array): Boolean; + procedure RandomMult(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt32Array); + function CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; + procedure FieldOne(const AZ: TCryptoLibUInt32Array); + end; + implementation { TSecP256R1Field } @@ -1205,4 +1235,109 @@ function TSecP256R1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean; end; end; +function TSecP256R1Curve.CreateDefaultMultiplier: IECMultiplier; +var + LCurve: IECCurve; + LFieldOps: IFpFieldOps; +begin + LCurve := Self as IECCurve; + LFieldOps := TSecP256R1FpFieldOps.Create(LCurve.A, LCurve.B, LCurve.Order); + Result := TFixedWindowCTMultiplier.Create(LFieldOps) as IECMultiplier; +end; + +{ TSecP256R1FpFieldOps } + +constructor TSecP256R1FpFieldOps.Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); +var + LB, LB3: TCryptoLibUInt32Array; +begin + Inherited Create; + FOrderBits := AOrder.BitLength; + FN := TNat.FromBigInteger(FE_INTS * 32, AOrder); + FOne := TSecP256R1Field.FromBigInteger(TBigInteger.One); + FA := TNat.Copy(FE_INTS, (AA as ISecP256R1FieldElement).X); + LB := (AB as ISecP256R1FieldElement).X; + LB3 := TNat256.Create(); + TSecP256R1Field.Add(LB, LB, LB3); + TSecP256R1Field.Add(LB3, LB, LB3); + FB3 := LB3; +end; + +function TSecP256R1FpFieldOps.GetFieldInts: Int32; +begin + Result := FE_INTS; +end; + +function TSecP256R1FpFieldOps.GetOrderBits: Int32; +begin + Result := FOrderBits; +end; + +procedure TSecP256R1FpFieldOps.GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); +begin + TNat.Copy(FE_INTS, FN, 0, AZ, 0); +end; + +procedure TSecP256R1FpFieldOps.Mul(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Multiply(AX, AY, AZ); +end; + +procedure TSecP256R1FpFieldOps.Square(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Square(AX, AZ); +end; + +procedure TSecP256R1FpFieldOps.Add(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Add(AX, AY, AZ); +end; + +procedure TSecP256R1FpFieldOps.Sub(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Subtract(AX, AY, AZ); +end; + +procedure TSecP256R1FpFieldOps.MulByB3(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Multiply(AX, FB3, AZ); +end; + +procedure TSecP256R1FpFieldOps.MulByA(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Multiply(AX, FA, AZ); +end; + +procedure TSecP256R1FpFieldOps.Inv(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.Inv(AX, AZ); +end; + +function TSecP256R1FpFieldOps.IsZero(const AX: TCryptoLibUInt32Array): Boolean; +begin + Result := TSecP256R1Field.IsZero(AX) <> 0; +end; + +procedure TSecP256R1FpFieldOps.RandomMult(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt32Array); +begin + TSecP256R1Field.RandomMult(ARandom, AZ); +end; + +procedure TSecP256R1FpFieldOps.FieldFromBigInteger(const AX: TBigInteger; + const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, TSecP256R1Field.FromBigInteger(AX), 0, AZ, 0); +end; + +function TSecP256R1FpFieldOps.CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; +begin + Result := TSecP256R1FieldElement.Create(AX) as IECFieldElement; +end; + +procedure TSecP256R1FpFieldOps.FieldOne(const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, FOne, 0, AZ, 0); +end; + end. diff --git a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas index d91919cf..4c9e08c0 100644 --- a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas +++ b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP384R1Custom.pas @@ -36,6 +36,8 @@ interface ClpECFieldElement, ClpECPoint, ClpECLookupTables, + ClpIFpFieldOps, + ClpFixedWindowCTMultiplier, ClpIECCommon, ClpIECFieldElement, ClpISecP384R1Custom, @@ -191,11 +193,39 @@ TSecP384R1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable, function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override; function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override; function SupportsCoordinateSystem(ACoord: Int32): Boolean; override; + function CreateDefaultMultiplier: IECMultiplier; override; class property Q: TBigInteger read FQ; class property SecP384R1AffineZs: TCryptoLibGenericArray read FSecP384R1AffineZs; end; +type + TSecP384R1FpFieldOps = class sealed(TInterfacedObject, IFpFieldOps) + strict private + const + FE_INTS = Int32(12); + var + FA, FB3, FOne, FN: TCryptoLibUInt32Array; + FOrderBits: Int32; + public + constructor Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); + function GetFieldInts: Int32; + function GetOrderBits: Int32; + procedure GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); + procedure Mul(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Square(const AX, AZ: TCryptoLibUInt32Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Sub(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure MulByB3(const AX, AZ: TCryptoLibUInt32Array); + procedure MulByA(const AX, AZ: TCryptoLibUInt32Array); + procedure Inv(const AX, AZ: TCryptoLibUInt32Array); + function IsZero(const AX: TCryptoLibUInt32Array): Boolean; + procedure RandomMult(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt32Array); + function CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; + procedure FieldOne(const AZ: TCryptoLibUInt32Array); + end; + implementation { TSecP384R1Field } @@ -1208,4 +1238,109 @@ function TSecP384R1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean; end; end; +function TSecP384R1Curve.CreateDefaultMultiplier: IECMultiplier; +var + LCurve: IECCurve; + LFieldOps: IFpFieldOps; +begin + LCurve := Self as IECCurve; + LFieldOps := TSecP384R1FpFieldOps.Create(LCurve.A, LCurve.B, LCurve.Order); + Result := TFixedWindowCTMultiplier.Create(LFieldOps) as IECMultiplier; +end; + +{ TSecP384R1FpFieldOps } + +constructor TSecP384R1FpFieldOps.Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); +var + LB, LB3: TCryptoLibUInt32Array; +begin + Inherited Create; + FOrderBits := AOrder.BitLength; + FN := TNat.FromBigInteger(FE_INTS * 32, AOrder); + FOne := TSecP384R1Field.FromBigInteger(TBigInteger.One); + FA := TNat.Copy(FE_INTS, (AA as ISecP384R1FieldElement).X); + LB := (AB as ISecP384R1FieldElement).X; + LB3 := TNat.Create(FE_INTS); + TSecP384R1Field.Add(LB, LB, LB3); + TSecP384R1Field.Add(LB3, LB, LB3); + FB3 := LB3; +end; + +function TSecP384R1FpFieldOps.GetFieldInts: Int32; +begin + Result := FE_INTS; +end; + +function TSecP384R1FpFieldOps.GetOrderBits: Int32; +begin + Result := FOrderBits; +end; + +procedure TSecP384R1FpFieldOps.GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); +begin + TNat.Copy(FE_INTS, FN, 0, AZ, 0); +end; + +procedure TSecP384R1FpFieldOps.Mul(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Multiply(AX, AY, AZ); +end; + +procedure TSecP384R1FpFieldOps.Square(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Square(AX, AZ); +end; + +procedure TSecP384R1FpFieldOps.Add(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Add(AX, AY, AZ); +end; + +procedure TSecP384R1FpFieldOps.Sub(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Subtract(AX, AY, AZ); +end; + +procedure TSecP384R1FpFieldOps.MulByB3(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Multiply(AX, FB3, AZ); +end; + +procedure TSecP384R1FpFieldOps.MulByA(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Multiply(AX, FA, AZ); +end; + +procedure TSecP384R1FpFieldOps.Inv(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.Inv(AX, AZ); +end; + +function TSecP384R1FpFieldOps.IsZero(const AX: TCryptoLibUInt32Array): Boolean; +begin + Result := TSecP384R1Field.IsZero(AX) <> 0; +end; + +procedure TSecP384R1FpFieldOps.RandomMult(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt32Array); +begin + TSecP384R1Field.RandomMult(ARandom, AZ); +end; + +procedure TSecP384R1FpFieldOps.FieldFromBigInteger(const AX: TBigInteger; + const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, TSecP384R1Field.FromBigInteger(AX), 0, AZ, 0); +end; + +function TSecP384R1FpFieldOps.CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; +begin + Result := TSecP384R1FieldElement.Create(AX) as IECFieldElement; +end; + +procedure TSecP384R1FpFieldOps.FieldOne(const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, FOne, 0, AZ, 0); +end; + end. diff --git a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas index 585231a8..68164844 100644 --- a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas +++ b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecP521R1Custom.pas @@ -36,6 +36,8 @@ interface ClpECFieldElement, ClpECPoint, ClpECLookupTables, + ClpIFpFieldOps, + ClpFixedWindowCTMultiplier, ClpIECCommon, ClpIECFieldElement, ClpISecP521R1Custom, @@ -188,11 +190,39 @@ TSecP521R1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable, function RandomFieldElement(const ARandom: ISecureRandom): IECFieldElement; override; function RandomFieldElementMult(const ARandom: ISecureRandom): IECFieldElement; override; function SupportsCoordinateSystem(ACoord: Int32): Boolean; override; + function CreateDefaultMultiplier: IECMultiplier; override; class property Q: TBigInteger read FQ; class property SecP521R1AffineZs: TCryptoLibGenericArray read FSecP521R1AffineZs; end; +type + TSecP521R1FpFieldOps = class sealed(TInterfacedObject, IFpFieldOps) + strict private + const + FE_INTS = Int32(17); + var + FA, FB3, FOne, FN: TCryptoLibUInt32Array; + FOrderBits: Int32; + public + constructor Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); + function GetFieldInts: Int32; + function GetOrderBits: Int32; + procedure GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); + procedure Mul(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Square(const AX, AZ: TCryptoLibUInt32Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure Sub(const AX, AY, AZ: TCryptoLibUInt32Array); + procedure MulByB3(const AX, AZ: TCryptoLibUInt32Array); + procedure MulByA(const AX, AZ: TCryptoLibUInt32Array); + procedure Inv(const AX, AZ: TCryptoLibUInt32Array); + function IsZero(const AX: TCryptoLibUInt32Array): Boolean; + procedure RandomMult(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt32Array); + function CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; + procedure FieldOne(const AZ: TCryptoLibUInt32Array); + end; + implementation { TSecP521R1Field } @@ -1042,4 +1072,109 @@ function TSecP521R1Curve.SupportsCoordinateSystem(ACoord: Int32): Boolean; end; end; +function TSecP521R1Curve.CreateDefaultMultiplier: IECMultiplier; +var + LCurve: IECCurve; + LFieldOps: IFpFieldOps; +begin + LCurve := Self as IECCurve; + LFieldOps := TSecP521R1FpFieldOps.Create(LCurve.A, LCurve.B, LCurve.Order); + Result := TFixedWindowCTMultiplier.Create(LFieldOps) as IECMultiplier; +end; + +{ TSecP521R1FpFieldOps } + +constructor TSecP521R1FpFieldOps.Create(const AA, AB: IECFieldElement; const AOrder: TBigInteger); +var + LB, LB3: TCryptoLibUInt32Array; +begin + Inherited Create; + FOrderBits := AOrder.BitLength; + FN := TNat.FromBigInteger(FE_INTS * 32, AOrder); + FOne := TSecP521R1Field.FromBigInteger(TBigInteger.One); + FA := TNat.Copy(FE_INTS, (AA as ISecP521R1FieldElement).X); + LB := (AB as ISecP521R1FieldElement).X; + LB3 := TNat.Create(FE_INTS); + TSecP521R1Field.Add(LB, LB, LB3); + TSecP521R1Field.Add(LB3, LB, LB3); + FB3 := LB3; +end; + +function TSecP521R1FpFieldOps.GetFieldInts: Int32; +begin + Result := FE_INTS; +end; + +function TSecP521R1FpFieldOps.GetOrderBits: Int32; +begin + Result := FOrderBits; +end; + +procedure TSecP521R1FpFieldOps.GetOrder(const AZ: TCryptoLibUInt32Array; AInts: Int32); +begin + TNat.Copy(FE_INTS, FN, 0, AZ, 0); +end; + +procedure TSecP521R1FpFieldOps.Mul(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Multiply(AX, AY, AZ); +end; + +procedure TSecP521R1FpFieldOps.Square(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Square(AX, AZ); +end; + +procedure TSecP521R1FpFieldOps.Add(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Add(AX, AY, AZ); +end; + +procedure TSecP521R1FpFieldOps.Sub(const AX, AY, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Subtract(AX, AY, AZ); +end; + +procedure TSecP521R1FpFieldOps.MulByB3(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Multiply(AX, FB3, AZ); +end; + +procedure TSecP521R1FpFieldOps.MulByA(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Multiply(AX, FA, AZ); +end; + +procedure TSecP521R1FpFieldOps.Inv(const AX, AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.Inv(AX, AZ); +end; + +function TSecP521R1FpFieldOps.IsZero(const AX: TCryptoLibUInt32Array): Boolean; +begin + Result := TSecP521R1Field.IsZero(AX) <> 0; +end; + +procedure TSecP521R1FpFieldOps.RandomMult(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt32Array); +begin + TSecP521R1Field.RandomMult(ARandom, AZ); +end; + +procedure TSecP521R1FpFieldOps.FieldFromBigInteger(const AX: TBigInteger; + const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, TSecP521R1Field.FromBigInteger(AX), 0, AZ, 0); +end; + +function TSecP521R1FpFieldOps.CreateFieldElement(const AX: TCryptoLibUInt32Array): IECFieldElement; +begin + Result := TSecP521R1FieldElement.Create(AX) as IECFieldElement; +end; + +procedure TSecP521R1FpFieldOps.FieldOne(const AZ: TCryptoLibUInt32Array); +begin + TNat.Copy(FE_INTS, FOne, 0, AZ, 0); +end; + end. diff --git a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283K1Custom.pas b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283K1Custom.pas index c645ce16..0dbe161b 100644 --- a/CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283K1Custom.pas +++ b/CryptoLib/src/Math/EC/Custom/Sec/ClpSecT283K1Custom.pas @@ -26,6 +26,7 @@ interface ClpBitOperations, ClpNat, ClpNat320, + ClpPack, ClpInterleave, ClpEncoders, ClpECCurve, @@ -34,6 +35,9 @@ interface ClpECPoint, ClpECLookupTables, ClpMultipliers, + ClpIF2mFieldOps, + ClpF2mMontgomeryLadderCTMultiplier, + ClpISecureRandom, ClpIECCommon, ClpIECFieldElement, ClpISecT283K1Custom, @@ -61,6 +65,8 @@ TSecT283Field = class sealed(TObject) class procedure ImplMultiply(const AX, AY, AZZ: TCryptoLibUInt64Array); static; class procedure ImplSquare(const AX, AZZ: TCryptoLibUInt64Array); static; class constructor Create; + private + class procedure InvertCT(const AX, AZ: TCryptoLibUInt64Array); static; public class procedure Add(const AX, AY, AZ: TCryptoLibUInt64Array); static; class procedure AddBothTo(const AX, AY, AZ: TCryptoLibUInt64Array); static; @@ -204,6 +210,31 @@ TSecT283K1LookupTable = class sealed(TAbstractECLookupTable, IECLookupTable, class property SecT283K1AffineZs: TCryptoLibGenericArray read FSecT283K1AffineZs; end; +type + TSecT283K1F2mFieldOps = class sealed(TInterfacedObject, IF2mFieldOps) + strict private + const + FE_LONGS = Int32(5); + M27 = UInt64($7FFFFFF); + var + FCard: TCryptoLibUInt32Array; + FCardLongs, FCardBits: Int32; + public + constructor Create(const AOrder, ACofactor: TBigInteger); + function GetFieldLongs: Int32; + function GetCardinalityBits: Int32; + procedure GetCardinality(const AZ: TCryptoLibUInt32Array; AInts: Int32); + procedure Mul(const AX, AY, AZ: TCryptoLibUInt64Array); + procedure Square(const AX, AZ: TCryptoLibUInt64Array); + procedure Add(const AX, AY, AZ: TCryptoLibUInt64Array); + procedure MulByB(const AX, AZ: TCryptoLibUInt64Array); + procedure Inv(const AX, AZ: TCryptoLibUInt64Array); + function IsZeroMask(const AX: TCryptoLibUInt64Array): UInt64; + procedure RandomNonZero(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt64Array); + procedure FieldFromBigInteger(const AX: TBigInteger; const AZ: TCryptoLibUInt64Array); + function CreateFieldElement(const AX: TCryptoLibUInt64Array): IECFieldElement; + end; + implementation { TSecT283Field } @@ -472,11 +503,17 @@ class procedure TSecT283Field.HalfTrace(const AX, AZ: TCryptoLibUInt64Array); end; class procedure TSecT283Field.Invert(const AX, AZ: TCryptoLibUInt64Array); -var - LT0, LT1: TCryptoLibUInt64Array; begin if TNat320.IsZero64(AX) then raise EInvalidOperationCryptoLibException.CreateRes(@SDivisionByZeroInFieldInversion); + InvertCT(AX, AZ); +end; + +class procedure TSecT283Field.InvertCT(const AX, AZ: TCryptoLibUInt64Array); +var + LT0, LT1: TCryptoLibUInt64Array; +begin + // guard-free Itoh-Tsujii chain a^(2^283 - 2); 0 is a fixed point so InvertCT(0)=0 SetLength(LT0, 5); SetLength(LT1, 5); Square(AX, LT0); @@ -1226,8 +1263,13 @@ function TSecT283K1Curve.GetIsKoblitz: Boolean; end; function TSecT283K1Curve.CreateDefaultMultiplier: IECMultiplier; +var + LCurve: IECCurve; + LFieldOps: IF2mFieldOps; begin - Result := TWTauNafMultiplier.Create() as IECMultiplier; + LCurve := Self as IECCurve; + LFieldOps := TSecT283K1F2mFieldOps.Create(LCurve.Order, LCurve.Cofactor); + Result := TF2mMontgomeryLadderCTMultiplier.Create(LFieldOps) as IECMultiplier; end; function TSecT283K1Curve.CloneCurve: IECCurve; @@ -1311,4 +1353,90 @@ function TSecT283K1Curve.GetK3: Int32; Result := 12; end; +{ TSecT283K1F2mFieldOps } + +constructor TSecT283K1F2mFieldOps.Create(const AOrder, ACofactor: TBigInteger); +var + LCard: TBigInteger; +begin + Inherited Create; + LCard := AOrder.Multiply(ACofactor); + FCardBits := LCard.BitLength; + FCardLongs := TNat.GetLengthForBits(FCardBits); + FCard := TNat.FromBigInteger(FCardBits, LCard); +end; + +function TSecT283K1F2mFieldOps.GetFieldLongs: Int32; +begin + Result := FE_LONGS; +end; + +function TSecT283K1F2mFieldOps.GetCardinalityBits: Int32; +begin + Result := FCardBits; +end; + +procedure TSecT283K1F2mFieldOps.GetCardinality(const AZ: TCryptoLibUInt32Array; AInts: Int32); +begin + TNat.Copy(FCardLongs, FCard, 0, AZ, 0); +end; + +procedure TSecT283K1F2mFieldOps.Mul(const AX, AY, AZ: TCryptoLibUInt64Array); +begin + TSecT283Field.Multiply(AX, AY, AZ); +end; + +procedure TSecT283K1F2mFieldOps.Square(const AX, AZ: TCryptoLibUInt64Array); +begin + TSecT283Field.Square(AX, AZ); +end; + +procedure TSecT283K1F2mFieldOps.Add(const AX, AY, AZ: TCryptoLibUInt64Array); +begin + TSecT283Field.Add(AX, AY, AZ); +end; + +procedure TSecT283K1F2mFieldOps.MulByB(const AX, AZ: TCryptoLibUInt64Array); +begin + // sect283k1 has b = 1: z := x + TNat.Copy64(FE_LONGS, AX, 0, AZ, 0); +end; + +procedure TSecT283K1F2mFieldOps.Inv(const AX, AZ: TCryptoLibUInt64Array); +begin + TSecT283Field.InvertCT(AX, AZ); +end; + +function TSecT283K1F2mFieldOps.IsZeroMask(const AX: TCryptoLibUInt64Array): UInt64; +var + LV: UInt64; +begin + LV := AX[0] or AX[1] or AX[2] or AX[3] or AX[4]; + Result := not UInt64(TBitOperations.Asr64(Int64(LV or (UInt64(0) - LV)), 63)); +end; + +procedure TSecT283K1F2mFieldOps.RandomNonZero(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt64Array); +var + LBytes: TCryptoLibByteArray; +begin + System.SetLength(LBytes, FE_LONGS * 8); + repeat + ARandom.NextBytes(LBytes); + TPack.LE_To_UInt64(LBytes, 0, AZ, 0, FE_LONGS); + AZ[FE_LONGS - 1] := AZ[FE_LONGS - 1] and M27; + until IsZeroMask(AZ) = 0; +end; + +procedure TSecT283K1F2mFieldOps.FieldFromBigInteger(const AX: TBigInteger; + const AZ: TCryptoLibUInt64Array); +begin + TNat.Copy64(FE_LONGS, TSecT283Field.FromBigInteger(AX), 0, AZ, 0); +end; + +function TSecT283K1F2mFieldOps.CreateFieldElement(const AX: TCryptoLibUInt64Array): IECFieldElement; +begin + Result := TSecT283FieldElement.Create(AX) as IECFieldElement; +end; + end. diff --git a/CryptoLib/src/Math/EC/Multiplier/ClpF2mMontgomeryLadderCTMultiplier.pas b/CryptoLib/src/Math/EC/Multiplier/ClpF2mMontgomeryLadderCTMultiplier.pas new file mode 100644 index 00000000..43127a5d --- /dev/null +++ b/CryptoLib/src/Math/EC/Multiplier/ClpF2mMontgomeryLadderCTMultiplier.pas @@ -0,0 +1,186 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ClpF2mMontgomeryLadderCTMultiplier; + +{$I ..\..\..\Include\CryptoLib.inc} + +interface + +uses + SysUtils, + ClpBigInteger, + ClpNat, + ClpPack, + ClpMultipliers, + ClpIF2mFieldOps, + ClpLopezDahabLadder, + ClpISecureRandom, + ClpSecureRandom, + ClpIECFieldElement, + ClpIECCommon, + ClpCryptoLibTypes, + ClpCryptoLibExceptions; + +type + /// + /// Constant-time single-scalar variable-point multiplier for binary (GF(2^m)) + /// curves — a plain López–Dahab Montgomery ladder (x-only), with a branch-free + /// conditional swap, a batched single field inversion for y-recovery, scalar + /// blinding by the group cardinality, independent randomized projective + /// coordinates, and a fixed processing length. + /// + TF2mMontgomeryLadderCTMultiplier = class sealed(TAbstractECMultiplier, IECMultiplier) + strict private + const + BLIND_BITS = Int32(64); + var + FFieldOps: IF2mFieldOps; + FRandom: ISecureRandom; + function GetRandom: ISecureRandom; + procedure GenerateBlind(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + strict protected + function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; override; + public + constructor Create(const AFieldOps: IF2mFieldOps); overload; + constructor Create(const AFieldOps: IF2mFieldOps; const ARandom: ISecureRandom); overload; + end; + +implementation + +resourcestring + SPointNotOnCurve = 'point is not a valid subgroup point for constant-time multiplication'; + +{ TF2mMontgomeryLadderCTMultiplier } + +constructor TF2mMontgomeryLadderCTMultiplier.Create(const AFieldOps: IF2mFieldOps); +begin + Inherited Create; + FFieldOps := AFieldOps; +end; + +constructor TF2mMontgomeryLadderCTMultiplier.Create(const AFieldOps: IF2mFieldOps; + const ARandom: ISecureRandom); +begin + Inherited Create; + FFieldOps := AFieldOps; + FRandom := ARandom; +end; + +function TF2mMontgomeryLadderCTMultiplier.GetRandom: ISecureRandom; +begin + if FRandom = nil then + FRandom := TSecureRandom.Create() as ISecureRandom; + Result := FRandom; +end; + +procedure TF2mMontgomeryLadderCTMultiplier.GenerateBlind(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt32Array); +var + LBytes: TCryptoLibByteArray; +begin + System.SetLength(LBytes, BLIND_BITS div 8); + ARandom.NextBytes(LBytes); + TPack.LE_To_UInt32(LBytes, 0, AZ, 0, BLIND_BITS div 32); +end; + +function TF2mMontgomeryLadderCTMultiplier.MultiplyPositive(const AP: IECPoint; + const AK: TBigInteger): IECPoint; +var + LN, LScalarBits, LScalarInts, LI, LKbit, LPbit: Int32; + LRandom: ISecureRandom; + LAffine: IECPoint; + LBaseX, LBaseY, LLambda1, LLambda2, LXOut, LLOut: TCryptoLibUInt64Array; + LCard, LR, LProd, LK, LKPrime: TCryptoLibUInt32Array; + LQ1, LQ2: TLDPoint; + LIsInfinity: Boolean; + LXfe, LLfe: IECFieldElement; +begin + if not AP.IsValid then + raise EInvalidOperationCryptoLibException.CreateRes(@SPointNotOnCurve); + + LN := FFieldOps.GetFieldLongs; + LRandom := GetRandom; + + // --- affine coordinates of the (public) input point --- + LAffine := AP.Normalize(); + LBaseX := TNat.Create64(LN); + LBaseY := TNat.Create64(LN); + FFieldOps.FieldFromBigInteger(LAffine.AffineXCoord.ToBigInteger(), LBaseX); + FFieldOps.FieldFromBigInteger(LAffine.AffineYCoord.ToBigInteger(), LBaseY); + // defensive: x = 0 is the 2-torsion point, not in the odd-order subgroup + if FFieldOps.IsZeroMask(LBaseX) <> 0 then + raise EInvalidOperationCryptoLibException.CreateRes(@SPointNotOnCurve); + + // --- scalar blinding by the cardinality: k' = k + r*(h*n) --- + LScalarBits := FFieldOps.GetCardinalityBits + BLIND_BITS + 1; + LScalarInts := TNat.GetLengthForBits(LScalarBits) + 1; + LCard := TNat.Create(LScalarInts); + LR := TNat.Create(LScalarInts); + LProd := TNat.Create(LScalarInts * 2); + FFieldOps.GetCardinality(LCard, LScalarInts); + GenerateBlind(LRandom, LR); + TNat.Mul(LScalarInts, LR, LCard, LProd); + LK := TNat.FromBigInteger(LScalarInts * 32, AK); + LKPrime := TNat.Create(LScalarInts); + TNat.Add(LScalarInts, LK, LProd, LKPrime); + + try + // --- randomized projective init: Q1 = infinity = (lambda1 : 0), Q2 = P = (lambda2*x : lambda2) --- + LLambda1 := TNat.Create64(LN); + LLambda2 := TNat.Create64(LN); + FFieldOps.RandomNonZero(LRandom, LLambda1); + FFieldOps.RandomNonZero(LRandom, LLambda2); + + LQ1.X := TNat.Create64(LN); LQ1.Z := TNat.Create64(LN); + LQ2.X := TNat.Create64(LN); LQ2.Z := TNat.Create64(LN); + TNat.Copy64(LN, LLambda1, LQ1.X); // Q1.X = lambda1, Q1.Z = 0 (infinity) + FFieldOps.Mul(LLambda2, LBaseX, LQ2.X); // Q2.X = lambda2 * x + TNat.Copy64(LN, LLambda2, LQ2.Z); // Q2.Z = lambda2 + + // --- fixed-length Montgomery ladder with branch-free conditional swap --- + LPbit := 0; + for LI := LScalarBits - 1 downto 0 do + begin + LKbit := Int32(TNat.GetBit(LKPrime, LI)) xor LPbit; + TNat.CSwap64(LN, LKbit, LQ1.X, LQ2.X); + TNat.CSwap64(LN, LKbit, LQ1.Z, LQ2.Z); + LQ2 := TLopezDahabLadder.MAdd(FFieldOps, LQ1, LQ2, LBaseX); + LQ1 := TLopezDahabLadder.MDouble(FFieldOps, LQ1); + LPbit := Int32(TNat.GetBit(LKPrime, LI)); + end; + TNat.CSwap64(LN, LPbit, LQ1.X, LQ2.X); + TNat.CSwap64(LN, LPbit, LQ1.Z, LQ2.Z); + + // --- y-recovery (batched single inversion) --- + LXOut := TNat.Create64(LN); + LLOut := TNat.Create64(LN); + TLopezDahabLadder.Recover(FFieldOps, LQ1, LQ2, LBaseX, LBaseY, LXOut, LLOut, LIsInfinity); + if LIsInfinity then + Exit(AP.Curve.Infinity); + + LXfe := FFieldOps.CreateFieldElement(LXOut); + LLfe := FFieldOps.CreateFieldElement(LLOut); + Result := AP.Curve.CreateRawPoint(LXfe, LLfe); + finally + TNat.Zero(LScalarInts, LKPrime); + TNat.Zero(LScalarInts, LK); + TNat.Zero(LScalarInts, LR); + TNat.Zero(LScalarInts * 2, LProd); + end; +end; + +end. diff --git a/CryptoLib/src/Math/EC/Multiplier/ClpFixedWindowCTMultiplier.pas b/CryptoLib/src/Math/EC/Multiplier/ClpFixedWindowCTMultiplier.pas new file mode 100644 index 00000000..a333205f --- /dev/null +++ b/CryptoLib/src/Math/EC/Multiplier/ClpFixedWindowCTMultiplier.pas @@ -0,0 +1,251 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ClpFixedWindowCTMultiplier; + +{$I ..\..\..\Include\CryptoLib.inc} + +interface + +uses + SysUtils, + ClpBigInteger, + ClpNat, + ClpPack, + ClpBitOperations, + ClpMultipliers, + ClpIFpFieldOps, + ClpHomogeneousPoint, + ClpISecureRandom, + ClpSecureRandom, + ClpIECFieldElement, + ClpIECCommon, + ClpCryptoLibTypes, + ClpCryptoLibExceptions; + +type + /// + /// Constant-time single-scalar variable-point multiplier for prime-field (Fp) + /// short-Weierstrass curves, driven by an IFpFieldOps adapter. Unsigned fixed + /// window over homogeneous complete formulas, masked table lookups only, one + /// unconditional addition per window; scalar blinding, randomized projective + /// coordinates and a fixed processing length as countermeasures. + /// + TFixedWindowCTMultiplier = class sealed(TAbstractECMultiplier, IECMultiplier) + strict private + const + WINDOW_BITS = Int32(4); + TABLE_SIZE = Int32(16); + DEFAULT_BLIND_BITS = Int32(64); + MAX_BLIND_BITS = Int32(512); + var + FFieldOps: IFpFieldOps; + FRandom: ISecureRandom; + FBlindBits: Int32; + function GetRandom: ISecureRandom; + procedure GenerateBlind(const ARandom: ISecureRandom; const AZ: TCryptoLibUInt32Array); + function SelectEntry(const ATable: TCryptoLibGenericArray; + AIndex: Int32): TCTHomogPoint; + strict protected + function MultiplyPositive(const AP: IECPoint; const AK: TBigInteger): IECPoint; override; + public + constructor Create(const AFieldOps: IFpFieldOps; + ABlindBits: Int32 = DEFAULT_BLIND_BITS); overload; + constructor Create(const AFieldOps: IFpFieldOps; const ARandom: ISecureRandom; + ABlindBits: Int32 = DEFAULT_BLIND_BITS); overload; + end; + +implementation + +resourcestring + SPointNotOnCurve = 'point is not a valid point on the curve for constant-time multiplication'; + SScalarTooLarge = 'scalar is larger than the curve order'; + SInvalidBlindBits = 'blinding length must be a multiple of 32 between 64 and 512'; + +{ TFixedWindowCTMultiplier } + +constructor TFixedWindowCTMultiplier.Create(const AFieldOps: IFpFieldOps; + ABlindBits: Int32); +begin + Inherited Create; + if (ABlindBits < DEFAULT_BLIND_BITS) or (ABlindBits > MAX_BLIND_BITS) + or ((ABlindBits and 31) <> 0) then + raise EArgumentCryptoLibException.CreateRes(@SInvalidBlindBits); + FFieldOps := AFieldOps; + FBlindBits := ABlindBits; +end; + +constructor TFixedWindowCTMultiplier.Create(const AFieldOps: IFpFieldOps; + const ARandom: ISecureRandom; ABlindBits: Int32); +begin + Inherited Create; + if (ABlindBits < DEFAULT_BLIND_BITS) or (ABlindBits > MAX_BLIND_BITS) + or ((ABlindBits and 31) <> 0) then + raise EArgumentCryptoLibException.CreateRes(@SInvalidBlindBits); + FFieldOps := AFieldOps; + FRandom := ARandom; + FBlindBits := ABlindBits; +end; + +function TFixedWindowCTMultiplier.GetRandom: ISecureRandom; +begin + if FRandom = nil then + FRandom := TSecureRandom.Create() as ISecureRandom; + Result := FRandom; +end; + +procedure TFixedWindowCTMultiplier.GenerateBlind(const ARandom: ISecureRandom; + const AZ: TCryptoLibUInt32Array); +var + LBytes: TCryptoLibByteArray; +begin + // FBlindBits of fresh randomness in the low limbs of AZ + System.SetLength(LBytes, FBlindBits div 8); + ARandom.NextBytes(LBytes); + TPack.LE_To_UInt32(LBytes, 0, AZ, 0, FBlindBits div 32); +end; + +function TFixedWindowCTMultiplier.SelectEntry( + const ATable: TCryptoLibGenericArray; AIndex: Int32): TCTHomogPoint; +var + LN, LI, LJ: Int32; + LMask: UInt32; +begin + LN := FFieldOps.GetFieldInts; + Result.X := TNat.Create(LN); + Result.Y := TNat.Create(LN); + Result.Z := TNat.Create(LN); + for LI := 0 to TABLE_SIZE - 1 do + begin + LMask := UInt32(TBitOperations.Asr32(((LI xor AIndex) - 1), 31)); + for LJ := 0 to LN - 1 do + begin + Result.X[LJ] := Result.X[LJ] xor (ATable[LI].X[LJ] and LMask); + Result.Y[LJ] := Result.Y[LJ] xor (ATable[LI].Y[LJ] and LMask); + Result.Z[LJ] := Result.Z[LJ] xor (ATable[LI].Z[LJ] and LMask); + end; + end; +end; + +function TFixedWindowCTMultiplier.MultiplyPositive(const AP: IECPoint; + const AK: TBigInteger): IECPoint; +var + LFieldInts, LScalarBits, LScalarInts, LWindows, LI, LJ, LBit, LLimb, LShift, LDigit: Int32; + LTable: TCryptoLibGenericArray; + LBase, LAcc, LSel: TCTHomogPoint; + LLambda, LXa, LYa, LN, LR, LProd, LK, LKPrime: TCryptoLibUInt32Array; + LIsInfinity: Boolean; + LXfe, LYfe: IECFieldElement; + LAffine: IECPoint; + LRandom: ISecureRandom; +begin + if not AP.IsValid then + raise EInvalidOperationCryptoLibException.CreateRes(@SPointNotOnCurve); + + // reject scalars wider than the group order (the fixed-width buffer holds up to that) + if AK.BitLength > FFieldOps.GetOrderBits then + raise EInvalidOperationCryptoLibException.CreateRes(@SScalarTooLarge); + + LFieldInts := FFieldOps.GetFieldInts; + LRandom := GetRandom; + + // --- affine coordinates of the (public) input point --- + LAffine := AP.Normalize(); + LXa := TNat.Create(LFieldInts); + LYa := TNat.Create(LFieldInts); + FFieldOps.FieldFromBigInteger(LAffine.AffineXCoord.ToBigInteger(), LXa); + FFieldOps.FieldFromBigInteger(LAffine.AffineYCoord.ToBigInteger(), LYa); + + // --- randomized projective coordinates: base = (lambda*x, lambda*y, lambda) --- + LLambda := TNat.Create(LFieldInts); + FFieldOps.RandomMult(LRandom, LLambda); + LBase := TCTHomogeneousMath.ScaleRandom(FFieldOps, + TCTHomogeneousMath.FromAffine(FFieldOps, LXa, LYa), LLambda); + + // --- projective precomputation table [0]=O, [i]=[i]*base --- + System.SetLength(LTable, TABLE_SIZE); + LTable[0] := TCTHomogeneousMath.Infinity(FFieldOps); + LTable[1] := LBase; + for LI := 2 to TABLE_SIZE - 1 do + LTable[LI] := TCTHomogeneousMath.Add(FFieldOps, LTable[LI - 1], LBase); + + // --- scalar blinding in fixed-width Nat: k' = k + r*n --- + LScalarBits := FFieldOps.GetOrderBits + FBlindBits + 1; + LScalarInts := TNat.GetLengthForBits(LScalarBits) + 1; + LN := TNat.Create(LScalarInts); + LR := TNat.Create(LScalarInts); + LProd := TNat.Create(LScalarInts * 2); + FFieldOps.GetOrder(LN, LScalarInts); + GenerateBlind(LRandom, LR); + TNat.Mul(LScalarInts, LR, LN, LProd); + LK := TNat.FromBigInteger(LScalarInts * 32, AK); + LKPrime := TNat.Create(LScalarInts); + TNat.Add(LScalarInts, LK, LProd, LKPrime); + + try + // --- fixed-length windowed ladder --- + LWindows := (LScalarBits + WINDOW_BITS - 1) div WINDOW_BITS; + LAcc := TCTHomogeneousMath.Infinity(FFieldOps); + for LI := LWindows - 1 downto 0 do + begin + for LJ := 0 to WINDOW_BITS - 1 do + LAcc := TCTHomogeneousMath.Double(FFieldOps, LAcc); + + // WINDOW_BITS divides 32, so a digit never spans a limb boundary + LBit := LI * WINDOW_BITS; + LLimb := TBitOperations.Asr32(LBit, 5); + LShift := LBit and 31; + LDigit := Int32((LKPrime[LLimb] shr LShift) and UInt32(TABLE_SIZE - 1)); + + LSel := SelectEntry(LTable, LDigit); + LAcc := TCTHomogeneousMath.Add(FFieldOps, LAcc, LSel); + end; + + TCTHomogeneousMath.ToAffine(FFieldOps, LAcc, LXa, LYa, LIsInfinity); + if LIsInfinity then + Exit(AP.Curve.Infinity); + + LXfe := FFieldOps.CreateFieldElement(LXa); + LYfe := FFieldOps.CreateFieldElement(LYa); + Result := AP.Curve.CreateRawPoint(LXfe, LYfe); + finally + TNat.Zero(LScalarInts, LKPrime); + TNat.Zero(LScalarInts, LK); + TNat.Zero(LScalarInts, LR); + TNat.Zero(LScalarInts * 2, LProd); + TNat.Zero(LFieldInts, LLambda); + for LI := 0 to TABLE_SIZE - 1 do + begin + TNat.Zero(LFieldInts, LTable[LI].X); + TNat.Zero(LFieldInts, LTable[LI].Y); + TNat.Zero(LFieldInts, LTable[LI].Z); + end; + if LAcc.X <> nil then + begin + TNat.Zero(LFieldInts, LAcc.X); + TNat.Zero(LFieldInts, LAcc.Y); + TNat.Zero(LFieldInts, LAcc.Z); + end; + if LSel.X <> nil then + begin + TNat.Zero(LFieldInts, LSel.X); + TNat.Zero(LFieldInts, LSel.Y); + TNat.Zero(LFieldInts, LSel.Z); + end; + end; +end; + +end. diff --git a/CryptoLib/src/Math/EC/Multiplier/ClpHomogeneousPoint.pas b/CryptoLib/src/Math/EC/Multiplier/ClpHomogeneousPoint.pas new file mode 100644 index 00000000..d8c83913 --- /dev/null +++ b/CryptoLib/src/Math/EC/Multiplier/ClpHomogeneousPoint.pas @@ -0,0 +1,232 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ClpHomogeneousPoint; + +{$I ..\..\..\Include\CryptoLib.inc} + +interface + +uses + ClpNat, + ClpIFpFieldOps, + ClpCryptoLibTypes; + +type + /// + /// A point in homogeneous projective coordinates (X : Y : Z), x = X/Z, y = Y/Z, + /// identity = (0 : 1 : 0). Value aggregate over the three limb arrays. + /// + TCTHomogPoint = record + X, Y, Z: TCryptoLibUInt32Array; + end; + + /// + /// Renes-Costello-Batina (EUROCRYPT 2016) complete addition formulas, + /// a = -3 specialization (Algorithms 4 and 6), homogeneous coordinates. + /// Exception-free for prime-order (cofactor 1) short-Weierstrass curves. + /// + TCTHomogeneousMath = class sealed(TObject) + public + class function Infinity(const AFO: IFpFieldOps): TCTHomogPoint; static; + class function FromAffine(const AFO: IFpFieldOps; + const AX, AY: TCryptoLibUInt32Array): TCTHomogPoint; static; + class function ScaleRandom(const AFO: IFpFieldOps; const AP: TCTHomogPoint; + const ALambda: TCryptoLibUInt32Array): TCTHomogPoint; static; + class function Add(const AFO: IFpFieldOps; const AP, AQ: TCTHomogPoint): TCTHomogPoint; static; + class function Double(const AFO: IFpFieldOps; const AP: TCTHomogPoint): TCTHomogPoint; static; + class procedure ToAffine(const AFO: IFpFieldOps; const AP: TCTHomogPoint; + out AX, AY: TCryptoLibUInt32Array; out AIsInfinity: Boolean); static; + end; + +implementation + +{ TCTHomogeneousMath } + +class function TCTHomogeneousMath.Infinity(const AFO: IFpFieldOps): TCTHomogPoint; +var + LN: Int32; + LX, LY, LZ: TCryptoLibUInt32Array; +begin + LN := AFO.GetFieldInts; + LX := TNat.Create(LN); + LY := TNat.Create(LN); + LZ := TNat.Create(LN); + AFO.FieldOne(LY); + Result.X := LX; + Result.Y := LY; + Result.Z := LZ; +end; + +class function TCTHomogeneousMath.FromAffine(const AFO: IFpFieldOps; + const AX, AY: TCryptoLibUInt32Array): TCTHomogPoint; +var + LN: Int32; + LX, LY, LZ: TCryptoLibUInt32Array; +begin + LN := AFO.GetFieldInts; + LX := TNat.Copy(LN, AX); + LY := TNat.Copy(LN, AY); + LZ := TNat.Create(LN); + AFO.FieldOne(LZ); + Result.X := LX; + Result.Y := LY; + Result.Z := LZ; +end; + +class function TCTHomogeneousMath.ScaleRandom(const AFO: IFpFieldOps; + const AP: TCTHomogPoint; const ALambda: TCryptoLibUInt32Array): TCTHomogPoint; +var + LN: Int32; +begin + LN := AFO.GetFieldInts; + Result.X := TNat.Create(LN); + Result.Y := TNat.Create(LN); + Result.Z := TNat.Create(LN); + AFO.Mul(AP.X, ALambda, Result.X); + AFO.Mul(AP.Y, ALambda, Result.Y); + AFO.Mul(AP.Z, ALambda, Result.Z); +end; + +class function TCTHomogeneousMath.Add(const AFO: IFpFieldOps; + const AP, AQ: TCTHomogPoint): TCTHomogPoint; +var + LN: Int32; + Lt0, Lt1, Lt2, Lt3, Lt4, Lt5, LX3, LY3, LZ3: TCryptoLibUInt32Array; + LX1, LY1, LZ1, LX2, LY2, LZ2: TCryptoLibUInt32Array; +begin + LN := AFO.GetFieldInts; + LX1 := AP.X; LY1 := AP.Y; LZ1 := AP.Z; + LX2 := AQ.X; LY2 := AQ.Y; LZ2 := AQ.Z; + + Lt0 := TNat.Create(LN); Lt1 := TNat.Create(LN); Lt2 := TNat.Create(LN); + Lt3 := TNat.Create(LN); Lt4 := TNat.Create(LN); Lt5 := TNat.Create(LN); + LX3 := TNat.Create(LN); LY3 := TNat.Create(LN); LZ3 := TNat.Create(LN); + + // RCB2016 complete addition (Algorithm 1), explicit a and b3 = 3b + AFO.Mul(LX1, LX2, Lt0); // t0 = X1*X2 + AFO.Mul(LY1, LY2, Lt1); // t1 = Y1*Y2 + AFO.Mul(LZ1, LZ2, Lt2); // t2 = Z1*Z2 + AFO.Add(LX1, LY1, Lt3); // t3 = X1+Y1 + AFO.Add(LX2, LY2, Lt4); // t4 = X2+Y2 + AFO.Mul(Lt3, Lt4, Lt3); // t3 = t3*t4 + AFO.Add(Lt0, Lt1, Lt4); // t4 = t0+t1 + AFO.Sub(Lt3, Lt4, Lt3); // t3 = t3-t4 + AFO.Add(LX1, LZ1, Lt4); // t4 = X1+Z1 + AFO.Add(LX2, LZ2, Lt5); // t5 = X2+Z2 + AFO.Mul(Lt4, Lt5, Lt4); // t4 = t4*t5 + AFO.Add(Lt0, Lt2, Lt5); // t5 = t0+t2 + AFO.Sub(Lt4, Lt5, Lt4); // t4 = t4-t5 + AFO.Add(LY1, LZ1, Lt5); // t5 = Y1+Z1 + AFO.Add(LY2, LZ2, LX3); // X3 = Y2+Z2 + AFO.Mul(Lt5, LX3, Lt5); // t5 = t5*X3 + AFO.Add(Lt1, Lt2, LX3); // X3 = t1+t2 + AFO.Sub(Lt5, LX3, Lt5); // t5 = t5-X3 + AFO.MulByA(Lt4, LZ3); // Z3 = a*t4 + AFO.MulByB3(Lt2, LX3); // X3 = b3*t2 + AFO.Add(LX3, LZ3, LZ3); // Z3 = X3+Z3 + AFO.Sub(Lt1, LZ3, LX3); // X3 = t1-Z3 + AFO.Add(Lt1, LZ3, LZ3); // Z3 = t1+Z3 + AFO.Mul(LX3, LZ3, LY3); // Y3 = X3*Z3 + AFO.Add(Lt0, Lt0, Lt1); // t1 = t0+t0 + AFO.Add(Lt1, Lt0, Lt1); // t1 = t1+t0 + AFO.MulByA(Lt2, Lt2); // t2 = a*t2 + AFO.MulByB3(Lt4, Lt4); // t4 = b3*t4 + AFO.Add(Lt1, Lt2, Lt1); // t1 = t1+t2 + AFO.Sub(Lt0, Lt2, Lt2); // t2 = t0-t2 + AFO.MulByA(Lt2, Lt2); // t2 = a*t2 + AFO.Add(Lt4, Lt2, Lt4); // t4 = t4+t2 + AFO.Mul(Lt1, Lt4, Lt0); // t0 = t1*t4 + AFO.Add(LY3, Lt0, LY3); // Y3 = Y3+t0 + AFO.Mul(Lt5, Lt4, Lt0); // t0 = t5*t4 + AFO.Mul(Lt3, LX3, LX3); // X3 = t3*X3 + AFO.Sub(LX3, Lt0, LX3); // X3 = X3-t0 + AFO.Mul(Lt3, Lt1, Lt0); // t0 = t3*t1 + AFO.Mul(Lt5, LZ3, LZ3); // Z3 = t5*Z3 + AFO.Add(LZ3, Lt0, LZ3); // Z3 = Z3+t0 + + Result.X := LX3; Result.Y := LY3; Result.Z := LZ3; +end; + +class function TCTHomogeneousMath.Double(const AFO: IFpFieldOps; + const AP: TCTHomogPoint): TCTHomogPoint; +var + LN: Int32; + Lt0, Lt1, Lt2, Lt3, LX3, LY3, LZ3: TCryptoLibUInt32Array; + LX, LY, LZ: TCryptoLibUInt32Array; +begin + LN := AFO.GetFieldInts; + LX := AP.X; LY := AP.Y; LZ := AP.Z; + + Lt0 := TNat.Create(LN); Lt1 := TNat.Create(LN); Lt2 := TNat.Create(LN); + Lt3 := TNat.Create(LN); + LX3 := TNat.Create(LN); LY3 := TNat.Create(LN); LZ3 := TNat.Create(LN); + + // RCB2016 complete doubling (Algorithm 3), explicit a and b3 = 3b + AFO.Square(LX, Lt0); // t0 = X*X + AFO.Square(LY, Lt1); // t1 = Y*Y + AFO.Square(LZ, Lt2); // t2 = Z*Z + AFO.Mul(LX, LY, Lt3); // t3 = X*Y + AFO.Add(Lt3, Lt3, Lt3); // t3 = t3+t3 + AFO.Mul(LX, LZ, LZ3); // Z3 = X*Z + AFO.Add(LZ3, LZ3, LZ3); // Z3 = Z3+Z3 + AFO.MulByA(LZ3, LX3); // X3 = a*Z3 + AFO.MulByB3(Lt2, LY3); // Y3 = b3*t2 + AFO.Add(LX3, LY3, LY3); // Y3 = X3+Y3 + AFO.Sub(Lt1, LY3, LX3); // X3 = t1-Y3 + AFO.Add(Lt1, LY3, LY3); // Y3 = t1+Y3 + AFO.Mul(LX3, LY3, LY3); // Y3 = X3*Y3 + AFO.Mul(Lt3, LX3, LX3); // X3 = t3*X3 + AFO.MulByB3(LZ3, LZ3); // Z3 = b3*Z3 + AFO.MulByA(Lt2, Lt2); // t2 = a*t2 + AFO.Sub(Lt0, Lt2, Lt3); // t3 = t0-t2 + AFO.MulByA(Lt3, Lt3); // t3 = a*t3 + AFO.Add(Lt3, LZ3, Lt3); // t3 = t3+Z3 + AFO.Add(Lt0, Lt0, LZ3); // Z3 = t0+t0 + AFO.Add(LZ3, Lt0, Lt0); // t0 = Z3+t0 + AFO.Add(Lt0, Lt2, Lt0); // t0 = t0+t2 + AFO.Mul(Lt0, Lt3, Lt0); // t0 = t0*t3 + AFO.Add(LY3, Lt0, LY3); // Y3 = Y3+t0 + AFO.Mul(LY, LZ, Lt2); // t2 = Y*Z + AFO.Add(Lt2, Lt2, Lt2); // t2 = t2+t2 + AFO.Mul(Lt2, Lt3, Lt0); // t0 = t2*t3 + AFO.Sub(LX3, Lt0, LX3); // X3 = X3-t0 + AFO.Mul(Lt2, Lt1, LZ3); // Z3 = t2*t1 + AFO.Add(LZ3, LZ3, LZ3); // Z3 = Z3+Z3 + AFO.Add(LZ3, LZ3, LZ3); // Z3 = Z3+Z3 + + Result.X := LX3; Result.Y := LY3; Result.Z := LZ3; +end; + +class procedure TCTHomogeneousMath.ToAffine(const AFO: IFpFieldOps; + const AP: TCTHomogPoint; out AX, AY: TCryptoLibUInt32Array; out AIsInfinity: Boolean); +var + LN: Int32; + LZInv: TCryptoLibUInt32Array; +begin + LN := AFO.GetFieldInts; + AIsInfinity := AFO.IsZero(AP.Z); + AX := TNat.Create(LN); + AY := TNat.Create(LN); + if AIsInfinity then + Exit; + LZInv := TNat.Create(LN); + AFO.Inv(AP.Z, LZInv); + AFO.Mul(AP.X, LZInv, AX); + AFO.Mul(AP.Y, LZInv, AY); +end; + +end. diff --git a/CryptoLib/src/Math/EC/Multiplier/ClpLopezDahabLadder.pas b/CryptoLib/src/Math/EC/Multiplier/ClpLopezDahabLadder.pas new file mode 100644 index 00000000..030d2308 --- /dev/null +++ b/CryptoLib/src/Math/EC/Multiplier/ClpLopezDahabLadder.pas @@ -0,0 +1,185 @@ +{ *********************************************************************************** } +{ * CryptoLib Library * } +{ * Author - Ugochukwu Mmaduekwe * } +{ * Github Repository * } +{ * * } +{ * 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 * } +{ * the development of this library * } +{ * ******************************************************************************* * } + +(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *) + +unit ClpLopezDahabLadder; + +{$I ..\..\..\Include\CryptoLib.inc} + +interface + +uses + ClpNat, + ClpIF2mFieldOps, + ClpCryptoLibTypes; + +type + /// + /// A point in López–Dahab x-only projective coordinates (X : Z), x = X/Z, + /// point at infinity = (X : 0) with X != 0. Value aggregate over the limb arrays. + /// + TLDPoint = record + X, Z: TCryptoLibUInt64Array; + end; + + /// + /// López–Dahab (1999) Montgomery-ladder x-only formulas over GF(2^m): + /// Mdouble, differential Madd, and Mxy y-recovery. See ClpLopezDahabLadder / + /// binary-ct plan for the exact formulas and the batched single-inversion + /// recovery. Exception-free through the infinity representation. + /// + TLopezDahabLadder = class sealed(TObject) + strict private + class procedure Sel(const AFO: IF2mFieldOps; AMask: UInt64; + const AIfTrue, AIfFalse, AZ: TCryptoLibUInt64Array); static; + public + // Mdouble: (X:Z) -> 2*(X:Z); Z' = X^2 Z^2, X' = X^4 + b Z^4 + class function MDouble(const AFO: IF2mFieldOps; const AP: TLDPoint): TLDPoint; static; + // Madd: differential add of (X1:Z1),(X2:Z2) whose difference is the base point x. + // Z' = (X1 Z2 + X2 Z1)^2, X' = x Z' + (X1 Z2)(X2 Z1) + class function MAdd(const AFO: IF2mFieldOps; const AP1, AP2: TLDPoint; + const ABaseX: TCryptoLibUInt64Array): TLDPoint; static; + // Recover affine (x_k) and lambda (lambda_k) of the result from the final + // ladder state (Q1 = x(kP), Q2 = x((k+1)P)) and the base affine (x, y). + // Returns infinity when Z1 = 0. Batched single secret-path inversion. + class procedure Recover(const AFO: IF2mFieldOps; const AP1, AP2: TLDPoint; + const ABaseX, ABaseY: TCryptoLibUInt64Array; + const AXOut, ALOut: TCryptoLibUInt64Array; out AIsInfinity: Boolean); static; + end; + +implementation + +{ TLopezDahabLadder } + +class procedure TLopezDahabLadder.Sel(const AFO: IF2mFieldOps; AMask: UInt64; + const AIfTrue, AIfFalse, AZ: TCryptoLibUInt64Array); +var + LN, LI: Int32; +begin + // constant-time: AZ := AMask ? AIfTrue : AIfFalse (AMask is 0 or all-ones) + LN := AFO.GetFieldLongs; + for LI := 0 to LN - 1 do + AZ[LI] := (AIfTrue[LI] and AMask) or (AIfFalse[LI] and (not AMask)); +end; + +class function TLopezDahabLadder.MDouble(const AFO: IF2mFieldOps; const AP: TLDPoint): TLDPoint; +var + LN: Int32; + Lt0, Lt1, LX3, LZ3: TCryptoLibUInt64Array; +begin + LN := AFO.GetFieldLongs; + Lt0 := TNat.Create64(LN); Lt1 := TNat.Create64(LN); + LX3 := TNat.Create64(LN); LZ3 := TNat.Create64(LN); + + AFO.Square(AP.X, Lt0); // t0 = X^2 + AFO.Square(AP.Z, Lt1); // t1 = Z^2 + AFO.Mul(Lt0, Lt1, LZ3); // Z3 = X^2 Z^2 + AFO.Square(Lt0, Lt0); // t0 = X^4 + AFO.Square(Lt1, Lt1); // t1 = Z^4 + AFO.MulByB(Lt1, Lt1); // t1 = b Z^4 + AFO.Add(Lt0, Lt1, LX3); // X3 = X^4 + b Z^4 + + Result.X := LX3; Result.Z := LZ3; +end; + +class function TLopezDahabLadder.MAdd(const AFO: IF2mFieldOps; const AP1, AP2: TLDPoint; + const ABaseX: TCryptoLibUInt64Array): TLDPoint; +var + LN: Int32; + LA, LB, LC, LD, LX3, LZ3: TCryptoLibUInt64Array; +begin + LN := AFO.GetFieldLongs; + LA := TNat.Create64(LN); LB := TNat.Create64(LN); LC := TNat.Create64(LN); + LD := TNat.Create64(LN); LX3 := TNat.Create64(LN); LZ3 := TNat.Create64(LN); + + AFO.Mul(AP1.X, AP2.Z, LA); // A = X1 Z2 + AFO.Mul(AP2.X, AP1.Z, LB); // B = X2 Z1 + AFO.Mul(LA, LB, LC); // C = A B + AFO.Add(LA, LB, LD); // D = A + B + AFO.Square(LD, LZ3); // Z3 = D^2 + AFO.Mul(ABaseX, LZ3, LX3); // X3 = x Z3 + AFO.Add(LX3, LC, LX3); // X3 = x Z3 + C + + Result.X := LX3; Result.Z := LZ3; +end; + +class procedure TLopezDahabLadder.Recover(const AFO: IF2mFieldOps; const AP1, AP2: TLDPoint; + const ABaseX, ABaseY: TCryptoLibUInt64Array; + const AXOut, ALOut: TCryptoLibUInt64Array; out AIsInfinity: Boolean); +var + LN: Int32; + LZ1Z2, LP1, LU, LUinv, LInvP1, LInvZ1, LInvX1, LTmp, LTmp2: TCryptoLibUInt64Array; + LxZ1, LxZ2, Lxk, Ls, Lt, LN2, Lx2y, Lfrac, Lyk, LinvXk, Llamk: TCryptoLibUInt64Array; + LInvX, LxNeg, LlamNeg: TCryptoLibUInt64Array; + LmaskZ2: UInt64; +begin + LN := AFO.GetFieldLongs; + AIsInfinity := AFO.IsZeroMask(AP1.Z) <> 0; + if AIsInfinity then + Exit; // kP = infinity (k == 0 mod ord P) - excluded for valid ECDH scalars + + LZ1Z2 := TNat.Create64(LN); LP1 := TNat.Create64(LN); LU := TNat.Create64(LN); + LUinv := TNat.Create64(LN); LInvP1 := TNat.Create64(LN); LInvZ1 := TNat.Create64(LN); + LInvX1 := TNat.Create64(LN); LTmp := TNat.Create64(LN); LTmp2 := TNat.Create64(LN); + LxZ1 := TNat.Create64(LN); LxZ2 := TNat.Create64(LN); Lxk := TNat.Create64(LN); + Ls := TNat.Create64(LN); Lt := TNat.Create64(LN); LN2 := TNat.Create64(LN); + Lx2y := TNat.Create64(LN); Lfrac := TNat.Create64(LN); Lyk := TNat.Create64(LN); + LinvXk := TNat.Create64(LN); Llamk := TNat.Create64(LN); + LInvX := TNat.Create64(LN); LxNeg := TNat.Create64(LN); LlamNeg := TNat.Create64(LN); + + // --- batched inversion: U = x*Z1*Z2*X1 (secret path, single guard-free inverse) --- + AFO.Mul(AP1.Z, AP2.Z, LZ1Z2); // Z1 Z2 + AFO.Mul(ABaseX, LZ1Z2, LP1); // P1 = x Z1 Z2 + AFO.Mul(LP1, AP1.X, LU); // U = P1 X1 + AFO.Inv(LU, LUinv); // 1/U (0 if U = 0; only in the Z2=0 edge, selected away) + AFO.Mul(AP1.X, LUinv, LInvP1); // 1/(x Z1 Z2) = X1/U + AFO.Mul(ABaseX, AP2.Z, LTmp); // x Z2 + AFO.Mul(LTmp, AP1.X, LTmp2); // x Z2 X1 + AFO.Mul(LTmp2, LUinv, LInvZ1); // 1/Z1 + AFO.Mul(LP1, LUinv, LInvX1); // 1/X1 + + // --- normal recovery --- + AFO.Mul(AP1.X, LInvZ1, Lxk); // x_k = X1/Z1 + AFO.Mul(ABaseX, AP1.Z, LxZ1); // x Z1 + AFO.Mul(ABaseX, AP2.Z, LxZ2); // x Z2 + AFO.Add(AP1.X, LxZ1, Ls); // s = X1 + x Z1 + AFO.Add(AP2.X, LxZ2, Lt); // t = X2 + x Z2 + AFO.Mul(Ls, Lt, LN2); // s t + AFO.Square(ABaseX, Lx2y); // x^2 + AFO.Add(Lx2y, ABaseY, Lx2y); // x^2 + y + AFO.Mul(Lx2y, LZ1Z2, LTmp); // (x^2+y) Z1 Z2 + AFO.Add(LN2, LTmp, LN2); // N = s t + (x^2+y) Z1 Z2 + AFO.Mul(LN2, LInvP1, Lfrac); // N / (x Z1 Z2) + AFO.Add(LxK, ABaseX, LTmp); // x_k + x + AFO.Mul(LTmp, Lfrac, Lyk); // (x_k+x) * frac + AFO.Add(Lyk, ABaseY, Lyk); // y_k = ... + y + AFO.Mul(AP1.Z, LInvX1, LinvXk); // 1/x_k = Z1/X1 + AFO.Mul(Lyk, LinvXk, Llamk); // y_k / x_k + AFO.Add(Llamk, LxK, Llamk); // lambda_k = y_k/x_k + x_k + + // --- -P candidate (public base; independent of the collapsed U) --- + AFO.Inv(ABaseX, LInvX); // 1/x (x is public, nonzero validated) + AFO.Add(ABaseX, ABaseY, LxNeg); // x + y (affine y of -P) + AFO.Mul(LxNeg, LInvX, LlamNeg); // (x+y)/x + AFO.Add(LlamNeg, ABaseX, LlamNeg); // lambda(-P) = (x+y)/x + x + // x-coordinate of -P is x itself; reuse ABaseX below. + + // --- CT select the Z2=0 edge (result = -P) --- + LmaskZ2 := AFO.IsZeroMask(AP2.Z); + Sel(AFO, LmaskZ2, ABaseX, LxK, AXOut); + Sel(AFO, LmaskZ2, LlamNeg, Llamk, ALOut); +end; + +end. diff --git a/CryptoLib/src/Math/Raw/ClpNat.pas b/CryptoLib/src/Math/Raw/ClpNat.pas index f388af56..cb2a9d90 100644 --- a/CryptoLib/src/Math/Raw/ClpNat.pas +++ b/CryptoLib/src/Math/Raw/ClpNat.pas @@ -64,6 +64,8 @@ TNat = class sealed class function CAdd(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; static; class function CAddTo(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt32Array; AZ: TCryptoLibUInt32Array): UInt32; static; class procedure CMov(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: TCryptoLibUInt32Array; AZOff: Int32); static; + class procedure CMov64(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); static; + class procedure CSwap64(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt64Array; const AZ: TCryptoLibUInt64Array); static; class function Compare(ALen: Int32; const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Int32; overload; static; class function Compare(ALen: Int32; const AX: TCryptoLibUInt32Array; AXOff: Int32; const AY: TCryptoLibUInt32Array; AYOff: Int32): Int32; overload; static; class function Copy(ALen: Int32; const AX: TCryptoLibUInt32Array): TCryptoLibUInt32Array; overload; static; @@ -623,6 +625,34 @@ class procedure TNat.CMov(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt32A end; end; +class procedure TNat.CMov64(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt64Array; AZ: TCryptoLibUInt64Array); +var + LMASK, LZI, LDiff: UInt64; + LI: Int32; +begin + LMASK := UInt64(-Int64(AMask and 1)); + for LI := 0 to ALen - 1 do + begin + LZI := AZ[LI]; + LDiff := LZI xor AX[LI]; + AZ[LI] := LZI xor (LDiff and LMASK); + end; +end; + +class procedure TNat.CSwap64(ALen: Int32; AMask: Int32; const AX: TCryptoLibUInt64Array; const AZ: TCryptoLibUInt64Array); +var + LMASK, LT: UInt64; + LI: Int32; +begin + LMASK := UInt64(-Int64(AMask and 1)); + for LI := 0 to ALen - 1 do + begin + LT := LMASK and (AX[LI] xor AZ[LI]); + AX[LI] := AX[LI] xor LT; + AZ[LI] := AZ[LI] xor LT; + end; +end; + class function TNat.Compare(ALen: Int32; const AX: TCryptoLibUInt32Array; const AY: TCryptoLibUInt32Array): Int32; var LI: Int32; @@ -672,12 +702,10 @@ class function TNat.Compare(ALen: Int32; const AX: TCryptoLibUInt32Array; AXOff: end; class function TNat.Copy(ALen: Int32; const AX: TCryptoLibUInt32Array): TCryptoLibUInt32Array; -var - LZ: TCryptoLibUInt32Array; begin - SetLength(LZ, ALen); - System.Move(AX[0], LZ[0], ALen * System.SizeOf(UInt32)); - Result := LZ; + Result := nil; + SetLength(Result, ALen); + System.Move(AX[0], Result[0], ALen * System.SizeOf(UInt32)); end; class procedure TNat.Copy(ALen: Int32; const AX: TCryptoLibUInt32Array; const AZ: TCryptoLibUInt32Array); @@ -691,12 +719,10 @@ class procedure TNat.Copy(ALen: Int32; const AX: TCryptoLibUInt32Array; AXOff: I end; class function TNat.Copy64(ALen: Int32; const AX: TCryptoLibUInt64Array): TCryptoLibUInt64Array; -var - LZ: TCryptoLibUInt64Array; begin - SetLength(LZ, ALen); - System.Move(AX[0], LZ[0], ALen * System.SizeOf(UInt64)); - Result := LZ; + Result := nil; + SetLength(Result, ALen); + System.Move(AX[0], Result[0], ALen * System.SizeOf(UInt64)); end; class procedure TNat.Copy64(ALen: Int32; const AX: TCryptoLibUInt64Array; const AZ: TCryptoLibUInt64Array); @@ -711,12 +737,14 @@ class procedure TNat.Copy64(ALen: Int32; const AX: TCryptoLibUInt64Array; AXOff: class function TNat.Create(ALen: Int32): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, ALen); Exit; end; class function TNat.Create64(ALen: Int32): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, ALen); Exit; end; @@ -1021,39 +1049,35 @@ class function TNat.EqualToZero64(ALen: Int32; const AX: TCryptoLibUInt64Array; class function TNat.FromBigInteger(ABits: Int32; AX: TBigInteger): TCryptoLibUInt32Array; var LLen: Int32; - LZ: TCryptoLibUInt32Array; LI: Int32; begin LLen := GetLengthForBits(ABits); - LZ := Create(LLen); + Result := Create(LLen); if ((AX.SignValue < 0) or (AX.BitLength > ABits)) then raise EArgumentCryptoLibException.CreateRes(@SValueOutOfRangeForBitLength); - LZ[0] := UInt32(AX.Int32Value); + Result[0] := UInt32(AX.Int32Value); for LI := 1 to LLen - 1 do begin AX := AX.ShiftRight(32); - LZ[LI] := UInt32(AX.Int32Value); + Result[LI] := UInt32(AX.Int32Value); end; - Result := LZ; end; class function TNat.FromBigInteger64(ABits: Int32; AX: TBigInteger): TCryptoLibUInt64Array; var LLen: Int32; - LZ: TCryptoLibUInt64Array; LI: Int32; begin LLen := GetLengthForBits64(ABits); - LZ := Create64(LLen); + Result := Create64(LLen); if ((AX.SignValue < 0) or (AX.BitLength > ABits)) then raise EArgumentCryptoLibException.CreateRes(@SValueOutOfRangeForBitLength); - LZ[0] := UInt64(AX.Int64Value); + Result[0] := UInt64(AX.Int64Value); for LI := 1 to LLen - 1 do begin AX := AX.ShiftRight(64); - LZ[LI] := UInt64(AX.Int64Value); + Result[LI] := UInt64(AX.Int64Value); end; - Result := LZ; end; class function TNat.GetBit(const AX: TCryptoLibUInt32Array; ABit: Int32): UInt32; diff --git a/CryptoLib/src/Math/Raw/ClpNat128.pas b/CryptoLib/src/Math/Raw/ClpNat128.pas index fb14bb63..af9a6d22 100644 --- a/CryptoLib/src/Math/Raw/ClpNat128.pas +++ b/CryptoLib/src/Math/Raw/ClpNat128.pas @@ -247,21 +247,25 @@ class procedure TNat128.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; co class function TNat128.Create: TCryptoLibUInt32Array; begin + Result := nil; System.SetLength(Result, 4); end; class function TNat128.Create64: TCryptoLibUInt64Array; begin + Result := nil; System.SetLength(Result, 2); end; class function TNat128.CreateExt: TCryptoLibUInt32Array; begin + Result := nil; System.SetLength(Result, 8); end; class function TNat128.CreateExt64: TCryptoLibUInt64Array; begin + Result := nil; System.SetLength(Result, 4); end; diff --git a/CryptoLib/src/Math/Raw/ClpNat160.pas b/CryptoLib/src/Math/Raw/ClpNat160.pas index 4b77a9b3..dfd209c7 100644 --- a/CryptoLib/src/Math/Raw/ClpNat160.pas +++ b/CryptoLib/src/Math/Raw/ClpNat160.pas @@ -243,11 +243,13 @@ class procedure TNat160.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; cons class function TNat160.Create: TCryptoLibUInt32Array; begin + Result := nil; System.SetLength(Result, 5); end; class function TNat160.CreateExt: TCryptoLibUInt32Array; begin + Result := nil; System.SetLength(Result, 10); end; diff --git a/CryptoLib/src/Math/Raw/ClpNat192.pas b/CryptoLib/src/Math/Raw/ClpNat192.pas index 3bd2e8e1..600f638b 100644 --- a/CryptoLib/src/Math/Raw/ClpNat192.pas +++ b/CryptoLib/src/Math/Raw/ClpNat192.pas @@ -238,24 +238,28 @@ class procedure TNat192.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ class function TNat192.Create(): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, 6); Exit; end; class function TNat192.Create64(): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, 3); Exit; end; class function TNat192.CreateExt(): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, 12); Exit; end; class function TNat192.CreateExt64(): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, 6); Exit; end; diff --git a/CryptoLib/src/Math/Raw/ClpNat224.pas b/CryptoLib/src/Math/Raw/ClpNat224.pas index 2f4c053f..2439b327 100644 --- a/CryptoLib/src/Math/Raw/ClpNat224.pas +++ b/CryptoLib/src/Math/Raw/ClpNat224.pas @@ -299,12 +299,14 @@ class procedure TNat224.Copy(const AX: TCryptoLibUInt32Array; AXOff: Int32; AZ: class function TNat224.Create(): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, 7); Exit; end; class function TNat224.CreateExt(): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, 14); Exit; end; diff --git a/CryptoLib/src/Math/Raw/ClpNat256.pas b/CryptoLib/src/Math/Raw/ClpNat256.pas index e35ef204..32266667 100644 --- a/CryptoLib/src/Math/Raw/ClpNat256.pas +++ b/CryptoLib/src/Math/Raw/ClpNat256.pas @@ -363,24 +363,28 @@ class procedure TNat256.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ class function TNat256.Create(): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, 8); Exit; end; class function TNat256.Create64(): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, 4); Exit; end; class function TNat256.CreateExt(): TCryptoLibUInt32Array; begin + Result := nil; SetLength(Result, 16); Exit; end; class function TNat256.CreateExt64(): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, 8); Exit; end; diff --git a/CryptoLib/src/Math/Raw/ClpNat320.pas b/CryptoLib/src/Math/Raw/ClpNat320.pas index c9af6c5e..a2269ee5 100644 --- a/CryptoLib/src/Math/Raw/ClpNat320.pas +++ b/CryptoLib/src/Math/Raw/ClpNat320.pas @@ -54,12 +54,14 @@ class procedure TNat320.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ class function TNat320.Create64(): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, 5); Exit; end; class function TNat320.CreateExt64(): TCryptoLibUInt64Array; begin + Result := nil; SetLength(Result, 10); Exit; end; diff --git a/CryptoLib/src/Math/Raw/ClpNat448.pas b/CryptoLib/src/Math/Raw/ClpNat448.pas index abc8a251..8358ac5e 100644 --- a/CryptoLib/src/Math/Raw/ClpNat448.pas +++ b/CryptoLib/src/Math/Raw/ClpNat448.pas @@ -65,11 +65,13 @@ class procedure TNat448.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ class function TNat448.Create64(): TCryptoLibUInt64Array; begin + Result := nil; System.SetLength(Result, 7); end; class function TNat448.CreateExt64(): TCryptoLibUInt64Array; begin + Result := nil; System.SetLength(Result, 14); end; diff --git a/CryptoLib/src/Math/Raw/ClpNat576.pas b/CryptoLib/src/Math/Raw/ClpNat576.pas index f6d9bf56..33b14ffb 100644 --- a/CryptoLib/src/Math/Raw/ClpNat576.pas +++ b/CryptoLib/src/Math/Raw/ClpNat576.pas @@ -55,11 +55,13 @@ class procedure TNat576.Copy64(const AX: TCryptoLibUInt64Array; AXOff: Int32; AZ class function TNat576.Create64(): TCryptoLibUInt64Array; begin + Result := nil; System.SetLength(Result, 9); end; class function TNat576.CreateExt64(): TCryptoLibUInt64Array; begin + Result := nil; System.SetLength(Result, 18); end; diff --git a/CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk b/CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk index 6c86f34d..b706a18e 100644 --- a/CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk +++ b/CryptoLib/src/Packages/Delphi/CryptoLib4PascalPackage.dpk @@ -397,6 +397,12 @@ contains ClpMacUtilities in '..\..\Crypto\Macs\ClpMacUtilities.pas', ClpMiscObjectIdentifiers in '..\..\Asn1\Misc\ClpMiscObjectIdentifiers.pas', ClpMultipliers in '..\..\Math\EC\Multiplier\ClpMultipliers.pas', + ClpIFpFieldOps in '..\..\Interfaces\Math\EC\Multiplier\ClpIFpFieldOps.pas', + ClpHomogeneousPoint in '..\..\Math\EC\Multiplier\ClpHomogeneousPoint.pas', + ClpFixedWindowCTMultiplier in '..\..\Math\EC\Multiplier\ClpFixedWindowCTMultiplier.pas', + ClpIF2mFieldOps in '..\..\Interfaces\Math\EC\Multiplier\ClpIF2mFieldOps.pas', + ClpLopezDahabLadder in '..\..\Math\EC\Multiplier\ClpLopezDahabLadder.pas', + ClpF2mMontgomeryLadderCTMultiplier in '..\..\Math\EC\Multiplier\ClpF2mMontgomeryLadderCTMultiplier.pas', ClpNistNamedCurves in '..\..\Asn1\Nist\ClpNistNamedCurves.pas', ClpNistObjectIdentifiers in '..\..\Asn1\Nist\ClpNistObjectIdentifiers.pas', ClpNoOpDigest in '..\..\Crypto\Digests\ClpNoOpDigest.pas', diff --git a/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk b/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk index 412629ed..e6c05270 100644 --- a/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk +++ b/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.lpk @@ -31,7 +31,7 @@ Acknowledgements: Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the development of this library "/> - + @@ -3465,6 +3465,30 @@ Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring the devel + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas b/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas index cbbff24f..7ed5edb3 100644 --- a/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas +++ b/CryptoLib/src/Packages/FPC/CryptoLib4PascalPackage.pas @@ -279,7 +279,9 @@ interface ClpPkixCrlRevocationChecker, ClpPkixRevocationChecker, ClpPkixAttrCertChecker, ClpRfc3281CertPathUtilities, ClpPkixAttrCertPathValidator, ClpPkixAttrCertPathBuilder, - ClpCryptoLibExceptions, ClpAesBitSlicedEngine; + ClpCryptoLibExceptions, ClpAesBitSlicedEngine, ClpHomogeneousPoint, + ClpFixedWindowCTMultiplier, ClpIFpFieldOps, ClpIF2mFieldOps, + ClpLopezDahabLadder, ClpF2mMontgomeryLadderCTMultiplier; implementation