Ugochukwu Mmaduekwe 1 неделя назад
Родитель
Сommit
bea0fe5212
27 измененных файлов с 5700 добавлено и 5406 удалено
  1. 6 5
      CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr
  2. 630 319
      CryptoLib.Tests/src/Math/EC/Rfc8032/Ed25519Tests.pas
  3. 859 250
      CryptoLib.Tests/src/Others/Ed25519HigherLevelTests.pas
  4. 0 53
      CryptoLib/src/Crypto/EC/ClpCustomNamedCurves.pas
  5. 10 13
      CryptoLib/src/Crypto/Generators/ClpEd25519KeyPairGenerator.pas
  6. 1 3
      CryptoLib/src/Crypto/Generators/ClpGeneratorUtilities.pas
  7. 100 98
      CryptoLib/src/Crypto/Parameters/ClpEd25519PrivateKeyParameters.pas
  8. 114 28
      CryptoLib/src/Crypto/Parameters/ClpEd25519PublicKeyParameters.pas
  9. 30 14
      CryptoLib/src/Crypto/Parameters/ClpX25519PrivateKeyParameters.pas
  10. 27 12
      CryptoLib/src/Crypto/Parameters/ClpX25519PublicKeyParameters.pas
  11. 147 51
      CryptoLib/src/Crypto/Signers/ClpEd25519CtxSigner.pas
  12. 17 16
      CryptoLib/src/Crypto/Signers/ClpEd25519PhSigner.pas
  13. 140 49
      CryptoLib/src/Crypto/Signers/ClpEd25519Signer.pas
  14. 46 2
      CryptoLib/src/GeneralUtilities/ClpStringUtilities.pas
  15. 3 4
      CryptoLib/src/Interfaces/Crypto/Parameters/ClpIEd25519PrivateKeyParameters.pas
  16. 7 2
      CryptoLib/src/Interfaces/Crypto/Parameters/ClpIEd25519PublicKeyParameters.pas
  17. 0 64
      CryptoLib/src/Interfaces/Math/EC/Custom/Djb/ClpICurve25519Custom.pas
  18. 0 100
      CryptoLib/src/Interfaces/Math/EC/Rfc8032/ClpIEd25519.pas
  19. 0 1408
      CryptoLib/src/Math/EC/Custom/Djb/ClpCurve25519Custom.pas
  20. 147 169
      CryptoLib/src/Math/EC/Rfc7748/ClpX25519.pas
  21. 820 781
      CryptoLib/src/Math/EC/Rfc7748/ClpX25519Field.pas
  22. 140 0
      CryptoLib/src/Math/EC/Rfc8032/ClpCodec.pas
  23. 1473 1960
      CryptoLib/src/Math/EC/Rfc8032/ClpEd25519.pas
  24. 453 0
      CryptoLib/src/Math/EC/Rfc8032/ClpScalar25519.pas
  25. 426 0
      CryptoLib/src/Math/EC/Rfc8032/ClpScalarUtilities.pas
  26. 99 0
      CryptoLib/src/Math/EC/Rfc8032/ClpWnaf.pas
  27. 5 5
      CryptoLib/src/Math/Raw/ClpNat.pas

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

@@ -55,6 +55,7 @@ uses
   ClpBufferedStreamCipher in '..\..\CryptoLib\src\Crypto\Ciphers\ClpBufferedStreamCipher.pas',
   ClpChaChaEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpChaChaEngine.pas',
   ClpCheck in '..\..\CryptoLib\src\Crypto\ClpCheck.pas',
+  ClpCodec in '..\..\CryptoLib\src\Math\EC\Rfc8032\ClpCodec.pas',
   ClpCipherKeyGenerator in '..\..\CryptoLib\src\Crypto\Generators\ClpCipherKeyGenerator.pas',
   ClpCipherUtilities in '..\..\CryptoLib\src\Crypto\Ciphers\ClpCipherUtilities.pas',
   ClpCollectionUtilities in '..\..\CryptoLib\src\GeneralUtilities\ClpCollectionUtilities.pas',
@@ -64,7 +65,6 @@ uses
   ClpCryptoLibComparers in '..\..\CryptoLib\src\GeneralUtilities\ClpCryptoLibComparers.pas',
   ClpCryptoLibTypes in '..\..\CryptoLib\src\GeneralUtilities\ClpCryptoLibTypes.pas',
   ClpCryptoProObjectIdentifiers in '..\..\CryptoLib\src\Asn1\CryptoPro\ClpCryptoProObjectIdentifiers.pas',
-  ClpCurve25519Custom in '..\..\CryptoLib\src\Math\EC\Custom\Djb\ClpCurve25519Custom.pas',
   ClpCustomNamedCurves in '..\..\CryptoLib\src\Crypto\EC\ClpCustomNamedCurves.pas',
   ClpECUtilities in '..\..\CryptoLib\src\Crypto\EC\ClpECUtilities.pas',
   ClpDateTimeUtilities in '..\..\CryptoLib\src\GeneralUtilities\ClpDateTimeUtilities.pas',
@@ -175,7 +175,6 @@ uses
   ClpICipherKeyGenerator in '..\..\CryptoLib\src\Interfaces\Crypto\Generators\ClpICipherKeyGenerator.pas',
   ClpICipherParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpICipherParameters.pas',
   ClpICryptoApiRandomGenerator in '..\..\CryptoLib\src\Interfaces\Rngs\ClpICryptoApiRandomGenerator.pas',
-  ClpICurve25519Custom in '..\..\CryptoLib\src\Interfaces\Math\EC\Custom\Djb\ClpICurve25519Custom.pas',
   ClpIDerivationFunction in '..\..\CryptoLib\src\Interfaces\Crypto\ClpIDerivationFunction.pas',
   ClpIDerivationParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpIDerivationParameters.pas',
   ClpIDHAgreement in '..\..\CryptoLib\src\Interfaces\Crypto\Agreements\ClpIDHAgreement.pas',
@@ -219,7 +218,6 @@ uses
   ClpIECNRSigner in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\ClpIECNRSigner.pas',
   ClpIECPrivateKeyParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpIECPrivateKeyParameters.pas',
   ClpIECPublicKeyParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpIECPublicKeyParameters.pas',
-  ClpIEd25519 in '..\..\CryptoLib\src\Interfaces\Math\EC\Rfc8032\ClpIEd25519.pas',
   ClpIEd25519CtxSigner in '..\..\CryptoLib\src\Interfaces\Crypto\Signers\ClpIEd25519CtxSigner.pas',
   ClpIEd25519KeyGenerationParameters in '..\..\CryptoLib\src\Interfaces\Crypto\Parameters\ClpIEd25519KeyGenerationParameters.pas',
   ClpIEd25519KeyPairGenerator in '..\..\CryptoLib\src\Interfaces\Crypto\Generators\ClpIEd25519KeyPairGenerator.pas',
@@ -421,6 +419,8 @@ uses
   ClpWeakRef in '..\..\CryptoLib\src\GeneralUtilities\ClpWeakRef.pas',
   ClpSignersEncodings in '..\..\CryptoLib\src\Crypto\Signers\SignerEncodings\ClpSignersEncodings.pas',
   ClpSignerSink in '..\..\CryptoLib\src\Crypto\IO\ClpSignerSink.pas',
+  ClpScalar25519 in '..\..\CryptoLib\src\Math\EC\Rfc8032\ClpScalar25519.pas',
+  ClpScalarUtilities in '..\..\CryptoLib\src\Math\EC\Rfc8032\ClpScalarUtilities.pas',
   ClpSignerUtilities in '..\..\CryptoLib\src\Crypto\Signers\ClpSignerUtilities.pas',
   ClpSimpleBigDecimal in '..\..\CryptoLib\src\Math\EC\Abc\ClpSimpleBigDecimal.pas',
   ClpSpeckEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpSpeckEngine.pas',
@@ -435,6 +435,7 @@ uses
   ClpValidityPreCompInfo in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpValidityPreCompInfo.pas',
   ClpWNafPreCompInfo in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpWNafPreCompInfo.pas',
   ClpWTauNafPreCompInfo in '..\..\CryptoLib\src\Math\EC\Multiplier\ClpWTauNafPreCompInfo.pas',
+  ClpWnaf in '..\..\CryptoLib\src\Math\EC\Rfc8032\ClpWnaf.pas',
   ClpX25519 in '..\..\CryptoLib\src\Math\EC\Rfc7748\ClpX25519.pas',
   ClpX25519Agreement in '..\..\CryptoLib\src\Crypto\Agreements\ClpX25519Agreement.pas',
   ClpX25519Field in '..\..\CryptoLib\src\Math\EC\Rfc7748\ClpX25519Field.pas',
@@ -556,7 +557,6 @@ uses
   DigestTests in '..\src\Others\DigestTests.pas',
   ECDsa5Tests in '..\src\Others\ECDsa5Tests.pas',
   ECTests in '..\src\Others\ECTests.pas',
-  Ed25519HigherLevelTests in '..\src\Others\Ed25519HigherLevelTests.pas',
   NamedCurveTests in '..\src\Others\NamedCurveTests.pas',
   ShortenedDigestTests in '..\src\Others\ShortenedDigestTests.pas',
   SignerUtilitiesTests in '..\src\Others\SignerUtilitiesTests.pas',
@@ -592,7 +592,6 @@ uses
   CTSTests in '..\src\Crypto\CTSTests.pas',
   PascalCoinECIESTests in '..\src\Math\PascalCoinECIESTests.pas',
   X25519Tests in '..\src\Math\EC\Rfc7748\X25519Tests.pas',
-  Ed25519Tests in '..\src\Math\EC\Rfc8032\Ed25519Tests.pas',
   Kdf1GeneratorTests in '..\src\Crypto\Kdf1GeneratorTests.pas',
   Kdf2GeneratorTests in '..\src\Crypto\Kdf2GeneratorTests.pas',
   Argon2Tests in '..\src\Crypto\Argon2Tests.pas',
@@ -618,6 +617,8 @@ uses
   X509NameTests in '..\src\Asn1\X509\X509NameTests.pas',
   Pkcs10CertRequestTests in '..\src\Asn1\Pkcs\Pkcs10CertRequestTests.pas',
   DeltaCertificateTests in '..\src\Asn1\X509\DeltaCertificateTests.pas',
+  Ed25519HigherLevelTests in '..\src\Others\Ed25519HigherLevelTests.pas',
+  Ed25519Tests in '..\src\Math\EC\Rfc8032\Ed25519Tests.pas',
   CryptoLibTestBase in '..\src\CryptoLibTestBase.pas';
 
 begin

+ 630 - 319
CryptoLib.Tests/src/Math/EC/Rfc8032/Ed25519Tests.pas

@@ -31,26 +31,29 @@ uses
 {$ELSE}
   TestFramework,
 {$ENDIF FPC}
-  ClpEd25519,
-  ClpIEd25519,
   ClpIDigest,
+  ClpEd25519,
   ClpSecureRandom,
   ClpISecureRandom,
+  ClpEncoders,
+  ClpArrayUtilities,
+  ClpConverters,
+  ClpCryptoLibTypes,
   CryptoLibTestBase;
 
 type
 
   TTestEd25519 = class(TCryptoLibAlgorithmTestCase)
-
   private
-
   var
     FRandom: ISecureRandom;
-    procedure CheckEd25519Vector(const sSK, sPK, sM, sSig, text: String);
-    procedure CheckEd25519ctxVector(const sSK, sPK, sM, sCTX, sSig,
-      text: String);
-    procedure CheckEd25519phVector(const sSK, sPK, sM, sCTX, sSig,
-      text: String);
+    FEd25519: TEd25519;
+
+    procedure CheckEd25519Vector(const ASK, APK, AM, ASig, AText: String);
+    procedure CheckEd25519ctxVector(const ASK, APK, AM, ACTX, ASig, AText: String);
+    procedure CheckEd25519phVector(const ASK, APK, AM, ACTX, ASig, AText: String);
+    procedure ImplTamingVector(ANumber: Int32; AExpected: Boolean; const AMsgHex, APubHex, ASigHex: String); overload;
+    function ImplTamingVector(const AMsgHex, APubHex, ASigHex: String): Boolean; overload;
   protected
     procedure SetUp; override;
     procedure TearDown; override;
@@ -62,6 +65,7 @@ type
     procedure TestEd25519Vector2();
     procedure TestEd25519Vector3();
     procedure TestEd25519Vector1023();
+
     procedure TestEd25519VectorSHAabc();
     procedure TestEd25519ctxVector1();
     procedure TestEd25519ctxVector2();
@@ -69,465 +73,772 @@ type
     procedure TestEd25519ctxVector4();
     procedure TestEd25519phVector1();
 
+    procedure TestPublicKeyValidationFull();
+    procedure TestPublicKeyValidationPartial();
+    procedure TamingNonRepudiation();
+    procedure TamingVector_00();
+    procedure TamingVector_01();
+    procedure TamingVector_02();
+    procedure TamingVector_03();
+    procedure TamingVector_04();
+    procedure TamingVector_05();
+    procedure TamingVector_06();
+    procedure TamingVector_07();
+    procedure TamingVector_08();
+    procedure TamingVector_09();
+    procedure TamingVector_10();
+    procedure TamingVector_11();
   end;
 
 implementation
 
 { TTestEd25519 }
 
-procedure TTestEd25519.CheckEd25519Vector(const sSK, sPK, sM, sSig,
-  text: String);
+procedure TTestEd25519.CheckEd25519Vector(const ASK, APK, AM, ASig, AText: String);
 var
-  sk, pk, pkGen, m, sig, badsig, sigGen: TBytes;
-  Ed25519Instance: IEd25519;
-  shouldVerify, shouldNotVerify: Boolean;
+  LSk, LPk, LM, LSig, LPkGen, LBadSig, LSigGen: TBytes;
+  LShouldVerify, LShouldNotVerify: Boolean;
 begin
-  sk := DecodeHex(sSK);
-  pk := DecodeHex(sPK);
-
-  System.SetLength(pkGen, TEd25519.PublicKeySize);
+  LSk := DecodeHex(ASK);
+  LPk := DecodeHex(APK);
 
-  Ed25519Instance := TEd25519.Create();
-  Ed25519Instance.GeneratePublicKey(sk, 0, pkGen, 0);
-  CheckTrue(AreEqual(pk, pkGen), text);
+  System.SetLength(LPkGen, TEd25519.PublicKeySize);
+  FEd25519.GeneratePublicKey(LSk, 0, LPkGen, 0);
+  CheckTrue(AreEqual(LPk, LPkGen), AText);
 
-  m := DecodeHex(sM);
-  sig := DecodeHex(sSig);
+  LM := DecodeHex(AM);
+  LSig := DecodeHex(ASig);
 
-  badsig := System.Copy(sig);
+  LBadSig := System.Copy(LSig);
+  LBadSig[TEd25519.SignatureSize - 1] := Byte(LBadSig[TEd25519.SignatureSize - 1]
+    xor $80);
 
-  badsig[TEd25519.PublicKeySize - 1] :=
-    badsig[TEd25519.SignatureSize - 1] xor $80;
+  System.SetLength(LSigGen, TEd25519.SignatureSize);
+  FEd25519.Sign(LSk, 0, LM, 0, System.Length(LM), LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  System.SetLength(sigGen, TEd25519.SignatureSize);
+  FEd25519.Sign(LSk, 0, LPk, 0, LM, 0, System.Length(LM), LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  Ed25519Instance.Sign(sk, 0, m, 0, System.Length(m), sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
+  LShouldVerify := FEd25519.Verify(LSig, 0, LPk, 0, LM, 0, System.Length(LM));
+  CheckTrue(LShouldVerify, AText);
 
-  Ed25519Instance.Sign(sk, 0, pk, 0, m, 0, System.Length(m), sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
-
-  shouldVerify := Ed25519Instance.Verify(sig, 0, pk, 0, m, 0, System.Length(m));
-  CheckTrue(shouldVerify, text);
-
-  shouldNotVerify := Ed25519Instance.Verify(badsig, 0, pk, 0, m, 0,
-    System.Length(m));
-  CheckFalse(shouldNotVerify, text);
+  LShouldNotVerify := FEd25519.Verify(LBadSig, 0, LPk, 0, LM, 0, System.Length(LM));
+  CheckFalse(LShouldNotVerify, AText);
 end;
 
-procedure TTestEd25519.CheckEd25519ctxVector(const sSK, sPK, sM, sCTX, sSig,
-  text: String);
+procedure TTestEd25519.CheckEd25519ctxVector(const ASK, APK, AM, ACTX, ASig,
+  AText: String);
 var
-  sk, pk, pkGen, m, ctx, sig, badsig, sigGen: TBytes;
-  Ed25519Instance: IEd25519;
-  shouldVerify, shouldNotVerify: Boolean;
+  LSk, LPk, LM, LCtx, LSig, LPkGen, LBadSig, LSigGen: TBytes;
+  LShouldVerify, LShouldNotVerify: Boolean;
 begin
-  sk := DecodeHex(sSK);
-  pk := DecodeHex(sPK);
-
-  System.SetLength(pkGen, TEd25519.PublicKeySize);
+  LSk := DecodeHex(ASK);
+  LPk := DecodeHex(APK);
 
-  Ed25519Instance := TEd25519.Create();
-  Ed25519Instance.GeneratePublicKey(sk, 0, pkGen, 0);
-  CheckTrue(AreEqual(pk, pkGen), text);
+  System.SetLength(LPkGen, TEd25519.PublicKeySize);
+  FEd25519.GeneratePublicKey(LSk, 0, LPkGen, 0);
+  CheckTrue(AreEqual(LPk, LPkGen), AText);
 
-  m := DecodeHex(sM);
-  ctx := DecodeHex(sCTX);
-  sig := DecodeHex(sSig);
+  LM := DecodeHex(AM);
+  LCtx := DecodeHex(ACTX);
+  LSig := DecodeHex(ASig);
 
-  badsig := System.Copy(sig);
+  LBadSig := System.Copy(LSig);
+  LBadSig[TEd25519.SignatureSize - 1] := Byte(LBadSig[TEd25519.SignatureSize - 1]
+    xor $80);
 
-  badsig[TEd25519.PublicKeySize - 1] :=
-    badsig[TEd25519.SignatureSize - 1] xor $80;
+  System.SetLength(LSigGen, TEd25519.SignatureSize);
+  FEd25519.Sign(LSk, 0, LCtx, LM, 0, System.Length(LM), LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  System.SetLength(sigGen, TEd25519.SignatureSize);
+  FEd25519.Sign(LSk, 0, LPk, 0, LCtx, LM, 0, System.Length(LM), LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  Ed25519Instance.Sign(sk, 0, ctx, m, 0, System.Length(m), sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
+  LShouldVerify := FEd25519.Verify(LSig, 0, LPk, 0, LCtx, LM, 0, System.Length(LM));
+  CheckTrue(LShouldVerify, AText);
 
-  Ed25519Instance.Sign(sk, 0, pk, 0, ctx, m, 0, System.Length(m), sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
-
-  shouldVerify := Ed25519Instance.Verify(sig, 0, pk, 0, ctx, m, 0,
-    System.Length(m));
-  CheckTrue(shouldVerify, text);
-
-  shouldNotVerify := Ed25519Instance.Verify(badsig, 0, pk, 0, ctx, m, 0,
-    System.Length(m));
-  CheckFalse(shouldNotVerify, text);
+  LShouldNotVerify := FEd25519.Verify(LBadSig, 0, LPk, 0, LCtx, LM, 0,
+    System.Length(LM));
+  CheckFalse(LShouldNotVerify, AText);
 end;
 
-procedure TTestEd25519.CheckEd25519phVector(const sSK, sPK, sM, sCTX, sSig,
-  text: String);
+procedure TTestEd25519.CheckEd25519phVector(const ASK, APK, AM, ACTX, ASig,
+  AText: String);
 var
-  sk, pk, pkGen, m, ph, ctx, sig, badsig, sigGen: TBytes;
-  Ed25519Instance: IEd25519;
-  shouldVerify, shouldNotVerify: Boolean;
-  prehash: IDigest;
+  LSk, LPk, LM, LCtx, LPh, LSig, LPkGen, LBadSig, LSigGen: TBytes;
+  LPrehash: IDigest;
+  LShouldVerify, LShouldNotVerify: Boolean;
 begin
-  sk := DecodeHex(sSK);
-  pk := DecodeHex(sPK);
-
-  System.SetLength(pkGen, TEd25519.PublicKeySize);
+  LSk := DecodeHex(ASK);
+  LPk := DecodeHex(APK);
 
-  Ed25519Instance := TEd25519.Create();
-  Ed25519Instance.GeneratePublicKey(sk, 0, pkGen, 0);
-  CheckTrue(AreEqual(pk, pkGen), text);
+  System.SetLength(LPkGen, TEd25519.PublicKeySize);
+  FEd25519.GeneratePublicKey(LSk, 0, LPkGen, 0);
+  CheckTrue(AreEqual(LPk, LPkGen), AText);
 
-  m := DecodeHex(sM);
-  ctx := DecodeHex(sCTX);
-  sig := DecodeHex(sSig);
+  LM := DecodeHex(AM);
+  LCtx := DecodeHex(ACTX);
+  LSig := DecodeHex(ASig);
 
-  badsig := System.Copy(sig);
+  LBadSig := System.Copy(LSig);
+  LBadSig[TEd25519.SignatureSize - 1] := Byte(LBadSig[TEd25519.SignatureSize - 1]
+    xor $80);
 
-  badsig[TEd25519.PublicKeySize - 1] :=
-    badsig[TEd25519.SignatureSize - 1] xor $80;
+  System.SetLength(LSigGen, TEd25519.SignatureSize);
 
-  System.SetLength(sigGen, TEd25519.SignatureSize);
+  LPrehash := TEd25519.CreatePreHash();
+  LPrehash.BlockUpdate(LM, 0, System.Length(LM));
+  System.SetLength(LPh, TEd25519.PrehashSize);
+  LPrehash.DoFinal(LPh, 0);
 
-  prehash := Ed25519Instance.CreatePreHash();
-  prehash.BlockUpdate(m, 0, System.Length(m));
+  FEd25519.SignPreHash(LSk, 0, LCtx, LPh, 0, LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  System.SetLength(ph, TEd25519.PreHashSize);
+  FEd25519.SignPreHash(LSk, 0, LPk, 0, LCtx, LPh, 0, LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  prehash.DoFinal(ph, 0);
+  LShouldVerify := FEd25519.VerifyPreHash(LSig, 0, LPk, 0, LCtx, LPh, 0);
+  CheckTrue(LShouldVerify, AText);
 
-  Ed25519Instance.SignPreHash(sk, 0, ctx, ph, 0, sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
+  LShouldNotVerify := FEd25519.VerifyPreHash(LBadSig, 0, LPk, 0, LCtx, LPh, 0);
+  CheckFalse(LShouldNotVerify, AText);
 
-  Ed25519Instance.SignPreHash(sk, 0, pk, 0, ctx, ph, 0, sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
+  LPrehash := TEd25519.CreatePreHash();
+  LPrehash.BlockUpdate(LM, 0, System.Length(LM));
+  FEd25519.SignPreHash(LSk, 0, LCtx, LPrehash, LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  shouldVerify := Ed25519Instance.VerifyPreHash(sig, 0, pk, 0, ctx, ph, 0);
-  CheckTrue(shouldVerify, text);
+  LPrehash := TEd25519.CreatePreHash();
+  LPrehash.BlockUpdate(LM, 0, System.Length(LM));
+  FEd25519.SignPreHash(LSk, 0, LPk, 0, LCtx, LPrehash, LSigGen, 0);
+  CheckTrue(AreEqual(LSig, LSigGen), AText);
 
-  shouldNotVerify := Ed25519Instance.VerifyPreHash(badsig, 0, pk, 0,
-    ctx, ph, 0);
-  CheckFalse(shouldNotVerify, text);
+  LPrehash := TEd25519.CreatePreHash();
+  LPrehash.BlockUpdate(LM, 0, System.Length(LM));
+  LShouldVerify := FEd25519.VerifyPreHash(LSig, 0, LPk, 0, LCtx, LPrehash);
+  CheckTrue(LShouldVerify, AText);
 
-  prehash := Ed25519Instance.CreatePreHash();
-  prehash.BlockUpdate(m, 0, System.Length(m));
-
-  Ed25519Instance.SignPreHash(sk, 0, ctx, prehash, sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
-
-  prehash := Ed25519Instance.CreatePreHash();
-  prehash.BlockUpdate(m, 0, System.Length(m));
-
-  Ed25519Instance.SignPreHash(sk, 0, pk, 0, ctx, prehash, sigGen, 0);
-  CheckTrue(AreEqual(sig, sigGen), text);
-
-  prehash := Ed25519Instance.CreatePreHash();
-  prehash.BlockUpdate(m, 0, System.Length(m));
+  LPrehash := TEd25519.CreatePreHash();
+  LPrehash.BlockUpdate(LM, 0, System.Length(LM));
+  LShouldNotVerify := FEd25519.VerifyPreHash(LBadSig, 0, LPk, 0, LCtx, LPrehash);
+  CheckFalse(LShouldNotVerify, AText);
+end;
 
-  shouldVerify := Ed25519Instance.VerifyPreHash(sig, 0, pk, 0, ctx, prehash);
-  CheckTrue(shouldVerify, text);
+procedure TTestEd25519.ImplTamingVector(ANumber: Int32; AExpected: Boolean;
+  const AMsgHex, APubHex, ASigHex: String);
+var
+  LActual: Boolean;
+begin
+  LActual := ImplTamingVector(AMsgHex, APubHex, ASigHex);
+  CheckEquals(AExpected, LActual, Format('Failed Taming EdDSA Vector #%d', [ANumber]));
+end;
 
-  prehash := Ed25519Instance.CreatePreHash();
-  prehash.BlockUpdate(m, 0, System.Length(m));
+function TTestEd25519.ImplTamingVector(const AMsgHex, APubHex,
+  ASigHex: String): Boolean;
+var
+  LMsg, LPub, LSig: TBytes;
+begin
+  if System.Length(ASigHex) <> TEd25519.SignatureSize * 2 then
+  begin
+    Result := False;
+    Exit;
+  end;
 
-  shouldNotVerify := Ed25519Instance.VerifyPreHash(badsig, 0, pk, 0,
-    ctx, prehash);
-  CheckFalse(shouldNotVerify, text);
+  LMsg := DecodeHex(AMsgHex);
+  LPub := DecodeHex(APubHex);
+  LSig := DecodeHex(ASigHex);
 
+  try
+    Result := FEd25519.Verify(LSig, 0, LPub, 0, LMsg, 0, System.Length(LMsg));
+  except
+    Result := False;
+  end;
 end;
 
 procedure TTestEd25519.SetUp;
 begin
   inherited;
-  FRandom := TSecureRandom.Create();
   TEd25519.Precompute();
+  FRandom := TSecureRandom.Create();
+  FEd25519 := TEd25519.Create();
 end;
 
 procedure TTestEd25519.TearDown;
 begin
+  FEd25519.Free;
+  FEd25519 := nil;
   inherited;
-
 end;
 
 procedure TTestEd25519.TestEd25519Consistency;
 var
-  sk, pk, m, sig1, sig2: TBytes;
-  i, mLen: Int32;
-  Ed25519Instance: IEd25519;
-  shouldVerify, shouldNotVerify: Boolean;
+  LSk, LPk, LPk2, LM, LSig1, LSig2: TBytes;
+  LPublicPoint: TEd25519.IPublicPoint;
+  I, LMLen: Int32;
+  LShouldVerify, LShouldNotVerify: Boolean;
 begin
-  System.SetLength(sk, TEd25519.SecretKeySize);
-  System.SetLength(pk, TEd25519.PublicKeySize);
-  System.SetLength(m, 255);
-  System.SetLength(sig1, TEd25519.SignatureSize);
-  System.SetLength(sig2, TEd25519.SignatureSize);
+  System.SetLength(LSk, TEd25519.SecretKeySize);
+  System.SetLength(LPk, TEd25519.PublicKeySize);
+  System.SetLength(LPk2, TEd25519.PublicKeySize);
+  System.SetLength(LM, 255);
+  System.SetLength(LSig1, TEd25519.SignatureSize);
+  System.SetLength(LSig2, TEd25519.SignatureSize);
 
-  FRandom.NextBytes(m);
+  FRandom.NextBytes(LM);
 
-  for i := 0 to System.Pred(10) do
+  for I := 0 to 9 do
   begin
-    FRandom.NextBytes(sk);
-    Ed25519Instance := TEd25519.Create();
-    Ed25519Instance.GeneratePublicKey(sk, 0, pk, 0);
+    FEd25519.GeneratePrivateKey(FRandom, LSk);
+    LPublicPoint := TEd25519.GeneratePublicKey(LSk, 0);
+    TEd25519.EncodePublicPoint(LPublicPoint, LPk, 0);
 
-    mLen := FRandom.NextInt32() and 255;
+    FEd25519.GeneratePublicKey(LSk, 0, LPk2, 0);
+    CheckTrue(AreEqual(LPk, LPk2), Format('Ed25519 consistent generation #%d', [I]));
 
-    Ed25519Instance.Sign(sk, 0, m, 0, mLen, sig1, 0);
-    Ed25519Instance.Sign(sk, 0, pk, 0, m, 0, mLen, sig2, 0);
+    LMLen := FRandom.NextInt32() and 255;
 
-    CheckTrue(AreEqual(sig1, sig2),
-      Format('Ed25519 consistent signatures #%d', [i]));
+    FEd25519.Sign(LSk, 0, LM, 0, LMLen, LSig1, 0);
+    FEd25519.Sign(LSk, 0, LPk, 0, LM, 0, LMLen, LSig2, 0);
 
-    shouldVerify := Ed25519Instance.Verify(sig1, 0, pk, 0, m, 0, mLen);
+    CheckTrue(AreEqual(LSig1, LSig2), Format('Ed25519 consistent signatures #%d', [I]));
 
-    CheckTrue(shouldVerify, Format('Ed25519 consistent sign/verify #%d', [i]));
+    LShouldVerify := FEd25519.Verify(LSig1, 0, LPk, 0, LM, 0, LMLen);
+    CheckTrue(LShouldVerify, Format('Ed25519 consistent sign/verify #%d', [I]));
 
-    sig1[TEd25519.PublicKeySize - 1] :=
-      sig1[TEd25519.PublicKeySize - 1] xor $80;
-    shouldNotVerify := Ed25519Instance.Verify(sig1, 0, pk, 0, m, 0, mLen);
+    LShouldVerify := FEd25519.Verify(LSig1, 0, LPublicPoint, LM, 0, LMLen);
+    CheckTrue(LShouldVerify, Format('Ed25519 consistent sign/verify #%d', [I]));
 
-    CheckFalse(shouldNotVerify,
-      Format('Ed25519 consistent verification failure #%d', [i]));
+    LSig1[TEd25519.PublicKeySize - 1] := Byte(LSig1[TEd25519.PublicKeySize - 1]
+      xor $80);
+
+    LShouldNotVerify := FEd25519.Verify(LSig1, 0, LPk, 0, LM, 0, LMLen);
+    CheckFalse(LShouldNotVerify,
+      Format('Ed25519 consistent verification failure #%d', [I]));
+
+    LShouldNotVerify := FEd25519.Verify(LSig1, 0, LPublicPoint, LM, 0, LMLen);
+    CheckFalse(LShouldNotVerify,
+      Format('Ed25519 consistent verification failure #%d', [I]));
   end;
 end;
 
 procedure TTestEd25519.TestEd25519ctxConsistency;
 var
-  sk, pk, ctx, m, sig1, sig2: TBytes;
-  i, mLen: Int32;
-  Ed25519Instance: IEd25519;
-  shouldVerify, shouldNotVerify: Boolean;
-begin
-  System.SetLength(sk, TEd25519.SecretKeySize);
-  System.SetLength(pk, TEd25519.PublicKeySize);
-  System.SetLength(ctx, FRandom.NextInt32() and 7);
-  System.SetLength(m, 255);
-  System.SetLength(sig1, TEd25519.SignatureSize);
-  System.SetLength(sig2, TEd25519.SignatureSize);
-
-  FRandom.NextBytes(ctx);
-  FRandom.NextBytes(m);
-
-  for i := 0 to System.Pred(10) do
+  LSk, LPk, LPk2, LCtx, LM, LSig1, LSig2: TBytes;
+  LPublicPoint: TEd25519.IPublicPoint;
+  I, LMLen: Int32;
+  LShouldVerify, LShouldNotVerify: Boolean;
+begin
+  System.SetLength(LSk, TEd25519.SecretKeySize);
+  System.SetLength(LPk, TEd25519.PublicKeySize);
+  System.SetLength(LPk2, TEd25519.PublicKeySize);
+  System.SetLength(LCtx, FRandom.NextInt32() and 7);
+  System.SetLength(LM, 255);
+  System.SetLength(LSig1, TEd25519.SignatureSize);
+  System.SetLength(LSig2, TEd25519.SignatureSize);
+
+  FRandom.NextBytes(LCtx);
+  FRandom.NextBytes(LM);
+
+  for I := 0 to 9 do
   begin
-    FRandom.NextBytes(sk);
-    Ed25519Instance := TEd25519.Create();
-    Ed25519Instance.GeneratePublicKey(sk, 0, pk, 0);
+    FEd25519.GeneratePrivateKey(FRandom, LSk);
+    LPublicPoint := TEd25519.GeneratePublicKey(LSk, 0);
+    TEd25519.EncodePublicPoint(LPublicPoint, LPk, 0);
 
-    mLen := FRandom.NextInt32() and 255;
+    FEd25519.GeneratePublicKey(LSk, 0, LPk2, 0);
+    CheckTrue(AreEqual(LPk, LPk2), Format('Ed25519 consistent generation #%d', [I]));
 
-    Ed25519Instance.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0);
-    Ed25519Instance.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0);
+    LMLen := FRandom.NextInt32() and 255;
 
-    CheckTrue(AreEqual(sig1, sig2),
-      Format('Ed25519ctx consistent signatures #%d', [i]));
+    FEd25519.Sign(LSk, 0, LCtx, LM, 0, LMLen, LSig1, 0);
+    FEd25519.Sign(LSk, 0, LPk, 0, LCtx, LM, 0, LMLen, LSig2, 0);
 
-    shouldVerify := Ed25519Instance.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen);
+    CheckTrue(AreEqual(LSig1, LSig2),
+      Format('Ed25519ctx consistent signatures #%d', [I]));
 
-    CheckTrue(shouldVerify,
-      Format('Ed25519ctx consistent sign/verify #%d', [i]));
+    LShouldVerify := FEd25519.Verify(LSig1, 0, LPk, 0, LCtx, LM, 0, LMLen);
+    CheckTrue(LShouldVerify, Format('Ed25519ctx consistent sign/verify #%d', [I]));
 
-    sig1[TEd25519.PublicKeySize - 1] :=
-      sig1[TEd25519.PublicKeySize - 1] xor $80;
-    shouldNotVerify := Ed25519Instance.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen);
+    LShouldVerify := FEd25519.Verify(LSig1, 0, LPublicPoint, LCtx, LM, 0, LMLen);
+    CheckTrue(LShouldVerify, Format('Ed25519ctx consistent sign/verify #%d', [I]));
 
-    CheckFalse(shouldNotVerify,
-      Format('Ed25519ctx consistent verification failure #%d', [i]));
+    LSig1[TEd25519.PublicKeySize - 1] := Byte(LSig1[TEd25519.PublicKeySize - 1]
+      xor $80);
+
+    LShouldNotVerify := FEd25519.Verify(LSig1, 0, LPk, 0, LCtx, LM, 0, LMLen);
+    CheckFalse(LShouldNotVerify,
+      Format('Ed25519ctx consistent verification failure #%d', [I]));
+
+    LShouldNotVerify := FEd25519.Verify(LSig1, 0, LPublicPoint, LCtx, LM, 0, LMLen);
+    CheckFalse(LShouldNotVerify,
+      Format('Ed25519ctx consistent verification failure #%d', [I]));
+  end;
+end;
+
+procedure TTestEd25519.TestEd25519phConsistency;
+var
+  LSk, LPk, LPk2, LCtx, LM, LPh, LSig1, LSig2: TBytes;
+  LPublicPoint: TEd25519.IPublicPoint;
+  LPrehash: IDigest;
+  I, LMLen: Int32;
+  LShouldVerify, LShouldNotVerify: Boolean;
+begin
+  System.SetLength(LSk, TEd25519.SecretKeySize);
+  System.SetLength(LPk, TEd25519.PublicKeySize);
+  System.SetLength(LPk2, TEd25519.PublicKeySize);
+  System.SetLength(LCtx, FRandom.NextInt32() and 7);
+  System.SetLength(LM, 255);
+  System.SetLength(LPh, TEd25519.PrehashSize);
+  System.SetLength(LSig1, TEd25519.SignatureSize);
+  System.SetLength(LSig2, TEd25519.SignatureSize);
+
+  FRandom.NextBytes(LCtx);
+  FRandom.NextBytes(LM);
+
+  for I := 0 to 9 do
+  begin
+    FEd25519.GeneratePrivateKey(FRandom, LSk);
+    LPublicPoint := TEd25519.GeneratePublicKey(LSk, 0);
+    TEd25519.EncodePublicPoint(LPublicPoint, LPk, 0);
+
+    FEd25519.GeneratePublicKey(LSk, 0, LPk2, 0);
+    CheckTrue(AreEqual(LPk, LPk2), Format('Ed25519 consistent generation #%d', [I]));
+
+    LMLen := FRandom.NextInt32() and 255;
+
+    LPrehash := TEd25519.CreatePreHash();
+    LPrehash.BlockUpdate(LM, 0, LMLen);
+    LPrehash.DoFinal(LPh, 0);
+
+    FEd25519.SignPreHash(LSk, 0, LCtx, LPh, 0, LSig1, 0);
+    FEd25519.SignPreHash(LSk, 0, LPk, 0, LCtx, LPh, 0, LSig2, 0);
+
+    CheckTrue(AreEqual(LSig1, LSig2),
+      Format('Ed25519ph consistent signatures #%d', [I]));
+
+    LShouldVerify := FEd25519.VerifyPreHash(LSig1, 0, LPk, 0, LCtx, LPh, 0);
+    CheckTrue(LShouldVerify, Format('Ed25519ph consistent sign/verify #%d', [I]));
+
+    LShouldVerify := FEd25519.VerifyPreHash(LSig1, 0, LPublicPoint, LCtx, LPh, 0);
+    CheckTrue(LShouldVerify, Format('Ed25519ph consistent sign/verify #%d', [I]));
+
+    LSig1[TEd25519.PublicKeySize - 1] := Byte(LSig1[TEd25519.PublicKeySize - 1]
+      xor $80);
+
+    LShouldNotVerify := FEd25519.VerifyPreHash(LSig1, 0, LPk, 0, LCtx, LPh, 0);
+    CheckFalse(LShouldNotVerify,
+      Format('Ed25519ph consistent verification failure #%d', [I]));
+
+    LShouldNotVerify := FEd25519.VerifyPreHash(LSig1, 0, LPublicPoint, LCtx, LPh, 0);
+    CheckFalse(LShouldNotVerify,
+      Format('Ed25519ph consistent verification failure #%d', [I]));
   end;
 end;
 
 procedure TTestEd25519.TestEd25519Vector1;
 begin
-  CheckEd25519Vector(('9d61b19deffd5a60ba844af492ec2cc4' +
-    '4449c5697b326919703bac031cae7f60'),
-    ('d75a980182b10ab7d54bfed3c964073a' + '0ee172f3daa62325af021a68f707511a'),
-    '', ('e5564300c360ac729086e2cc806e828a' + '84877f1eb8e5d974d873e06522490155'
-    + '5fb8821590a33bacc61e39701cf9b46b' + 'd25bf5f0595bbe24655141438e7a100b'),
+  CheckEd25519Vector(
+    '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60',
+    'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a',
+    '',
+    'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b',
     'Ed25519 Vector #1');
 end;
 
 procedure TTestEd25519.TestEd25519Vector2;
 begin
-  CheckEd25519Vector(('4ccd089b28ff96da9db6c346ec114e0f' +
-    '5b8a319f35aba624da8cf6ed4fb8a6fb'),
-    ('3d4017c3e843895a92b70aa74d1b7ebc' + '9c982ccf2ec4968cc0cd55f12af4660c'),
-    '72', ('92a009a9f0d4cab8720e820b5f642540' +
-    'a2b27b5416503f8fb3762223ebdb69da' + '085ac1e43e15996e458f3613d0f11d8c' +
-    '387b2eaeb4302aeeb00d291612bb0c00'), 'Ed25519 Vector #2');
+  CheckEd25519Vector(
+    '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb',
+    '3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c',
+    '72',
+    '92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00',
+    'Ed25519 Vector #2');
 end;
 
 procedure TTestEd25519.TestEd25519Vector3;
 begin
-  CheckEd25519Vector(('c5aa8df43f9f837bedb7442f31dcb7b1' +
-    '66d38535076f094b85ce3a2e0b4458f7'),
-    ('fc51cd8e6218a1a38da47ed00230f058' + '0816ed13ba3303ac5deb911548908025'),
-    'af82', ('6291d657deec24024827e69c3abe01a3' +
-    '0ce548a284743a445e3680d7db5ac3ac' + '18ff9b538d16f290ae67f760984dc659' +
-    '4a7c15e9716ed28dc027beceea1ec40a'), 'Ed25519 Vector #3');
+  CheckEd25519Vector(
+    'c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7',
+    'fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025',
+    'af82',
+    '6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a',
+    'Ed25519 Vector #3');
 end;
 
 procedure TTestEd25519.TestEd25519Vector1023;
 var
-  m: String;
-begin
-  m := '08b8b2b733424243760fe426a4b54908' + '632110a66c2f6591eabd3345e3e4eb98' +
-    'fa6e264bf09efe12ee50f8f54e9f77b1' + 'e355f6c50544e23fb1433ddf73be84d8' +
-    '79de7c0046dc4996d9e773f4bc9efe57' + '38829adb26c81b37c93a1b270b20329d' +
-    '658675fc6ea534e0810a4432826bf58c' + '941efb65d57a338bbd2e26640f89ffbc' +
-    '1a858efcb8550ee3a5e1998bd177e93a' + '7363c344fe6b199ee5d02e82d522c4fe' +
-    'ba15452f80288a821a579116ec6dad2b' + '3b310da903401aa62100ab5d1a36553e' +
-    '06203b33890cc9b832f79ef80560ccb9' + 'a39ce767967ed628c6ad573cb116dbef' +
-    'efd75499da96bd68a8a97b928a8bbc10' + '3b6621fcde2beca1231d206be6cd9ec7' +
-    'aff6f6c94fcd7204ed3455c68c83f4a4' + '1da4af2b74ef5c53f1d8ac70bdcb7ed1' +
-    '85ce81bd84359d44254d95629e9855a9' + '4a7c1958d1f8ada5d0532ed8a5aa3fb2' +
-    'd17ba70eb6248e594e1a2297acbbb39d' + '502f1a8c6eb6f1ce22b3de1a1f40cc24' +
-    '554119a831a9aad6079cad88425de6bd' + 'e1a9187ebb6092cf67bf2b13fd65f270' +
-    '88d78b7e883c8759d2c4f5c65adb7553' + '878ad575f9fad878e80a0c9ba63bcbcc' +
-    '2732e69485bbc9c90bfbd62481d9089b' + 'eccf80cfe2df16a2cf65bd92dd597b07' +
-    '07e0917af48bbb75fed413d238f5555a' + '7a569d80c3414a8d0859dc65a46128ba' +
-    'b27af87a71314f318c782b23ebfe808b' + '82b0ce26401d2e22f04d83d1255dc51a' +
-    'ddd3b75a2b1ae0784504df543af8969b' + 'e3ea7082ff7fc9888c144da2af58429e' +
-    'c96031dbcad3dad9af0dcbaaaf268cb8' + 'fcffead94f3c7ca495e056a9b47acdb7' +
-    '51fb73e666c6c655ade8297297d07ad1' + 'ba5e43f1bca32301651339e22904cc8c' +
-    '42f58c30c04aafdb038dda0847dd988d' + 'cda6f3bfd15c4b4c4525004aa06eeff8' +
-    'ca61783aacec57fb3d1f92b0fe2fd1a8' + '5f6724517b65e614ad6808d6f6ee34df' +
-    'f7310fdc82aebfd904b01e1dc54b2927' + '094b2db68d6f903b68401adebf5a7e08' +
-    'd78ff4ef5d63653a65040cf9bfd4aca7' + '984a74d37145986780fc0b16ac451649' +
-    'de6188a7dbdf191f64b5fc5e2ab47b57' + 'f7f7276cd419c17a3ca8e1b939ae49e4' +
-    '88acba6b965610b5480109c8b17b80e1' + 'b7b750dfc7598d5d5011fd2dcc5600a3' +
-    '2ef5b52a1ecc820e308aa342721aac09' + '43bf6686b64b2579376504ccc493d97e' +
-    '6aed3fb0f9cd71a43dd497f01f17c0e2' + 'cb3797aa2a2f256656168e6c496afc5f' +
-    'b93246f6b1116398a346f1a641f3b041' + 'e989f7914f90cc2c7fff357876e506b5' +
-    '0d334ba77c225bc307ba537152f3f161' + '0e4eafe595f6d9d90d11faa933a15ef1' +
-    '369546868a7f3a45a96768d40fd9d034' + '12c091c6315cf4fde7cb68606937380d' +
-    'b2eaaa707b4c4185c32eddcdd306705e' + '4dc1ffc872eeee475a64dfac86aba41c' +
-    '0618983f8741c5ef68d3a101e8a3b8ca' + 'c60c905c15fc910840b94c00a0b9d0';
-
-  CheckEd25519Vector(('f5e5767cf153319517630f226876b86c' +
-    '8160cc583bc013744c6bf255f5cc0ee5'),
-    ('278117fc144c72340f67d0f2316e8386' + 'ceffbf2b2428c9c51fef7c597f1d426e'),
-    m, ('0aab4c900501b3e24d7cdf4663326a3a' + '87df5e4843b2cbdb67cbf6e460fec350'
-    + 'aa5371b1508f9f4528ecea23c436d94b' + '5e8fcd4f681e30a6ac00a9704a188a03'),
+  LM: String;
+begin
+  LM := '08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355' +
+        'f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc' +
+        '6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b' +
+        '199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b8' +
+        '32f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d' +
+        '206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d9562' +
+        '9e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40' +
+        'cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553' +
+        '878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0' +
+        '917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26' +
+        '401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3' +
+        'dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301' +
+        '651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f' +
+        '92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401ade' +
+        'bf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab4' +
+        '7b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a3' +
+        '2ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb37' +
+        '97aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba7' +
+        '7c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315c' +
+        'f4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef' +
+        '68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0';
+
+  CheckEd25519Vector(
+    'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5',
+    '278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e',
+    LM,
+    '0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03',
     'Ed25519 Vector #1023');
 end;
 
 procedure TTestEd25519.TestEd25519VectorSHAabc;
 begin
-  CheckEd25519Vector(('833fe62409237b9d62ec77587520911e' +
-    '9a759cec1d19755b7da901b96dca3d42'),
-    ('ec172b93ad5e563bf4932c70e1245034' + 'c35467ef2efd4d64ebf819683467e2bf'),
-    ('ddaf35a193617abacc417349ae204131' + '12e6fa4e89a97ea20a9eeee64b55d39a' +
-    '2192992a274fc1a836ba3c23a3feebbd' + '454d4423643ce80e2a9ac94fa54ca49f'),
-    ('dc2a4459e7369633a52b1bf277839a00' + '201009a3efbf3ecb69bea2186c26b589' +
-    '09351fc9ac90b3ecfdfbc7c66431e030' + '3dca179c138ac17ad9bef1177331a704'),
+  CheckEd25519Vector(
+    '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42',
+    'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf',
+    'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f',
+    'dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704',
     'Ed25519 Vector SHA(abc)');
 end;
 
 procedure TTestEd25519.TestEd25519ctxVector1;
 begin
-  CheckEd25519ctxVector(('0305334e381af78f141cb666f6199f57' +
-    'bc3495335a256a95bd2a55bf546663f6'),
-    ('dfc9425e4f968f7f0c29f0259cf5f9ae' + 'd6851c2bb4ad8bfb860cfee0ab248292'),
-    'f726936d19c800494e3fdaff20b276a8', '666f6f',
-    ('55a4cc2f70a54e04288c5f4cd1e45a7b' + 'b520b36292911876cada7323198dd87a' +
-    '8b36950b95130022907a7fb7c4e9b2d5' + 'f6cca685a587b4b21f4b888e4e7edb0d'),
+  CheckEd25519ctxVector(
+    '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
+    'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
+    'f726936d19c800494e3fdaff20b276a8',
+    '666f6f',
+    '55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d',
     'Ed25519ctx Vector #1');
 end;
 
 procedure TTestEd25519.TestEd25519ctxVector2;
 begin
-  CheckEd25519ctxVector(('0305334e381af78f141cb666f6199f57' +
-    'bc3495335a256a95bd2a55bf546663f6'),
-    ('dfc9425e4f968f7f0c29f0259cf5f9ae' + 'd6851c2bb4ad8bfb860cfee0ab248292'),
-    'f726936d19c800494e3fdaff20b276a8', '626172',
-    ('fc60d5872fc46b3aa69f8b5b4351d580' + '8f92bcc044606db097abab6dbcb1aee3' +
-    '216c48e8b3b66431b5b186d1d28f8ee1' + '5a5ca2df6668346291c2043d4eb3e90d'),
+  CheckEd25519ctxVector(
+    '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
+    'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
+    'f726936d19c800494e3fdaff20b276a8',
+    '626172',
+    'fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d',
     'Ed25519ctx Vector #2');
 end;
 
 procedure TTestEd25519.TestEd25519ctxVector3;
 begin
-  CheckEd25519ctxVector(('0305334e381af78f141cb666f6199f57' +
-    'bc3495335a256a95bd2a55bf546663f6'),
-    ('dfc9425e4f968f7f0c29f0259cf5f9ae' + 'd6851c2bb4ad8bfb860cfee0ab248292'),
-    '508e9e6882b979fea900f62adceaca35', '666f6f',
-    ('8b70c1cc8310e1de20ac53ce28ae6e72' + '07f33c3295e03bb5c0732a1d20dc6490' +
-    '8922a8b052cf99b7c4fe107a5abb5b2c' + '4085ae75890d02df26269d8945f84b0b'),
+  CheckEd25519ctxVector(
+    '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
+    'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
+    '508e9e6882b979fea900f62adceaca35',
+    '666f6f',
+    '8b70c1cc8310e1de20ac53ce28ae6e7207f33c3295e03bb5c0732a1d20dc64908922a8b052cf99b7c4fe107a5abb5b2c4085ae75890d02df26269d8945f84b0b',
     'Ed25519ctx Vector #3');
 end;
 
 procedure TTestEd25519.TestEd25519ctxVector4;
 begin
-  CheckEd25519ctxVector(('ab9c2853ce297ddab85c993b3ae14bca' +
-    'd39b2c682beabc27d6d4eb20711d6560'),
-    ('0f1d1274943b91415889152e893d80e9' + '3275a1fc0b65fd71b4b0dda10ad7d772'),
-    'f726936d19c800494e3fdaff20b276a8', '666f6f',
-    ('21655b5f1aa965996b3f97b3c849eafb' + 'a922a0a62992f73b3d1b73106a84ad85' +
-    'e9b86a7b6005ea868337ff2d20a7f5fb' + 'd4cd10b0be49a68da2b2e0dc0ad8960f'),
+  CheckEd25519ctxVector(
+    'ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560',
+    '0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772',
+    'f726936d19c800494e3fdaff20b276a8',
+    '666f6f',
+    '21655b5f1aa965996b3f97b3c849eafba922a0a62992f73b3d1b73106a84ad85e9b86a7b6005ea868337ff2d20a7f5fbd4cd10b0be49a68da2b2e0dc0ad8960f',
     'Ed25519ctx Vector #4');
 end;
 
 procedure TTestEd25519.TestEd25519phVector1;
 begin
-  CheckEd25519phVector(('833fe62409237b9d62ec77587520911e' +
-    '9a759cec1d19755b7da901b96dca3d42'),
-    ('ec172b93ad5e563bf4932c70e1245034' + 'c35467ef2efd4d64ebf819683467e2bf'),
-    '616263', '', ('98a70222f0b8121aa9d30f813d683f80' +
-    '9e462b469c7ff87639499bb94e6dae41' + '31f85042463c2a355a2003d062adf5aa' +
-    'a10b8c61e636062aaad11c2a26083406'), 'Ed25519ph Vector #1');
+  CheckEd25519phVector(
+    '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42',
+    'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf',
+    '616263',
+    '',
+    '98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406',
+    'Ed25519ph Vector #1');
 end;
 
-procedure TTestEd25519.TestEd25519phConsistency;
+procedure TTestEd25519.TestPublicKeyValidationFull;
 var
-  sk, pk, ctx, m, ph, sig1, sig2: TBytes;
-  i, mLen: Int32;
-  Ed25519Instance: IEd25519;
-  shouldVerify, shouldNotVerify: Boolean;
-  prehash: IDigest;
-begin
-  System.SetLength(sk, TEd25519.SecretKeySize);
-  System.SetLength(pk, TEd25519.PublicKeySize);
-  System.SetLength(ctx, FRandom.NextInt32() and 7);
-  System.SetLength(m, 255);
-  System.SetLength(ph, 255);
-  System.SetLength(sig1, TEd25519.PreHashSize);
-  System.SetLength(sig2, TEd25519.SignatureSize);
-
-  FRandom.NextBytes(ctx);
-  FRandom.NextBytes(m);
-
-  for i := 0 to System.Pred(10) do
+  LSk, LPk: TBytes;
+  I: Int32;
+begin
+  System.SetLength(LSk, TEd25519.SecretKeySize);
+  System.SetLength(LPk, TEd25519.PublicKeySize);
+
+  for I := 0 to 9 do
   begin
-    FRandom.NextBytes(sk);
-    Ed25519Instance := TEd25519.Create();
-    Ed25519Instance.GeneratePublicKey(sk, 0, pk, 0);
+    FEd25519.GeneratePrivateKey(FRandom, LSk);
+    FEd25519.GeneratePublicKey(LSk, 0, LPk, 0);
+    CheckTrue(TEd25519.ValidatePublicKeyFull(LPk, 0));
+  end;
 
-    mLen := FRandom.NextInt32() and 255;
+  // Small order points (canonical encodings)
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('0000000000000000000000000000000000000000000000000000000000000000'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('0000000000000000000000000000000000000000000000000000000000000080'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('0100000000000000000000000000000000000000000000000000000000000000'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('C7176A703D4DD84FBA3C0B760D10670F2A2053FA2C39CCC64EC7FD7792AC037A'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('C7176A703D4DD84FBA3C0B760D10670F2A2053FA2C39CCC64EC7FD7792AC03FA'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('26E8958FC2B227B045C3F489F2EF98F0D5DFAC05D3C63339B13802886D53FC05'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('26E8958FC2B227B045C3F489F2EF98F0D5DFAC05D3C63339B13802886D53FC85'), 0));
+
+  // Small order points (non-canonical encodings)
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('0100000000000000000000000000000000000000000000000000000000000080'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 0));
+
+  // Non-canonical encodings
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 0));
+
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('D73D6044821BD0DF4068AE1792F0851170F53062150AA70A87E2A58A05A26115'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('F9D557BE0F3C700571CD8AD9CFDE0A2C67F88EE71830073C7756A0599311AD94'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('7A772BBC08D53BF381B150D8411B9AF134BBF24B90A038EFD8DA4A17B32606A1'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('DC6EF81316C08B91209A73FE8E208DD319F56C6A47956A03AF7D6D826A88AC87'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('6EEDF105177868C9AD48DAF2C36EE3B169D892A02A3BF83101B1D50D86BFB19E'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('4BAAB5711F22FF7479E6D9BD2C5BC4DCD3CFC9F36921971496907B1F2B62C6BA'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('D96A46432581A80085F978F7FC0977E228C5A3FD2E64D588BB5F5E5A84E4ABAE'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('10C326AE15FA5BA89EDDAB89C860797385298F4C7750BAEB94A5AAC9A876B538'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('7808F3F6EB858E9BBD2570F20A9F7502175F312FA2DBE4C96EB5C683B384AA60'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('0DE943C51E91AA3ED9FFA82D39A9813D94F59246452F6A7780D067BC61342FE1'), 0));
+
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('10026DBFB4C55628716BB0EF979A10DD5AC7AA970C229B5E68DD993E2C20E7D5'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('68EC52D16C1DB4483AA8679277C34E0DC56EB7D064D302B9749F0D31A901D484'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('6E54C8F00669422D5697E09C0575AE1E699841ACF1690A5DFAA25E3160F3A2EF'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('CA66B62D361F790AA9658161BA0FFDC3CE60624151258C7301926DFE0C67EE64'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('88D912C322AE3D0907B38ED08727FBF06D51C5D1DE622B5BC24DAB30078AE9FF'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('F24683E044CE3F14BCA24F1356AE7767509E17EFA2606438BA275860819E14B8'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('B2865F02E6D19A94CE6147B574095733B3628A2FBE2C84022262D88F7D6C4F7D'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('FA4DA03321816C1C9066BD250982DDD1B4349C43C5E124D2B39F8DDA4E5364F8'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('FCADF40DE51A943F3B7847DBEBA0627B33D020D81DFFABF2B3701BD9B746952A'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyFull(DecodeHex('379B071E6F7E2479D5A8588AB708137808D63F689127D4A228E2C1681873C55E'), 0));
+end;
 
-    prehash := Ed25519Instance.CreatePreHash();
-    prehash.BlockUpdate(m, 0, mLen);
-    prehash.DoFinal(ph, 0);
+procedure TTestEd25519.TestPublicKeyValidationPartial;
+var
+  LSk, LPk: TBytes;
+  I: Int32;
+begin
+  System.SetLength(LSk, TEd25519.SecretKeySize);
+  System.SetLength(LPk, TEd25519.PublicKeySize);
 
-    Ed25519Instance.SignPreHash(sk, 0, ctx, ph, 0, sig1, 0);
-    Ed25519Instance.SignPreHash(sk, 0, pk, 0, ctx, ph, 0, sig2, 0);
+  for I := 0 to 9 do
+  begin
+    FEd25519.GeneratePrivateKey(FRandom, LSk);
+    FEd25519.GeneratePublicKey(LSk, 0, LPk, 0);
+    CheckTrue(TEd25519.ValidatePublicKeyPartial(LPk, 0));
+  end;
 
-    CheckTrue(AreEqual(sig1, sig2),
-      Format('Ed25519ph consistent signatures #%d', [i]));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '0000000000000000000000000000000000000000000000000000000000000000'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '0000000000000000000000000000000000000000000000000000000000000080'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '0100000000000000000000000000000000000000000000000000000000000000'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'C7176A703D4DD84FBA3C0B760D10670F2A2053FA2C39CCC64EC7FD7792AC037A'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'C7176A703D4DD84FBA3C0B760D10670F2A2053FA2C39CCC64EC7FD7792AC03FA'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '26E8958FC2B227B045C3F489F2EF98F0D5DFAC05D3C63339B13802886D53FC05'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '26E8958FC2B227B045C3F489F2EF98F0D5DFAC05D3C63339B13802886D53FC85'), 0));
+
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '0100000000000000000000000000000000000000000000000000000000000080'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 0));
+
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 0));
+
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'D73D6044821BD0DF4068AE1792F0851170F53062150AA70A87E2A58A05A26115'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'F9D557BE0F3C700571CD8AD9CFDE0A2C67F88EE71830073C7756A0599311AD94'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '7A772BBC08D53BF381B150D8411B9AF134BBF24B90A038EFD8DA4A17B32606A1'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'DC6EF81316C08B91209A73FE8E208DD319F56C6A47956A03AF7D6D826A88AC87'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '6EEDF105177868C9AD48DAF2C36EE3B169D892A02A3BF83101B1D50D86BFB19E'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '4BAAB5711F22FF7479E6D9BD2C5BC4DCD3CFC9F36921971496907B1F2B62C6BA'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'D96A46432581A80085F978F7FC0977E228C5A3FD2E64D588BB5F5E5A84E4ABAE'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '10C326AE15FA5BA89EDDAB89C860797385298F4C7750BAEB94A5AAC9A876B538'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '7808F3F6EB858E9BBD2570F20A9F7502175F312FA2DBE4C96EB5C683B384AA60'), 0));
+  CheckFalse(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '0DE943C51E91AA3ED9FFA82D39A9813D94F59246452F6A7780D067BC61342FE1'), 0));
+
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '10026DBFB4C55628716BB0EF979A10DD5AC7AA970C229B5E68DD993E2C20E7D5'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '68EC52D16C1DB4483AA8679277C34E0DC56EB7D064D302B9749F0D31A901D484'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '6E54C8F00669422D5697E09C0575AE1E699841ACF1690A5DFAA25E3160F3A2EF'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'CA66B62D361F790AA9658161BA0FFDC3CE60624151258C7301926DFE0C67EE64'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '88D912C322AE3D0907B38ED08727FBF06D51C5D1DE622B5BC24DAB30078AE9FF'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'F24683E044CE3F14BCA24F1356AE7767509E17EFA2606438BA275860819E14B8'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'B2865F02E6D19A94CE6147B574095733B3628A2FBE2C84022262D88F7D6C4F7D'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'FA4DA03321816C1C9066BD250982DDD1B4349C43C5E124D2B39F8DDA4E5364F8'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    'FCADF40DE51A943F3B7847DBEBA0627B33D020D81DFFABF2B3701BD9B746952A'), 0));
+  CheckTrue(TEd25519.ValidatePublicKeyPartial(DecodeHex(
+    '379B071E6F7E2479D5A8588AB708137808D63F689127D4A228E2C1681873C55E'), 0));
+end;
 
-    shouldVerify := Ed25519Instance.VerifyPreHash(sig1, 0, pk, 0, ctx, ph, 0);
+procedure TTestEd25519.TamingNonRepudiation;
+var
+  LMsg1, LMsg2, LPub, LSig: TBytes;
+begin
+  LMsg1 := TConverters.ConvertStringToBytes('Send 100 USD to Alice',
+    TEncoding.UTF8);
+  LMsg2 := TConverters.ConvertStringToBytes('Send 100000 USD to Alice',
+    TEncoding.UTF8);
+  LPub := DecodeHex(
+    'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f');
+  LSig := DecodeHex(
+    'a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dc' +
+    'a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04');
+
+  CheckFalse(FEd25519.Verify(LSig, 0, LPub, 0, LMsg1, 0, System.Length(LMsg1)));
+  CheckFalse(FEd25519.Verify(LSig, 0, LPub, 0, LMsg2, 0, System.Length(LMsg2)));
+end;
 
-    CheckTrue(shouldVerify,
-      Format('Ed25519ph consistent sign/verify #%d', [i]));
+procedure TTestEd25519.TamingVector_00;
+begin
+  ImplTamingVector(0, False,
+    '8c93255d71dcab10e8f379c26200f3c7bd5f09d9bc3068d3ef4edeb4853022b6',
+    'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
+    'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a' +
+    '0000000000000000000000000000000000000000000000000000000000000000');
+end;
 
-    sig1[TEd25519.PublicKeySize - 1] :=
-      sig1[TEd25519.PublicKeySize - 1] xor $80;
-    shouldNotVerify := Ed25519Instance.VerifyPreHash(sig1, 0, pk, 0,
-      ctx, ph, 0);
+procedure TTestEd25519.TamingVector_01;
+begin
+  ImplTamingVector(1, False,
+    '9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79',
+    'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
+    'f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43' +
+    'a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04');
+end;
 
-    CheckFalse(shouldNotVerify,
-      Format('Ed25519ph consistent verification failure #%d', [i]));
-  end;
+procedure TTestEd25519.TamingVector_02;
+begin
+  ImplTamingVector(2, True,
+    'aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab',
+    'f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43',
+    'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa' +
+    '8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e');
 end;
 
-initialization
+procedure TTestEd25519.TamingVector_03;
+begin
+  ImplTamingVector(3, True,
+    '9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79',
+    'cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d',
+    '9046a64750444938de19f227bb80485e92b83fdb4b6506c160484c016cc1852f' +
+    '87909e14428a7a1d62e9f22f3d3ad7802db02eb2e688b6c52fcd6648a98bd009');
+end;
 
-// Register any test cases with the test runner
+procedure TTestEd25519.TamingVector_04;
+begin
+  ImplTamingVector(4, True,
+    'e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c',
+    'cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d',
+    '160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed512' +
+    '5ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09');
+end;
+
+procedure TTestEd25519.TamingVector_05;
+begin
+  ImplTamingVector(5, True,
+    'e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c',
+    'cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d',
+    '21122a84e0b5fca4052f5b1235c80a537878b38f3142356b2c2384ebad4668b7' +
+    'e40bc836dac0f71076f9abe3a53f9c03c1ceeeddb658d0030494ace586687405');
+end;
+
+procedure TTestEd25519.TamingVector_06;
+begin
+  ImplTamingVector(6, False,
+    '85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40',
+    '442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623',
+    'e96f66be976d82e60150baecff9906684aebb1ef181f67a7189ac78ea23b6c0e' +
+    '547f7690a0e2ddcd04d87dbc3490dc19b3b3052f7ff0538cb68afb369ba3a514');
+end;
+
+procedure TTestEd25519.TamingVector_07;
+begin
+  ImplTamingVector(7, False,
+    '85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40',
+    '442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623',
+    '8ce5b96c8f26d0ab6c47958c9e68b937104cd36e13c33566acd2fe8d38aa1942' +
+    '7e71f98a4734e74f2f13f06f97c20d58cc3f54b8bd0d272f42b695dd7e89a8c22');
+end;
+
+procedure TTestEd25519.TamingVector_08;
+begin
+  ImplTamingVector(8, False,
+    '9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41',
+    'f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43',
+    'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
+    '03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f');
+end;
+
+procedure TTestEd25519.TamingVector_09;
+begin
+  ImplTamingVector(9, False,
+    '9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41',
+    'f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43',
+    'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
+    'ca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908');
+end;
+
+procedure TTestEd25519.TamingVector_10;
+begin
+  ImplTamingVector(10, False,
+    'e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b',
+    'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+    'a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dc' +
+    'a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04');
+end;
+
+procedure TTestEd25519.TamingVector_11;
+begin
+  ImplTamingVector(11, False,
+    '39a591f5321bbe07fd5a23dc2f39d025d74526615746727ceefd6e82ae65c06f',
+    'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
+    'a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dc' +
+    'a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04');
+end;
+
+initialization
 
 {$IFDEF FPC}
   RegisterTest(TTestEd25519);

+ 859 - 250
CryptoLib.Tests/src/Others/Ed25519HigherLevelTests.pas

@@ -31,265 +31,145 @@ uses
 {$ELSE}
   TestFramework,
 {$ENDIF FPC}
-  TypInfo,
-  ClpSecureRandom,
-  ClpISecureRandom,
-  ClpISigner,
   ClpEd25519,
-  ClpIEd25519,
   ClpEd25519Signer,
-  ClpIEd25519Signer,
   ClpEd25519CtxSigner,
-  ClpIEd25519CtxSigner,
   ClpEd25519PhSigner,
-  ClpIEd25519PhSigner,
-  ClpIEd25519PrivateKeyParameters,
-  ClpIEd25519PublicKeyParameters,
   ClpEd25519PrivateKeyParameters,
+  ClpIEd25519PrivateKeyParameters,
   ClpEd25519PublicKeyParameters,
-  ClpIAsymmetricCipherKeyPair,
-  ClpAsymmetricCipherKeyPair,
+  ClpIEd25519PublicKeyParameters,
   ClpEd25519KeyPairGenerator,
   ClpIEd25519KeyPairGenerator,
   ClpEd25519KeyGenerationParameters,
   ClpIEd25519KeyGenerationParameters,
-  ClpSignerUtilities,
+  ClpIAsymmetricCipherKeyPair,
+  ClpISigner,
+  ClpSecureRandom,
+  ClpISecureRandom,
+  ClpICipherParameters,
+  ClpArrayUtilities,
+  ClpEncoders,
+  ClpStringUtilities,
   ClpCryptoLibTypes,
   CryptoLibTestBase;
 
 type
 
-  /// <summary>
-  /// test vectors gotten from <see href="https://github.com/warner/python-ed25519" />
-  /// and <see href="https://github.com/Matoking/python-ed25519-blake2b" />
-  /// </summary>
   TTestEd25519HigherLevel = class(TCryptoLibAlgorithmTestCase)
   private
   var
     FRandom: ISecureRandom;
 
-  type
-{$SCOPEDENUMS ON}
-    TEd25519SignerAlgorithm = (Ed25519);
-{$SCOPEDENUMS OFF}
-  function CreateSigner(algorithm: TEd25519.TEd25519Algorithm;
-    const context: TBytes): ISigner;
-
-  function CreateCustomSigner(const algorithm: TEd25519SignerAlgorithm)
-    : ISigner;
-
-  function ReconstructEd25519KeyPair(algorithm: TEd25519SignerAlgorithm;
-    const sk, pk: TBytes): IAsymmetricCipherKeyPair;
-
-  function RandomContext(length: Int32): TBytes;
-
-  procedure DoTestConsistency(algorithm: TEd25519.TEd25519Algorithm;
-    const context: TBytes);
-
-  procedure DoEd25519Test(id: Int32; algorithm: TEd25519SignerAlgorithm;
-    const sk, pk, msg, sig: String);
+    function CreateSigner(AAlgorithm: TEd25519.TAlgorithm;
+      const AContext: TBytes): ISigner;
+    procedure DoTestConsistency(AAlgorithm: TEd25519.TAlgorithm;
+      const AContext: TBytes);
+    function RandomContext(ALength: Int32): TBytes;
+    procedure TestRegressionInfiniteLoopImpl();
   protected
     procedure SetUp; override;
     procedure TearDown; override;
   published
-    procedure TestConsistency();
-    procedure TestEd25519();
-
+    procedure TestBasicSig();
+    procedure TestConsistencyEd25519();
+    procedure TestConsistencyEd25519ctx();
+    procedure TestConsistencyEd25519ph();
+    procedure TestRegressionInfiniteLoop();
   end;
 
 implementation
 
 { TTestEd25519HigherLevel }
 
-function TTestEd25519HigherLevel.CreateCustomSigner(const algorithm
-  : TEd25519SignerAlgorithm): ISigner;
-var
-  algorithmName: String;
-begin
-  algorithmName := GetEnumName(TypeInfo(TEd25519SignerAlgorithm),
-    Ord(algorithm));
-  Result := TSignerUtilities.GetSigner(algorithmName);
-end;
-
-function TTestEd25519HigherLevel.CreateSigner
-  (algorithm: TEd25519.TEd25519Algorithm; const context: TBytes): ISigner;
+function TTestEd25519HigherLevel.CreateSigner(AAlgorithm: TEd25519.TAlgorithm;
+  const AContext: TBytes): ISigner;
 begin
-  case algorithm of
-    TEd25519.TEd25519Algorithm.Ed25519:
-      Result := TEd25519Signer.Create()
-        as IEd25519Signer;
-    TEd25519.TEd25519Algorithm.Ed25519ctx:
-      Result := TEd25519CtxSigner.Create(context)
-        as IEd25519CtxSigner;
-    TEd25519.TEd25519Algorithm.Ed25519ph:
-      Result := TEd25519PhSigner.Create(context)
-        as IEd25519PhSigner;
+  case AAlgorithm of
+    TEd25519.TAlgorithm.Ed25519:
+      Result := TEd25519Signer.Create();
+    TEd25519.TAlgorithm.Ed25519ctx:
+      Result := TEd25519CtxSigner.Create(AContext);
+    TEd25519.TAlgorithm.Ed25519ph:
+      Result := TEd25519PhSigner.Create(AContext);
   else
-    begin
-      raise EArgumentCryptoLibException.Create('algorithm');
-    end;
+    raise EArgumentException.Create('algorithm');
   end;
 end;
 
-procedure TTestEd25519HigherLevel.DoEd25519Test(id: Int32;
-  algorithm: TEd25519SignerAlgorithm; const sk, pk, msg, sig: String);
+procedure TTestEd25519HigherLevel.DoTestConsistency(AAlgorithm: TEd25519.TAlgorithm;
+  const AContext: TBytes);
 var
-  LSk, LPk, LMsg, LSig, LResultSig, LKey: TBytes;
-  LKeyPair: IAsymmetricCipherKeyPair;
-  LIsVerified: Boolean;
-  LSigner: ISigner;
+  LKpg: IEd25519KeyPairGenerator;
+  LKp: IAsymmetricCipherKeyPair;
+  LPriv: IEd25519PrivateKeyParameters;
+  LPub: IEd25519PublicKeyParameters;
+  LMsg, LSignature, LWrongLengthSignature, LBadSignature: TBytes;
+  LMsgLen, LIdx, LBit: Int32;
+  LSigner, LVerifier: ISigner;
+  LShouldVerify, LShouldNotVerify: Boolean;
 begin
-  LSk := DecodeHex(sk);
-  LPk := DecodeHex(pk);
-  LMsg := DecodeHex(msg);
-  LSig := DecodeHex(sig);
-  LKeyPair := ReconstructEd25519KeyPair(algorithm, LSk, LPk);
-  LSigner := CreateCustomSigner(algorithm);
-
-  case algorithm of
-    TTestEd25519HigherLevel.TEd25519SignerAlgorithm.Ed25519:
-      begin
-        LKey := (LKeyPair.Private as IEd25519PrivateKeyParameters).GetEncoded();
-        if not AreEqual(LKey, System.Copy(LSk, 0, 32)) then
-        begin
-          Fail(Format
-            ('Test with Id %d Failed on PrivateKey Reconstruction Comparison, Expected "%s" but got "%s"',
-            [id, EncodeHex(LSk), EncodeHex(LKey)]));
-        end;
-
-        LKey := (LKeyPair.Public as IEd25519PublicKeyParameters).GetEncoded();
-        if not AreEqual(LKey, System.Copy(LPk, 0, 64)) then
-        begin
-          Fail(Format
-            ('Test with Id %d Failed on PublicKey Reconstruction Comparison, Expected "%s" but got "%s"',
-            [id, EncodeHex(LPk), EncodeHex(LKey)]));
-        end;
-      end;
-  else
-    begin
-      raise EArgumentCryptoLibException.Create('algorithm');
-    end;
-
-  end;
-
-  LSigner.Init(True, LKeyPair.Private);
-  LSigner.BlockUpdate(LMsg, 0, System.length(LMsg));
-  LResultSig := LSigner.GenerateSignature();
-
-  if not AreEqual(LResultSig, System.Copy(LSig, 0, 64)) then
-  begin
-    Fail(Format
-      ('Test with Id %d Failed on Signature Comparison, Expected "%s" but got "%s"',
-      [id, EncodeHex(LSig), EncodeHex(LResultSig)]));
-  end;
-
-  LSigner.Init(False, LKeyPair.Public);
-  LSigner.BlockUpdate(LMsg, 0, System.length(LMsg));
-  LIsVerified := LSigner.VerifySignature(LResultSig);
-
-  if not LIsVerified then
-  begin
-    Fail(Format('Test with Id %d Failed on Verifying "%s" Signature',
-      [id, EncodeHex(LResultSig)]));
-  end;
-end;
-
-procedure TTestEd25519HigherLevel.DoTestConsistency
-  (algorithm: TEd25519.TEd25519Algorithm; const context: TBytes);
-var
-  kpg: IEd25519KeyPairGenerator;
-  kp: IAsymmetricCipherKeyPair;
-  privateKey: IEd25519PrivateKeyParameters;
-  publicKey: IEd25519PublicKeyParameters;
-  msg, signature, wrongLengthSignature: TBytes;
-  Signer, verifier: ISigner;
-  shouldVerify, shouldNotVerify: Boolean;
-  algorithmName: String;
-  tempRand: Int32;
-begin
-  kpg := TEd25519KeyPairGenerator.Create(TEd25519.Create() as IEd25519);
-  kpg.Init(TEd25519KeyGenerationParameters.Create(FRandom)
+  LKpg := TEd25519KeyPairGenerator.Create() as IEd25519KeyPairGenerator;
+  LKpg.Init(TEd25519KeyGenerationParameters.Create(FRandom)
     as IEd25519KeyGenerationParameters);
 
-  kp := kpg.GenerateKeyPair();
-  privateKey := kp.Private as IEd25519PrivateKeyParameters;
-  publicKey := kp.Public as IEd25519PublicKeyParameters;
-
-  System.SetLength(msg, FRandom.NextInt32 and 255);
-  FRandom.NextBytes(msg);
-
-  Signer := CreateSigner(algorithm, context);
-  Signer.Init(True, privateKey);
-  Signer.BlockUpdate(msg, 0, System.length(msg));
-  signature := Signer.GenerateSignature();
-
-  verifier := CreateSigner(algorithm, context);
-  verifier.Init(False, publicKey);
-  verifier.BlockUpdate(msg, 0, System.length(msg));
-  shouldVerify := verifier.VerifySignature(signature);
-
-  algorithmName := GetEnumName(TypeInfo(TEd25519.TEd25519Algorithm),
-    Ord(algorithm));
-
-  if (not shouldVerify) then
+  LKp := LKpg.GenerateKeyPair();
+  LPriv := LKp.Private as IEd25519PrivateKeyParameters;
+  LPub := LKp.Public as IEd25519PublicKeyParameters;
+
+  LMsgLen := FRandom.NextInt32() and 255;
+  System.SetLength(LMsg, LMsgLen);
+  FRandom.NextBytes(LMsg);
+
+  LSigner := CreateSigner(AAlgorithm, AContext);
+  LSigner.Init(True, LPriv as ICipherParameters);
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+  LSignature := LSigner.GenerateSignature();
+
+  LVerifier := CreateSigner(AAlgorithm, AContext);
+  LVerifier.Init(False, LPub as ICipherParameters);
+  LVerifier.BlockUpdate(LMsg, 0, System.Length(LMsg));
+  LShouldVerify := LVerifier.VerifySignature(LSignature);
+  if not LShouldVerify then
+    Fail(Format('Ed25519(%s) signature failed to verify', [IntToStr(Ord(AAlgorithm))]));
+
+  System.SetLength(LWrongLengthSignature, System.Length(LSignature) + 1);
+  System.Move(LSignature[0], LWrongLengthSignature[0],
+    System.Length(LSignature) * System.SizeOf(Byte));
+  LWrongLengthSignature[System.Length(LSignature)] := 0;
+  LVerifier.Init(False, LPub as ICipherParameters);
+  LVerifier.BlockUpdate(LMsg, 0, System.Length(LMsg));
+  LShouldNotVerify := LVerifier.VerifySignature(LWrongLengthSignature);
+  if LShouldNotVerify then
+    Fail(Format('Ed25519(%s) wrong length signature incorrectly verified',
+      [IntToStr(Ord(AAlgorithm))]));
+
+  if LMsgLen > 0 then
   begin
-    Fail(Format('Ed25519 (%s) signature failed to verify', [algorithmName]));
+    LShouldNotVerify := LVerifier.VerifySignature(LSignature);
+    if LShouldNotVerify then
+      Fail(Format('Ed25519(%s) wrong length failure did not reset verifier',
+        [IntToStr(Ord(AAlgorithm))]));
   end;
 
-  wrongLengthSignature := Prepend(signature, Byte($00));
-
-  verifier.Init(False, publicKey);
-  verifier.BlockUpdate(msg, 0, System.length(msg));
-  shouldNotVerify := verifier.VerifySignature(wrongLengthSignature);
-
-  if (shouldNotVerify) then
-  begin
-    Fail(Format('Ed25519 (%s) wrong length signature incorrectly verified',
-      [algorithmName]));
-  end;
-
-  tempRand := FRandom.Next();
-  signature[tempRand mod System.length(signature)] :=
-    signature[tempRand mod System.length(signature)
-    ] xor Byte(1 shl (FRandom.NextInt32 and 7));
-
-  verifier.Init(False, publicKey);
-  verifier.BlockUpdate(msg, 0, System.length(msg));
-  shouldNotVerify := verifier.VerifySignature(signature);
-
-  if (shouldNotVerify) then
-  begin
-    Fail(Format('Ed25519 (%s) bad signature incorrectly verified',
-      [algorithmName]));
-  end;
+  LBadSignature := System.Copy(LSignature);
+  LIdx := (FRandom.Next() and $7FFFFFFF) mod System.Length(LBadSignature);
+  LBit := FRandom.NextInt32() and 7;
+  LBadSignature[LIdx] := Byte(LBadSignature[LIdx] xor (1 shl LBit));
+  LVerifier.Init(False, LPub as ICipherParameters);
+  LVerifier.BlockUpdate(LMsg, 0, System.Length(LMsg));
+  LShouldNotVerify := LVerifier.VerifySignature(LBadSignature);
+  if LShouldNotVerify then
+    Fail(Format('Ed25519(%s) bad signature incorrectly verified',
+      [IntToStr(Ord(AAlgorithm))]));
 end;
 
-function TTestEd25519HigherLevel.RandomContext(length: Int32): TBytes;
+function TTestEd25519HigherLevel.RandomContext(ALength: Int32): TBytes;
 begin
-  System.SetLength(Result, length);
+  System.SetLength(Result, ALength);
   FRandom.NextBytes(Result);
 end;
 
-function TTestEd25519HigherLevel.ReconstructEd25519KeyPair
-  (algorithm: TEd25519SignerAlgorithm; const sk, pk: TBytes)
-  : IAsymmetricCipherKeyPair;
-begin
-  case algorithm of
-    TTestEd25519HigherLevel.TEd25519SignerAlgorithm.Ed25519:
-      begin
-        Result := TAsymmetricCipherKeyPair.Create
-          (TEd25519PublicKeyParameters.Create(pk, 0)
-          as IEd25519PublicKeyParameters,
-          TEd25519PrivateKeyParameters.Create(TEd25519.Create() as IEd25519, sk,
-          0) as IEd25519PrivateKeyParameters);
-      end;
-  else
-    begin
-      raise EArgumentCryptoLibException.Create('algorithm');
-    end;
-  end;
-end;
-
 procedure TTestEd25519HigherLevel.SetUp;
 begin
   inherited;
@@ -299,62 +179,791 @@ end;
 procedure TTestEd25519HigherLevel.TearDown;
 begin
   inherited;
+end;
+
+procedure TTestEd25519HigherLevel.TestBasicSig;
+var
+  LPrivKey: IEd25519PrivateKeyParameters;
+  LPubKey: IEd25519PublicKeyParameters;
+  LSig, LSigGen: TBytes;
+  LSigner: ISigner;
+begin
+  LPrivKey := TEd25519PrivateKeyParameters.Create(DecodeHex(
+    '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60'));
+  LPubKey := TEd25519PublicKeyParameters.Create(DecodeHex(
+    'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'));
+
+  LSig := DecodeHex(
+    'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b');
 
+  LSigner := TEd25519Signer.Create();
+  LSigner.Init(True, LPrivKey as ICipherParameters);
+  LSigGen := LSigner.GenerateSignature();
+
+  CheckTrue(AreEqual(LSig, LSigGen),
+    'Ed25519 basic signature mismatch');
+
+  LSigner.Init(False, LPubKey as ICipherParameters);
+  CheckTrue(LSigner.VerifySignature(LSig), 'Ed25519 basic verify');
 end;
 
-procedure TTestEd25519HigherLevel.TestConsistency;
+procedure TTestEd25519HigherLevel.TestConsistencyEd25519;
 var
-  i: Int32;
-  context: TBytes;
+  I: Int32;
 begin
-  i := 0;
-  while i < 10 do
+  I := 0;
+  while I < 10 do
   begin
-    DoTestConsistency(TEd25519.TEd25519Algorithm.Ed25519, Nil);
-
-    context := RandomContext(FRandom.NextInt32 and 255);
-    DoTestConsistency(TEd25519.TEd25519Algorithm.Ed25519ctx, context);
-    DoTestConsistency(TEd25519.TEd25519Algorithm.Ed25519ph, context);
-    System.Inc(i);
+    DoTestConsistency(TEd25519.TAlgorithm.Ed25519, nil);
+    System.Inc(I);
   end;
 end;
 
-procedure TTestEd25519HigherLevel.TestEd25519;
+procedure TTestEd25519HigherLevel.TestConsistencyEd25519ctx;
+var
+  I: Int32;
+  LCtx: TBytes;
 begin
+  I := 0;
+  while I < 10 do
+  begin
+    LCtx := RandomContext(FRandom.NextInt32() and 255);
+    DoTestConsistency(TEd25519.TAlgorithm.Ed25519ctx, LCtx);
+    System.Inc(I);
+  end;
+end;
 
-  // TEd25519SignerAlgorithm.Ed25519
+procedure TTestEd25519HigherLevel.TestConsistencyEd25519ph;
+var
+  I: Int32;
+  LCtx: TBytes;
+begin
+  I := 0;
+  while I < 10 do
+  begin
+    LCtx := RandomContext(FRandom.NextInt32() and 255);
+    DoTestConsistency(TEd25519.TAlgorithm.Ed25519ph, LCtx);
+    System.Inc(I);
+  end;
+end;
 
-  DoEd25519Test(1, TEd25519SignerAlgorithm.Ed25519,
-    '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a',
-    'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a', '',
-    'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b');
+procedure TTestEd25519HigherLevel.TestRegressionInfiniteLoopImpl;
+const
+ TestCaseCount = 637;
+const
+  TestCases: array[0 .. TestCaseCount] of string = (
+    ('pub=MCowBQYDK2VwAyEA3/3evB5w/U2/UClcztEy9jyUhCYb4lsYC/Uc0Y3XU2A= priv=MC4CAQAwBQYDK2VwBCIEIPqycfmKBO' + 't+r71r9rPfm/qHloKw1mi0u7EtapwiyLFq msg=XffXN58qcNEDB9bG0Bi4+rJx+YoE636vvWv2s9+b+oeWgrDWaLS7sS1qnCLIs' + 'WogbfSKviAwbnT17l1hipS+Qw== sig=ygsIhBS66Bh6JYI+7NS7WX/KXIIqjMX4zlgqbH8euNCg1mkdj1E9gTZ1fxSfws8ZywBf' + 'LY1Sy+7ldggN2tLIDQ== e=found 57 iterations'),
+    ('pub=MCowBQYDK2VwAyEAHE6pGleQ6FLeLw37qqETXGJ7ypORl7ipr8mhKsuwGaE= priv=MC4CAQAwBQYDK2VwBCIEIOOZeFAaz2' + 'ab5MpacOllrYaslZc5GniKpptk6wBxJXIf msg=5uTZqblhMeTvsI2p6090Pjkkdqd+8GZQMN1Mnv/WvVFmnJN5IBDOjahUTJnfh' + 'Txs6EmeXSYeO4WrevJor16ETg== sig=s8aJ/GKWfb2dz7ll7Ne+CrCdjHI1K3Y/7gLDOIZavFpxHcH8giHrrQ59TIWU3T4Fhe/w' + 'e9EPcW/KzNcU4CUXAQ== e=found 58 iterations'),
+    ('pub=MCowBQYDK2VwAyEAJHkMcEbTWYrCDb+3JciGTTTwiTHHOGt/H0oWdCF7KjQ= priv=MC4CAQAwBQYDK2VwBCIEIGazYWgWo6' + 'F/+K0HNs1V1/N9LQm6T32nqJJ87pH5FSWb msg=yBv8Q3VCicgj+eBdgBrcdnp8uNO+LfgSVGazYWgWo6F/+K0HNs1V1/N9LQm6T' + '32nqJJ87pH5FSWbXmXIcTEWeQ== sig=o4KkE0Fe5PQXZ66mfG7tnh/k2/5EaPqXAOmgo0ji+apD2iiaQcb+1skazsJWbwoubWSD' + 'FiWUlJdh+eY/x0f+BA== e=found 59 iterations'),
+    ('pub=MCowBQYDK2VwAyEAQ0jwSazJght+xwc61Oot3UmMdefnvHBOvi3VsQ+X4qk= priv=MC4CAQAwBQYDK2VwBCIEICD2bl/Zm5' + 'YSPMftEm00BM0MUe6j+nlZXqztAkE0xrky msg=fADFP9wG2ltHE+pIErYCjodSbK5U/wnHzBHhx/vHJjhUxQv7uWx27zjvEYKLT' + 'JeJJvD3J2fH+afqfAJv7KmAPg== sig=dFQffK66bpOuv/CVySTNuuVvZ9vneh8N2gVYmEDjwEeYKVxDXOWR7Lz9VL4VREnMKmY1' + 'ABZqFGat42mtDhT7BQ== e=found 60 iterations'),
+    ('pub=MCowBQYDK2VwAyEAw9qjlWaWApPsYJoi1urhuZRPJ0HwKmcxSH+d+UrulFY= priv=MC4CAQAwBQYDK2VwBCIEIEChvJXCKY' + 'lzD95RdByx424MtBDDuNH+RUkdGOrFje93 msg=cpZ5pNbNxLTwIKyTGTCUpDNSOQZAobyVwimJcw/eUXQcseNuDLQQw7jR/kVJH' + 'RjqxY3vd9/B1yDiHPqJPl1weQ== sig=fQZ9FXypim4TXvs5XmLyfHlnl+H5dxsDruEXBRChZBPpYI+RU/DAN4/KJfxf3jWsr8Ek' + 'njmVgPncDftqBtGeCA== e=found 61 iterations'),
+    ('pub=MCowBQYDK2VwAyEAHVoqu90LAbDc9tY/24I85V3Iddy9IaYaqC6QnztbIWw= priv=MC4CAQAwBQYDK2VwBCIEIC5EY5KGGA' + '9Vz+RXn+Jb3C2P3vLngGox1x/VMq/xgQ/c msg=4g0xLkRjkoYYD1XP5Fef4lvcLY/e8ueAajHXH9Uyr/GBD9xDLCrQyr7DAX37F' + 'iM6XMXXdImapHyrKxjZ4hljwA== sig=goY0VKd7aQHUnHkfIX2ZUbE36lbJeOIT2949NsG77LmDn1don59tvyxfC1XaXVRiVx5l' + 'z6FbRQprvDqK8ltFDA== e=found 62 iterations'),
+    ('pub=MCowBQYDK2VwAyEAO2X9m9WY0jkQ3rsWHgB07rKXKSowZijSwNcats/rxls= priv=MC4CAQAwBQYDK2VwBCIEIHpGklIDOO' + 'xGzlBBJx8Z8q+uNYC7qwAT7Io3moNwpdNx msg=qY16RpJSAzjsRs5QQScfGfKvrjWAu6sAE+yKN5qDcKXTcU8uPgLQEoR22vXmN' + '0ZL1IjapYbh8IuG5X8o5C+9bQ== sig=ENLBlvemjb580cnBqSE9an761T3sVD7A/WYM9GZIspeOj8u2eyjMSrzOcu+hvL3sFNxZ' + 'vuIkv0WNBZSfNre8Bw== e=found 63 iterations'),
+    ('pub=MCowBQYDK2VwAyEAgU4uXIkXFTLtmF3rLM4rUbpMQqJAJKFAzKJm7T1CpiA= priv=MC4CAQAwBQYDK2VwBCIEIFjsWgCM7V' + 'fazSZBCZ1VOijO1YGF1keRqw9HVh5VRQxB msg=OijO1YGF1keRqw9HVh5VRQxBSbw4babQ5wmgtR4LVClBV2VEHtuBTsPAqisBJ' + 'NocB9h+LWJu+DejyjmHpcz9WQ== sig=jSRxppkrB+yUOs668HXOMy4Jjj4H9MP+cmXMwzEqsVl8wc6fp7EQj5+TrQKMxmE7wssK' + 'qEMiKkdBjDhtwjH5CQ== e=found 64 iterations'),
+    ('pub=MCowBQYDK2VwAyEAtouD0lJ0YQHbkEaX8gO3r9S0ChGHc+yTSaoCIvapPwE= priv=MC4CAQAwBQYDK2VwBCIEINjDs+pGo0' + 'ltBaFttGeFJCf9Mxx1HtKQTfDM+RvYsv5o msg=QnVUUQt6Oc4jVIN5s9jDs+pGo0ltBaFttGeFJCf9Mxx1HtKQTfDM+RvYsv5o1' + 'RebMvFrjIccGemNKesf2D1Dqg== sig=uRWDxSUqrlhZugfNof0M9ChCSAyXRwxPQj4BFMs1hPeN2OZOs9zwwX9A/txWOvjFFrxz' + 'Zv2RfxYDsbBw361fCw== e=found 65 iterations'),
+    ('pub=MCowBQYDK2VwAyEA7gJi5r5MaxpTqo6RUdDKnQ6dBI7F8nLQEKyBeHXIY8Q= priv=MC4CAQAwBQYDK2VwBCIEIPpWOkkMNi' + 'GqG3fvJKZmCmk4wkMlU/9pANei/BX3Mmxl msg=0p4n7fEf9tz7VFfwSUwQ6DD6VjpJDDYhqht37ySmZgppOMJDJVP/aQDXovwV9' + 'zJsZa09HhhSgN28xezygc6rxQ== sig=EinE0Nh/AIUdB6L4m93Y9/k0EHM9gXgGfBk5w3yJ4DyBTzwmfcvKpMM4biqeeGkLp/o1' + '78h99qo7VKHy4iu/CA== e=found 66 iterations'),
+    ('pub=MCowBQYDK2VwAyEAQ8fC52l1Ap4uBSm1UBbMGhUVYxQh3hrrwpO34TuwsMo= priv=MC4CAQAwBQYDK2VwBCIEIMCByifE3x' + 'spIRrcWScSuaPmd3teD9OAusym1ko2SHHN msg=LGrH8cQFin0saRCHUg32Uvl6W9CwSOI8sQKyw61UPe7AgconxN8bKSEa3FknE' + 'rmj5nd7Xg/TgLrMptZKNkhxzQ== sig=xuBEeHak/xpR0JWm3zIgMZBdNoAu4nBeYT4ZCMWWWIAp+N8WLRLEwqZc5ATRxFSIAyro' + 'eqqwfM+HCd57CYfJDQ== e=found 67 iterations'),
+    ('pub=MCowBQYDK2VwAyEALz5ECUSoAyj++sngkV9x579Rn9gIv60EhWM/Mo04qYI= priv=MC4CAQAwBQYDK2VwBCIEIAj/Likh1E' + 'SWhlieUj3NJsJYiyEaAb+NJGo0mJQlSFsI msg=Likh1ESWhlieUj3NJsJYiyEaAb+NJGo0mJQlSFsISkKXYllc3AFZLfIxEJhlg' + '7kkSPRoSjsywIKkQMKz0nTqmQ== sig=wyrojflpY11TM7qOQID9w2MuNEiBUe5djMdOd592gBtG3rC34bCM+e4YACZLRokN4+fI' + 'AEYkVBj9IsmqPa7DAw== e=found 68 iterations'),
+    ('pub=MCowBQYDK2VwAyEA3v9XVY2xwD7nD5NUZl3lvzlX7Vl+sSNQ39gDfBVy6Y4= priv=MC4CAQAwBQYDK2VwBCIEIHUSb1VM6d' + '2XAr/tGjaihT4lwDrhS6m+jQD4ss+BuWHP msg=f8Cm7q424+L+dRJvVUzp3ZcCv+0aNqKFPiXAOuFLqb6NAPiyz4G5Yc9djz1ZD' + 'GoobooR+E9P8LPdcnl3VW9XDg== sig=ArQBwnYbRe/TC/9mHVu9DpK2tUXh4QuikFZl7uKo4zaozZcR8T141Exm/c1gpEVZTVkz' + 'gej8LUsRD4bcO5L3Dw== e=found 69 iterations'),
+    ('pub=MCowBQYDK2VwAyEAcOsf+gEhq9BSSqzZ/qxCn/c4soTZuAQ2OIUmZbxOpo8= priv=MC4CAQAwBQYDK2VwBCIEIJjji9eyxd' + 'pYzxuxWfMJBunPDOVmBRMj4BVVP65o2Hlg msg=u4VP6f9VElsVCcWHrLH+6l138t4veA+LuUmOhVIzd8tg5ACs6fABUxYLd9WS5' + 'lixkY6lHSwtYnpxdTjw4W/xfw== sig=95we7zTeiWqIUgYq6ITdhOuY+wVeT52vFLxJ9lIHfbOvQIoUG/jIJ4tN8aO+E8+0ogKw' + '6hbMe5kI8BDcolD1BQ== e=found 70 iterations'),
+    ('pub=MCowBQYDK2VwAyEA5N2A+KytH1SUeGrALPa4exr9T7ilFqY4mP263N/dpoA= priv=MC4CAQAwBQYDK2VwBCIEIPW2m9QjkR' + 'RPOvH8+G9UzZawwLHeAvpb776Kbjy++FDm msg=GKb1tpvUI5EUTzrx/PhvVM2WsMCx3gL6W+++im48vvhQ5tHN4ZL4Npk59iwd+' + 'Xt3q244B0J4TrBjQTCJNOe1gA== sig=xBAT3nWrOK3BmthFVhjzQmRyuc//xEXnht058kFn7iMiK9qTawfPYrh/0GtMT+D8T+yw' + 'SHs8dheT2u6IMpGvCw== e=found 71 iterations'),
+    ('pub=MCowBQYDK2VwAyEAck4cyMfKmNjVvsYCniBLPGufQHdhsYkHxwN/yLRkFqI= priv=MC4CAQAwBQYDK2VwBCIEIOnPLabQHy' + 'dXPuXSFvVoefv5gGDw7g/hjwlkaYXvfkU2 msg=pTdX5+nPLabQHydXPuXSFvVoefv5gGDw7g/hjwlkaYXvfkU2eKdkOblsgfjKi' + 'unbgZSTPS+CsOJz3/C1qkuwoQ== sig=BBauQZjlkp/KGMQralAlgGOASATf4FTVr7pQJjRI+Z+ZRgWHdqwfwc2f+bskbFzdk/dM' + 'fX1+/adjpNqnQx++Aw== e=found 72 iterations'),
+    ('pub=MCowBQYDK2VwAyEACvojkSBSZ7VCiwZ3xXoU2ATVM0WICTajOKL9lE4p+/8= priv=MC4CAQAwBQYDK2VwBCIEIEGLCxghIN' + 'DDsZ2KD5pbvtezu48inGVtJDkhGJTNlExL msg=0MOxnYoPmlu+17O7jyKcZW0kOSEYlM2UTEsyjeEVoSB1oWw43IbtQsU1aXjEA' + 'bsGR37fjN2CJUSIIjbjWobglA== sig=tazDpJk/+ksUjyROEq7CQeYG3JWvSuo/a7n4i27dTtLnBZdJKI2Ss/CFgoUaFR7MghXm' + 'uFTgjRNkFTyIRH5kAQ== e=found 73 iterations'),
+    ('pub=MCowBQYDK2VwAyEAcyMeLZ2B6y+bumyenoAPjsVS3hYttEc65namio44OfY= priv=MC4CAQAwBQYDK2VwBCIEIMGtgiHjjy' + 'e6/sD0KGQsl3yMeglzwgUcLfr6kvZv1tLi msg=448nuv7A9ChkLJd8jHoJc8IFHC36+pL2b9bS4tSUHiMdMbHfGNxLoKVyQWmwZ' + 'I25RV3tb6uCZjShyeyAQxf5qQ== sig=rleDJhVQLfwwW/8BeJzQ0faH8exOaLOj2mZ7Pl22xb26SO/kJTNjwRwuJIa1ikE3VUYy' + 'in+Z8l1AKIsB1bUUDw== e=found 74 iterations'),
+    ('pub=MCowBQYDK2VwAyEAVbTtelb7fdEllJU4Isl/qQBVfpCwf/FS98Qo+39Juts= priv=MC4CAQAwBQYDK2VwBCIEIGR4+PJZWi' + 'LYLvY7K7QjxgEDc6wJNEP5FZVceJcYQFLd msg=XHiXGEBS3ebu2T5Ysp26sqATj5AgBZ5lUMXuFKDyRu7aKqKSj7IA7A6kqAHTK' + 'RgApzYkHFebiEYN4OYbnwL5yw== sig=DJyEPFFWYsBLXZhuAbeAuGFGX6d1uGdOyMQWfZUxb0VRUHtOqSqnkqxD6MFQCqrCRK99' + 'csxWM/sjzu/ElUEGBA== e=found 75 iterations'),
+    ('pub=MCowBQYDK2VwAyEADpJZkPbMGm3OJGBNebqCWuhtKM9K7GYoummru/XeKmU= priv=MC4CAQAwBQYDK2VwBCIEIPcAlXkRpR' + 'VYcwmciwCGfXpZMhocJ4Su/l8r2kfil4AM msg=tyoG4LBmsMzwLstDhgGON++RjqIxe27QojpSXRLFBU3b2Ipl0a/3f9hpdA/20' + 'eNxNcO6RXOcZApNwXfcGwr+wg== sig=1sTcSr9s6K0vpvLL8r2ha7hf8zLez3rF6EIWZHkktuaJoguKzcfzc27lIl4INnJcDIha' + 'lsi2DROCaYTfDKhNCg== e=found 76 iterations'),
+    ('pub=MCowBQYDK2VwAyEAVF/N5oJKWCGWHfiAslb8VdiCxx5JO7JZZRK4jqeNpr8= priv=MC4CAQAwBQYDK2VwBCIEIIGsfXvUlj' + 'v/gjBtQYZGb4AuQrkdiYfR3auP3wEq1HE+ msg=gax9e9SWO/+CMG1BhkZvgC5CuR2Jh9Hdq4/fASrUcT6+uYYI9C8+sjoyKDeM2' + 'x4RFSmY6SnAhg5qTxeEoxxNbA== sig=AJBypRL1pNBImpqiZF7G6eXNvxWHlAbxwjT+MV1H2gFBsAG2Ym3CcsyHPd0QsqXkU2Nd' + 'enmPGcDcUBjFgXLrBg== e=found 77 iterations'),
+    ('pub=MCowBQYDK2VwAyEA+ia1bvX/7K8dvgMawIcr+MTySXi/AgVAL2drXfvqBPM= priv=MC4CAQAwBQYDK2VwBCIEICrDfb37zq' + 'LPR/skhQQmsGhTmw/zHOfbjmAjGPEW/8oV msg=vE8KZwJ6YtP/+WyzyJWretDzt0ubvZgUtNBIuEcpELCMWfbtTVe23JPMKmjDl' + 'CTdnAtrwDbLqb5FIVEiqOXzcw== sig=20vXY9u8jczxgmmBTTWT8GypkISPYyeudzcBBRW8DhFN/469gCsM7ORIFj+kpdcS36sK' + 'eBqR7Nb+668rdvKJCA== e=found 78 iterations'),
+    ('pub=MCowBQYDK2VwAyEATbYfEv8ed/G/fVWIK6UmJnEo4r1CbWTRGqZLw+HITp8= priv=MC4CAQAwBQYDK2VwBCIEIEYmeASKSh' + 'p0E4i7tcQubwJKh7FXMoQ+AVVgIInCCQv7 msg=JngEikoadBOIu7XELm8CSoexVzKEPgFVYCCJwgkL+07AFp7AzE5dUJa2m57x2' + 'Vgya5fJJM0A8xDx8ycIfCsXdw== sig=kF8val6rPSkqlKCE2LQMY4TOtcuBr+TXHBikJLnaOrJaN3UpdIuENMRZ5PcpQQPaUpbV' + '2H7U7d2Tp4QVCTm+DQ== e=found 79 iterations'),
+    ('pub=MCowBQYDK2VwAyEAbHE4FALgveWrQGocE8gnBau1q5PpS0okUZSNHY06U+s= priv=MC4CAQAwBQYDK2VwBCIEIJT/Ds6W00' + 'gFY7t5Orz8jUbrLO7WXT/XQ8wk41xVeaaT msg=lP8OzpbTSAVju3k6vPyNRuss7tZdP9dDzCTjXFV5ppOAfhGgM/MxuyzejSkeA' + '0JkR/b+9HQh8gOgaA601guxAg== sig=tG3nio6FoZZR9Czx6K25m5qLxIuTpSwBABkek65zya2t/eEVA4117dwB2OQpDssGbzth' + 'vpWcyj4tI551PgncDQ== e=found 80 iterations'),
+    ('pub=MCowBQYDK2VwAyEAlT/tfiwUqJmUvhwfGT3SZzp3fE2AIH40b7r3eXvWmus= priv=MC4CAQAwBQYDK2VwBCIEIHjr+VxWtv' + 'NNPJxbyiqBPEig906yvaR3UkhisWnyyaoE msg=+VxWtvNNPJxbyiqBPEig906yvaR3UkhisWnyyaoEaq+wmzpfZ7h77z7awiRrv' + 'zpHhexuwmR0kBG+32cuoG2FIw== sig=pqy9Bjqk89dM5Vqi9sXWps7gj0K5VZ4TSbE54/bmzz0dQlmrBB3BoLr9jR3lYmQSHGeU' + 'AiOEMF/IFqiUtVAsDw== e=found 81 iterations'),
+    ('pub=MCowBQYDK2VwAyEALI9zvH2ox89t5vAQ3rgcUXiudRR0qqHXSTtqfSrWtR0= priv=MC4CAQAwBQYDK2VwBCIEIABqFXbYOd' + 'PeA7tNMv+mOgMwMULjSEF/ILV7jHyvmmsH msg=SEF/ILV7jHyvmmsH/yenViLDIDsUMZ2+O5OClYh62MfqPvmJfnm5xS0936u+E' + 'ITgSGoFAM01tTz+FhDT3cFZcw== sig=UMMD7kAPsI+lg6IRL/fVfAfTuPuUkuKUHu+zHn4GyDel0SeHm4qeCkDoGIYcqAKUXodT' + 'Ce8HFgGXO6B/LOaFCw== e=found 82 iterations'),
+    ('pub=MCowBQYDK2VwAyEAaluPrsdE7hJvsRlYQxKlJpLCErJVA7oJ+6VBP6ZpBK8= priv=MC4CAQAwBQYDK2VwBCIEIJdiqV/cVG' + '3IhVWka+6RJcg5/Euw+MOb2nvvugLRXZsa msg=VG3IhVWka+6RJcg5/Euw+MOb2nvvugLRXZsag4W/k17xGzCj01czIctEQ2Ghi' + '3mkNlAy0xSx1iI8w5oKxoyYTA== sig=TCG2PI2fhSxKFFdbR6LYTZjQcUl08fphHg8Extx55xT6akJGPSA394JGfXTQ5EmRwpmS' + 'rOc3ctWNg0W8LkzYDw== e=found 83 iterations'),
+    ('pub=MCowBQYDK2VwAyEAgVFBME0lxzYhAT3mMzcN4vBD14XvUE3T7WvkCz/Hi6A= priv=MC4CAQAwBQYDK2VwBCIEIGxbsvPeQP' + '5alHZwIFpJ/zE0VCeDg4UVZNAULW9Gz6Rn msg=bFuy895A/lqUdnAgWkn/MTRUJ4ODhRVk0BQtb0bPpGeSamrYBUN5isjpmzmEy' + 'T+PNLDnDVltWRZlast6wHKCiQ== sig=o0bihdMu3Nbu37kOilhK605/skxlRzmuqckuws2sQsXU1vektNygzTVGplO0YhzaqVRi' + 'aEQ25XyX0E5WInjYBg== e=found 84 iterations'),
+    ('pub=MCowBQYDK2VwAyEADswLfYaCgPTNDo6VABvIVVBL2RYzGsZwRGxD8U8sBmI= priv=MC4CAQAwBQYDK2VwBCIEIF+8551mbE' + 'LCuqvXE8qIYSdQY3xcyUcAJbIBk4E/b1bJ msg=551mbELCuqvXE8qIYSdQY3xcyUcAJbIBk4E/b1bJRqeo4ZJpgVjI+9VWvsp+K' + 'gIO3PHMeP2/MR352QtwkV8Jjg== sig=OK2GAlZ8ktI0sc8DZUWTen91ZodncG4F2GEAiRWT7BMG171Kt4TmpOONC7zxg/CZATbp' + 'QsYjeJbYChOHzD2YAw== e=found 85 iterations'),
+    ('pub=MCowBQYDK2VwAyEAmf8knio0TlExv5yjOXhS3To0t1zTwjqM6WkFCqcgm2Y= priv=MC4CAQAwBQYDK2VwBCIEIAcdGU61Dl' + '6Qm09qZYD8o0Ijd4TstKtRsEnSC1wKseoJ msg=Bx0ZTrUOXpCbT2plgPyjQiN3hOy0q1GwSdILXAqx6glr7GkcJj+5i7A8plIVz' + 'fqdVqcAhIotNFj7urMLHIaNEQ== sig=Fap/Bkr09J2hZmS7MFQiAdQlGdRIxd5UUyf+2j9NCVH1UDW73cCHrYhgQzIYqLLKRDm4' + 'g68XQkDKVip99A9MCg== e=found 86 iterations'),
+    ('pub=MCowBQYDK2VwAyEAZmMMrMIw9N+GEaZ+MlNEJhp02NBmJ0ff5oMAar+DoOc= priv=MC4CAQAwBQYDK2VwBCIEIIDlRkWRmt' + '+LuJ46+mCurmpzSgoMK+giRrLrOoFPfwMC msg=kZrfi7ieOvpgrq5qc0oKDCvoIkay6zqBT38DAhcD3/vxzbq5F211Rh73Lgjt2' + 'kIBQ2AKCE/kZhH4zmhwaO8DRw== sig=FoDjiSWwscc8094p0SEuBLw58VABp1KdO2v7DTxJF8sFJgLBCMQwoKaJh/IWvErAs01x' + 'NO+j5xTzuA535f+KAw== e=found 87 iterations'),
+    ('pub=MCowBQYDK2VwAyEAlFfIiS9RuWVB2EEt89Vwxbkp0qtkxysWH59GajLVnDQ= priv=MC4CAQAwBQYDK2VwBCIEILJ7yOj2x6' + 'u8927a68u22Mn9/jt85RLzZx7aL5wLWjkV msg=snvI6PbHq7z3btrry7bYyf3+O3zlEvNnHtovnAtaORX+s2PwQjBdgbxjPaPwf' + 'SLgxFmnWk4Y5QSONrkg8nSzOQ== sig=yHkgcBJ1q/8SHJQS1mfFicAnez3hLoO9wxTwC320MQVBUbstibJ5dZWQKPQTxZc3nUKn' + 'gOfljHWyQTZmhWQ7Dw== e=found 88 iterations'),
+    ('pub=MCowBQYDK2VwAyEAntmlfS2c/Iy1zr6sZyb0qyDK7WqUWdtsaa1I7CJe7gM= priv=MC4CAQAwBQYDK2VwBCIEIKC9jpiEaa' + 'U9gYJXUt2ZCypHSydp5iOV5U56nFeqaxAf msg=oL2OmIRppT2BgldS3ZkLKkdLJ2nmI5XlTnqcV6prEB+7hLJTfgylcRN+Ng2MB' + 'DU2IjIquzE4oRirt+Anagx9ew== sig=AlKASNgsDM3hZq+yVGgrP9Cs6ut1sqbly9q6V613jrszQxs8G0hr+uEzZlIUMmRPQsx1' + 'MeUWOwVMKjruSIqpCg== e=found 89 iterations'),
+    ('pub=MCowBQYDK2VwAyEAe3onup6XeBxGwdWuV15GuBBgWPMYHypWmNksVjY9T3A= priv=MC4CAQAwBQYDK2VwBCIEIIx4VqqMrh' + '+55Tlhbz04Eu0OSSRkIVBFwuED7hCn48KE msg=eFaqjK4fueU5YW89OBLtDkkkZCFQRcLhA+4Qp+PChHChKuKYO4nuCRoyK/OgE' + '1ixwj7du0TazPZ9vqIX/gxkxA== sig=ZV57Xncn3MBEOzPF0z5O4VNPIJe9NYz8DGjC8MFZAeCdEWPzl2RclqtHzT9wG6fxfXyk' + '2trOYO0UGLYprAEKDA== e=found 90 iterations'),
+    ('pub=MCowBQYDK2VwAyEAMSHRc9b0uFPLiF7PoiOtz3nF9ONP833g/8lGRaeKsEM= priv=MC4CAQAwBQYDK2VwBCIEIISX12XJ3r' + 'epK7/2EMbAzZJQXdU4tNKM9xhehI0aTUJK msg=hJfXZcnet6krv/YQxsDNklBd1Ti00oz3GF6EjRpNQko4draNLxRGDGAcxlGKY' + '7LEJiyFaGCoPptQaKQdg5sKoQ== sig=J5+N17b5XRRe7jYPFKyfgzAJAu7xfkRoY1hMbbqdct5NgjFdgcE+vqB7ygS7OPFnhj8M' + 'emHIWEvoseEgIfL4Aw== e=found 91 iterations'),
+    ('pub=MCowBQYDK2VwAyEA4Qs8/gmbNddoDAJF26eotJ7vXz0eB1kY5fUNdgazKUE= priv=MC4CAQAwBQYDK2VwBCIEIHUOUwvhq7' + 'F/oqKzRoQ5/5JGwmAdqD1Nagjul/xu2Ubx msg=dQ5TC+GrsX+iorNGhDn/kkbCYB2oPU1qCO6X/G7ZRvFpN/T3drIdx9JHySmFq' + 'zxs6ozOrPIl8Z7N7z7TexoCdQ== sig=D0P0GHtEGXw2U4ufZTGQ9nw0u/3KVi6uKeEg9iZug8A4cW3IWEpaTDgsDQiIbQV1G4wa' + 'lipOoGwOEaYgcov7BQ== e=found 92 iterations'),
+    ('pub=MCowBQYDK2VwAyEAaFcWF7so4FDMjXe7rx0Sc8SJhQUiPgiP8+rZnEQqRIc= priv=MC4CAQAwBQYDK2VwBCIEIClbAlg50Y' + '8EgrYktJUhlhagflkXEd3nQTL9sEGFKndr msg=KVsCWDnRjwSCtiS0lSGWFqB+WRcR3edBMv2wQYUqd2u3Y86Iza/ftJtSL37uc' + '7+jxbk2an9WFUgKxr3TE0ZJ1w== sig=Lm6fLEspvqzSHUDYTGqOpkyGkH/MExrYPTaKTJFGwfc1rlgmltD/FZX/3QuDFz2RC3R+' + '61/w4NOBt+5SXY07Cw== e=found 93 iterations'),
+    ('pub=MCowBQYDK2VwAyEAvPN/2oNoXurS+vDYHCbjYuPfXgbe0itAbFhEijxJeow= priv=MC4CAQAwBQYDK2VwBCIEIPOrXDYpgo' + '4GV50wKFxBZ2gzLjjSwGoYU+OLIjrY2jDB msg=go4GV50wKFxBZ2gzLjjSwGoYU+OLIjrY2jDBghVSp/ug4Cd9SfNbTsQNlNfvv' + '49897siFoRH0wL7kEMobwLqTQ== sig=j+FR8fXWQBoTg7udoMiaB2fYii5+0fQHGbfRN5ZdTAnBPjLOIu/60CevpLQZ3wU4xQFM' + 'MQdMR/sYKa/bGKGQAg== e=found 94 iterations'),
+    ('pub=MCowBQYDK2VwAyEARwQK6+aqwEQkHuqHNt4KD2YOfvzd4EDIg3MtE14qHYo= priv=MC4CAQAwBQYDK2VwBCIEIB1VShb8vi' + 'JS0hvqhAXO+ApFu77HOXbJ4V+k/c1JCuRF msg=HVVKFvy+IlLSG+qEBc74CkW7vsc5dsnhX6T9zUkK5EVmsJSbifLY7dXV2dqt3' + 'IJcWmrjjzzyxvo/cxScb+/mLg== sig=+GKFVPRIFUZXl/UVEA7Ew7dJpIIktgJc47TjCz+Xn7d73e7HdYk+SzNO3CAHf1rXsn+6' + 'g6aq14xJ40+sm5YeCA== e=found 95 iterations'),
+    ('pub=MCowBQYDK2VwAyEAsA0JXns6Fdx3PWAPV1YMlyzuZGiTGDAdGVy0R4kfAJg= priv=MC4CAQAwBQYDK2VwBCIEINg1tiot0K' + 'rcoQz5LAWPQi8VUq40bEHOlJIZgrNL1Bf2 msg=2DW2Ki3QqtyhDPksBY9CLxVSrjRsQc6UkhmCs0vUF/Zu03kar5GVOIPS9hcPP' + 'iMPalsG94tTfOcd6K489mSgWQ== sig=5DISt2qCS/TEyxsrBNEcmT0WmftDgXLU3fGZGliQ13qkdcbGfbBBgn5ZynWYjkZs+vWg' + 'Y/aUFJqR1xdrT/jmDg== e=found 96 iterations'),
+    ('pub=MCowBQYDK2VwAyEAyXjgbLtOOWNQTI2yHWwu6wraCx7+SpA+l+MorxAuyC4= priv=MC4CAQAwBQYDK2VwBCIEIJQCZBRpNV' + 'YNKJT2RglfyiZBHqgQNT7p643mWANtMs93 msg=lAJkFGk1Vg0olPZGCV/KJkEeqBA1PunrjeZYA20yz3fjvqNAj4OYV5woBHgFB' + 'oBzBMYNMrQFXi15k7pnan5nQQ== sig=2rVSgYmxPpK5rxcfOJ9KQ8vwzampF6wLOi3bLpeBuWZkrM3c3/00WhgLzxkKT293YP9M' + '9vQWJ7PAaHw0kujmBA== e=found 97 iterations'),
+    ('pub=MCowBQYDK2VwAyEAln54NhyJ/X/2jquXbp76ah/LB6oDIDr4Kd2WuzG67Hw= priv=MC4CAQAwBQYDK2VwBCIEIPM6tBV/BM' + 'q/nT0sGnR1UdDKFHYAEcsWbzbOT7qGHsM+ msg=8zq0FX8Eyr+dPSwadHVR0MoUdgARyxZvNs5PuoYewz7cZ1HatzjU17kcntHRN' + 'KlYBD4S4oYNemfMlI6F6ph2iA== sig=KIoQvdBfc9mxQ0/v4voWTAexNlAUyd/oUqMZWWHIIS/tCMO4n/+d7vkKbseaCKjIjlDS' + 'NDLTDkiGlTvlXC+nAQ== e=found 98 iterations'),
+    ('pub=MCowBQYDK2VwAyEAS6N91+jeeXJEbYbxEBlxjvrFy9hoJzyPWytHVP/CUno= priv=MC4CAQAwBQYDK2VwBCIEIOnlWtKs7c' + 'O6oDUYZdDRupL+rcoDOrnGBNF4DahV3pb2 msg=6eVa0qztw7qgNRhl0NG6kv6tygM6ucYE0XgNqFXelvYg8JqZNeSllXXMjUnmD' + 'Ls3kZ49fXJuEtwju+fN2bV/LA== sig=OLNQWDDTXk6Y20N4L0ExI4tVAghBdEMtMDh61O6s8qo38gBqN6Z9+z9fB7pT75qJ3TS/' + 'cr2gpkgsMJCN408ADQ== e=found 99 iterations'),
+    ('pub=MCowBQYDK2VwAyEAep3fxNQ3AZVdrzzQQh2r6Q6HG72z04tRbF4Y3MaVfpk= priv=MC4CAQAwBQYDK2VwBCIEIAO05+oHAN' + '0iDVfxh6PrV23NHSAG39ic3oI6j7q2zVU2 msg=A7Tn6gcA3SINV/GHo+tXbc0dIAbf2JzegjqPurbNVTZnffJIGIVWmda1asLPa' + 'wPKBm6d7wom9x1aTvC75D1zqw== sig=OwfEYNcZkywink/oki2yQdSStICDGNGDMzBkiwzMT48JZdfFAAJv1MpE2PAltUQ7AKR6' + 'd8ayNAnaB+j2fcehAA== e=found 100 iterations'),
+    ('pub=MCowBQYDK2VwAyEAtmWPpI2qjU8+cuDxey/OeGxfI0HI8YKpTCNph83eQbM= priv=MC4CAQAwBQYDK2VwBCIEILNmVpfQEe' + 'XqAgU3AT/wzVfZKLch2JCKQVo1twgU7Vcx msg=l9AR5eoCBTcBP/DNV9kotyHYkIpBWjW3CBTtVzE8BX9m6gpvPXySqSXM+2EZS' + 'OHdWrqOuAjFl3f9/D5SV51Y3w== sig=Xcvf0aMYrUHrFl++l0AIF4gTFL3+CAAw6JdS2VgGz7kvmgFtI8kY9h0PZ134Zu+8nNVC' + 'vDxW/8nBRdFGPlJoCQ== e=found 101 iterations'),
+    ('pub=MCowBQYDK2VwAyEAxB4rpEdE6bQs2h2EWS5czrD7/EOiLjphE08wOAKyr+g= priv=MC4CAQAwBQYDK2VwBCIEIJ3civsLgK' + 'DYpvKpfXq/VjIlqV84wyWMPQPoG/Z2bPUd msg=ndyK+wuAoNim8ql9er9WMiWpXzjDJYw9A+gb9nZs9R197YzifOxRBzP2IDK6i' + 'EV8GH0Zc00L+TSum1AyL/HIuw== sig=PQFAHZE8iojkwYYpdditN/P40LRB+6JRB5aMWaXS2ZBl8giA/WaN7z+QmvusGZzspIPq' + 'cU3IYxLkpxqiC+1GBw== e=found 102 iterations'),
+    ('pub=MCowBQYDK2VwAyEADb2Wja4KaAI9S3FDjyz27HMJmRiXFM5bW8Um80DuVzs= priv=MC4CAQAwBQYDK2VwBCIEILOzZ+v4C9' + 'bwHglFkhU8BpQTwPi7gXgptY+BRBf1mFso msg=s7Nn6/gL1vAeCUWSFTwGlBPA+LuBeCm1j4FEF/WYWyjP5l49E+h39fGv22Us0' + 'XQq3ZzCi5PXuHHWE7aqzCalyQ== sig=gw+6zaHeASQU1vzZzAMDo0WBWRDKwvYir+Epb3CHCzjCptBbRbkyTezKV04zgjCC8v6p' + 'nTW+PV/JswFnEyahBw== e=found 103 iterations'),
+    ('pub=MCowBQYDK2VwAyEAY+kkohAG8v6XX/g5ehc3qm6uAe2wiPp2JD667ZTUwZs= priv=MC4CAQAwBQYDK2VwBCIEINGNGzJsI6' + '0cXv4kQAXN9lPtkrCAuIOf75woW7D0JOL+ msg=0Y0bMmwjrRxe/iRABc32U+2SsIC4g5/vnChbsPQk4v4Pc8sVc0KgHGRXTam3w' + 'qe2+z89MWV3CwrFlI1WgFepRQ== sig=8oO1Dk3MEb7ci90HGiLr9IIH3I2r3ot706oDagqFB9WMjXiz8/VOrk671sEsAmkEqx9W' + 'i6BR+TToNfrVwaVGDw== e=found 104 iterations'),
+    ('pub=MCowBQYDK2VwAyEAV+eerrwAURGpcHcK0JeGobQoqRoNFwG3iyMszmcpr9s= priv=MC4CAQAwBQYDK2VwBCIEIF+Glnmbao' + 'CNTb9Dp0bB1oThaqV9wLsK7ZZX/WH7Su8+ msg=X4aWeZtqgI1Nv0OnRsHWhOFqpX3Auwrtllf9YftK7z6LF7MaQ/zv/YrcFHLgN' + 'h+tO8pNZNdxTaGHJqF4pQi29A== sig=lvsqZuf9cjMwTfU3UTWpm4F+vdGQfRpB2Vr8821in7KCya+SU9L7O28etc7K6jAehVh1' + 'WhwM89bkI4KhQBOxAA== e=found 105 iterations'),
+    ('pub=MCowBQYDK2VwAyEACVSLzN/JMMBQKViu1fIlHn2OcvUdHLMrIxVYRcik2wY= priv=MC4CAQAwBQYDK2VwBCIEIPGVBkBRaQ' + '5VRcjtx9GYH1QvA6ByaLj8l/OdLmQwN4f4 msg=8ZUGQFFpDlVFyO3H0ZgfVC8DoHJouPyX850uZDA3h/iMs107I9zrBTcO84Nbj' + 'mV2B4pyrgbM0xQDjYrulY2xMg== sig=9KLcuiDjbHlLiTSpHLUux+xeRyUHcwx7xmLjbdoPr/3KloJDSVcJyS/AFxijLi/oCGiC' + 'k0d+IGNSsjBgYWahCg== e=found 106 iterations'),
+    ('pub=MCowBQYDK2VwAyEAjvV5DVaAbsrgVhzuIG2U3kRsGwZKX6PHjZpw/kBSNbg= priv=MC4CAQAwBQYDK2VwBCIEIAysY9jJSO' + 'qH6zsbLOoZhmm4dgoW8F+WaD0tjiPaiWHh msg=2MlI6ofrOxss6hmGabh2ChbwX5ZoPS2OI9qJYeGbELTDkeTTuBIxJkgMmto8J' + '4ZZj1COP1fl42RuDoD1KErE/Q== sig=C7hZ34BoCJM5URpDRyN6sAJubjX6KGj2SPhdcSzHK+fgQViJLuUqn1JXmP3XpHYH/Po3' + 'O1CluRT4ywIjVh3DCQ== e=found 107 iterations'),
+    ('pub=MCowBQYDK2VwAyEAVOUySxyz79hRissjZEL+quwGOxc+AdwFas7VrRgsgSc= priv=MC4CAQAwBQYDK2VwBCIEIKxd3M5fRF' + 'sBy3Fz1cOuUV799FcJ/UvCkGY6KjdhK+0n msg=XdzOX0RbActxc9XDrlFe/fRXCf1LwpBmOio3YSvtJ5MaW3Lb+tdIdsynqxMne' + '1zOt6B+kZIISyidVbf60bMFeg== sig=YmZA7rBj45Zli4gmwHsEa20sEhwSWXrKomj1juUhGfNujwyRxnYKoSt4QjNvlvl5AVIn' + 'nhXQl0dA7hkPm9JIBQ== e=found 108 iterations'),
+    ('pub=MCowBQYDK2VwAyEAZlIDdXJgAnnhHVoNMQWO+OE+VcMAlQHhlQ+x8Hi/7uk= priv=MC4CAQAwBQYDK2VwBCIEIL4S80IGx2' + 'KYQQE1zxQj06ZYpCp2LDr5U3ZzuSrLpSXZ msg=KnYsOvlTdnO5KsulJdmDAYwRIWvfaIlUWSSFTSm2MAdqK5rcTcs5ACqRp8lZV' + 'lB2FZYBoOJ8yfNvzvqQLKgo9A== sig=Akz2lxK2ijLs+y30Qsf0Q6DfQuvlXAQ64zqjcpBZEsHclHzi0AdsNZw4GXaYqwSoCrPV' + 'zQVl+0Ni/mUaXmjSCA== e=found 109 iterations'),
+    ('pub=MCowBQYDK2VwAyEA50i4BEW6p4B1yBk0iCrFGUM0YRzz1A7zbw4v25dhg5M= priv=MC4CAQAwBQYDK2VwBCIEIEa77POdeL' + 'W7Yu5ob0jgT9jgrKS9JSxysD9FSAEhlcO7 msg=4E/Y4KykvSUscrA/RUgBIZXDuzm6v+E6kdQxEC0ip+Ka0CE1Z0A11Y+gv57xv' + 'Mdb4eW0Iz3ggJtY8nfVO353SA== sig=It7Wf+Av1hSsJXU4X9cy2lJs5Hd8xblaAIxkETy8y2AEPoCnkwBF//GtB2HZH1AFzO61' + 'OadpkiiZPYrwKhm0Cg== e=found 110 iterations'),
+    ('pub=MCowBQYDK2VwAyEANkftEt72NPdPk87PrASjacXTl6PavTzAwx+JnyZKRJ4= priv=MC4CAQAwBQYDK2VwBCIEINgCmCrO9v' + 'mG172MlaQL14QlI0h7rOhTrAJ/bIL59Bn2 msg=laQL14QlI0h7rOhTrAJ/bIL59Bn2LlnYtukvEZDmGNPGCwbOjNrxSz5xh8R4k' + 'tueccMEdqLsymc7VqrhfRFL1Q== sig=ekz8oTUmcj8E/7JkKmz3jGPn4A/Vzo6IXs1Br8a40f81PezLt4fg4AET8yKnflXPLnIx' + 'svWMFf75kcS/MZQ9BQ== e=found 111 iterations'),
+    ('pub=MCowBQYDK2VwAyEA/4riYc3bZpCPbqWr/xhgHMI+qLvApmqe5oxKC8HAcps= priv=MC4CAQAwBQYDK2VwBCIEIBlCc9I42R' + 'FdUSpapkLcZRXZmS3IQkbjs0eD4TIwofO+ msg=LchCRuOzR4PhMjCh8755nw/BOYJpgXD0ylEIsBZZ62eq+tgCglyZYIpN/94Cl' + 'wRS/9xi3A5NYNPNz5/mj/TKNg== sig=/Ybq0ft2t16ji2KqGfEnE6nDP71VToLc9X7V2HHnq0CVW+hcJPM7TSmsTPFu7N96jCwa' + 'jpZnyK+69JaKcOhVCg== e=found 112 iterations'),
+    ('pub=MCowBQYDK2VwAyEAF4l0xsXs4JpegvWBwtYSvMAW8cxQ6wtoVHKj/ljLk3A= priv=MC4CAQAwBQYDK2VwBCIEICKG9KtMFN' + 'm+NY01HdZo9vfocfFG8z6+ZIbVWIDGRr7E msg=hvSrTBTZvjWNNR3WaPb36HHxRvM+vmSG1ViAxka+xDHPNQm/wQmlAw0Tm4W5b' + 'aDGnRVWshIoFi9lIYISeU6hDg== sig=xk3MjjaQ8aWi+pYS7iztra/l/Jie1/FrCXMP5J4FtQ3Zplm0BNJ8xxOK3GbsajAWIrtJ' + 'T39r/N+IQUh+ZJRsBQ== e=found 113 iterations'),
+    ('pub=MCowBQYDK2VwAyEAkzgho5/z+HviQDIY9bkPHqyXMQCiXRrIiQCgXRkwqzw= priv=MC4CAQAwBQYDK2VwBCIEIOlUfDbMqv' + 'NWdgLVt7XbebmEeAUpE0iaBTNiwdaqIkF5 msg=fDbMqvNWdgLVt7XbebmEeAUpE0iaBTNiwdaqIkF5jlsgNDGyTJmnvIELx0Ait' + 'TL/hcFhNVwVY/vnstmHvfYkew== sig=TziR8PAa2Xnuk6XixgTSX2arI/9Tq3wt1rjc+5hUI/iVtAkQHRCpv6CYZlICBMuT6kgh' + '8gaPIvHgjP6yPW5HBA== e=found 114 iterations'),
+    ('pub=MCowBQYDK2VwAyEApI1F6sU7qwmXHxGL7dtf9tu1XyzAzwi3ssF37Jf0dSM= priv=MC4CAQAwBQYDK2VwBCIEIIw6ZKX5nz' + 'KL5PZv1q6cTsfa7eV/yP/CLCmyxIklP/wd msg=1q6cTsfa7eV/yP/CLCmyxIklP/wdT1sYiSq89jwR3b0hxERp6yU/itMNA7rC7' + '8lZjgQ9jOaZcoWiWkJE+5k5AQ== sig=DD17y3VKQVgikhAPgFWMZC7Hyx/tKg069CvoRYfXOfdR23Vq236SH6A2JcJPuXD0eNnK' + 'WVLit0J6HPh5eFgGBw== e=found 115 iterations'),
+    ('pub=MCowBQYDK2VwAyEAjlAWDsH7LRj0ZAUIVliBHNtrsOtTzA3vcvvaYpf2d+I= priv=MC4CAQAwBQYDK2VwBCIEIEc2T1fCXG' + 'z6QwLmlxyUzobRp0ScJTBIvn9nyV/dnsua msg=eXtSnxApDQM4oGuHDCKDnWHClGqMYRdM47wRgdiagdeHuIGmgqTCs2HbGJ9iQ' + '3xzDKz0bA28/ZUKuECC3v7VIQ== sig=J1aBRj5B+Vkd3Fns7HjKvLiROS6Pykf1NXogsGfzqYEG55wrsq84J9WTNxPrAI67XHl3' + 'V0XQJhrcaQ6vTVYIAA== e=found 116 iterations'),
+    ('pub=MCowBQYDK2VwAyEAx/J338CWREzgr3VDj+SYEoRkufWma184TOstM64JIvw= priv=MC4CAQAwBQYDK2VwBCIEIOwyhIb6cQ' + 'vGuXavoAP2bNZIMrkDGJqpkz/rwLkwqYE5 msg=k5jbL+4bGuCPkwlCPujRhoAMsLTVgDXLBR82linwu81mMkF//K7mjshaBUf/6' + 'RjwM1ahvsMeUrqYsA9N8ExVBg== sig=7eWOr0C48A0FSRz6ERZGV8BoAV77aIH0vLErlozjehYaOqzB2xBN343ak337DncVCQFm' + 'j1O+zOXc+oE5kH1AAw== e=found 117 iterations'),
+    ('pub=MCowBQYDK2VwAyEAsV3ow8DVlcbtSwNq02ifJ95G4MdPUJ7r1FmAbhTeX9o= priv=MC4CAQAwBQYDK2VwBCIEIEDOhJN72N' + '9SVZZEvhDoRNif1ggDElqVYpusx+rA+Twc msg=vX1KKcCsAHuzAyNwmLQbj1hHdu0xYvraHvhhUtLdwLjYriq8oGpktEsXe0R6U' + 'rrba4/dgoiJrg3ZswQ811Q6vg== sig=zsaQwF1jX0g+1zqOE2UqKFGIalFWTITFycgcSPy0RrJkSwrtheMTxbKAQ0LzDTkJihqL' + 'BfCXu0wfO1Je+ixeBg== e=found 118 iterations'),
+    ('pub=MCowBQYDK2VwAyEA7dZmMFlNTWPWPZgCgWX+GMEIwweha45WyeuaJEScQEY= priv=MC4CAQAwBQYDK2VwBCIEIFJXyspLbX' + 'Kewnvs3oEa9c62lm+8n9Dmtx4KxQ+Ohnfz msg=2U0jfWaZXC71/PiaxinTygfhDkjwCnVIcFfwiTnfm317zs+awCOx/0wvlH3AE' + 'JHOl+fwTLaOd3DupZ2LiIQ7/A== sig=rxa1s40iO/DgWBYElFPWzOT1/vRWKu92h7a9LlOthgAlPBoeOdZKJCI6uIJegVlW0vgk' + 'CcHXf4rRc7VomPuvDw== e=found 119 iterations'),
+    ('pub=MCowBQYDK2VwAyEAcKGYlao5G64KfCrn0rxhttE0nbyj9bmXNNHIpmt8Fgw= priv=MC4CAQAwBQYDK2VwBCIEIE6pRyNDgB' + 'X1xzVpC5QXW8I8Y+AQHBx31V1TieBCwZ0q msg=cD4WTqlHI0OAFfXHNWkLlBdbwjxj4BAcHHfVXVOJ4ELBnSpWhuYSQwkKA3QTl' + 'dz8H8IVK2J0k0qtv8JDBa2sjg== sig=gyd+gBQhXu57ixVnwzgt7Ar4rC51pduSmd6EdLLZgPBN/zXwxsLY92KjALsXoiy5I2BK' + 'NHbKaLaA7E7eWz5hCQ== e=found 120 iterations'),
+    ('pub=MCowBQYDK2VwAyEAiOHKTeVVFdSn1Cb5GaOujy/ZiKKK5JTx1rOoyH2hZS4= priv=MC4CAQAwBQYDK2VwBCIEIPr6hfTbh2' + '4/qN2LTEBmsoO+O7LXSGOEnhccKGkQ9xao msg=HAZszQIBEZX3T956a6X2qPnpL18/UrgMqG36+oX024duP6jdi0xAZrKDvjuy1' + '0hjhJ4XHChpEPcWqLr3EgEh3Q== sig=XK/tnbhmjUuP2zShxHthiNTDdMpnxZDBVV3DCSoth8CoFJpm9j7l1m8RP2DkNBOk7N3C' + '1eQuYX7Xtmg5Dqv7Dg== e=found 121 iterations'),
+    ('pub=MCowBQYDK2VwAyEA2fYktkj1ov74JQ3ziXQGIEBu69ZyNK9HJXcwOjORB4I= priv=MC4CAQAwBQYDK2VwBCIEIAXENRxhQH' + 'qF2NsgH+Yo2M4j2gz7T6CE8Ti5gc4lwGmz msg=s36EjclDkM5ovsjWHnTbQgpRzBcOToob27OFXDMvthJ/Wkiuujtl9lBpQ6BS+' + 'LcHAN8A+1Tdg2cAEM4kf78FVA== sig=5HL+dmVc4FnY5fxYQYh1G3EQ6mDvVmnTvO+0VrAGKT0IbpO1rzfE6s59tRIOlwegK1tw' + 'o489j5luttd2kpw2Ag== e=found 122 iterations'),
+    ('pub=MCowBQYDK2VwAyEAxgIbd+1KO+EwLcNYV0viNHISlJ/yMr6ejj9o6bZZaQg= priv=MC4CAQAwBQYDK2VwBCIEIIcxnu/B3y' + 'e5/U+gErU8IEiNJ6hKwrZyIXHAxl+IetKa msg=iHrSmjW3+YWb0eieg2VzaEwvLYfQ74WpmNx/9zzojVyyDEmzxba1RvJELvN1g' + '1tiGRS04X7tMR3V2zC7JL+O4w== sig=NC5YeGcd9z/2A82B1c8a+8/gzFURMBr/5wDhFWgFy+dAOE9o+9JplsxTKgEtYkB20na0' + 'X89fyiuU0i7/TSo5Bw== e=found 123 iterations'),
+    ('pub=MCowBQYDK2VwAyEAn328lpY3CdJ7a83KonTKMTHTaUZOoVVow2eDGvLQXU8= priv=MC4CAQAwBQYDK2VwBCIEIHvvqFTxw/' + 'O9Y81plNuGexhSqOUCAJX4wKy5G/RSYE6S msg=QTALCo3mn6sfHr1J2wA6E+KSSBY0jgnO96RGVWsbAPmge++oVPHD871jzWmU2' + '4Z7GFKo5QIAlfjArLkb9FJgTg== sig=GyNNRaiV6jBM/Un1moAf6+9HoG1doryo8EH9ozNAoIIKhzOzBcXL8K1Yyxw1ikzjhB/c' + 'thvad5nIqCnFy/s/Ag== e=found 124 iterations'),
+    ('pub=MCowBQYDK2VwAyEAODcrDW4/Tiw57u4yH0GaqlbMP/CNb5xYJBtWSPUlkhY= priv=MC4CAQAwBQYDK2VwBCIEIBWmfL19HX' + 'VaNb/V9YjvUD4HlTXbAOGJymU43nYSzYbC msg=xNF0lcWH0tr2cZmfb86bqLDM4sFtpf/j6DIOCZw+rPR0vXBz3opqS9QqBoZrq' + 'xu/HnINC3vMzbBcfVeA1fJapA== sig=CWdE2P+RAySVsX5RBZRFMdPMVzW6Ll2OqMMrbxY1uAbXPBrPhmCTKzyXpkMQYse8p6PQ' + 'L8Q8Nisk9rpRG9JcAQ== e=found 125 iterations'),
+    ('pub=MCowBQYDK2VwAyEAeMRPfeY1/Ej07VytXhsMqcknQhs1D4ybys8KoGdEcl8= priv=MC4CAQAwBQYDK2VwBCIEIAeBzvUPjV' + '8+3MvxZy6vb9+fCBnLp1OKntl4jx6/M4iY msg=zC2R+O/dtgeBzvUPjV8+3MvxZy6vb9+fCBnLp1OKntl4jx6/M4iYj/zoYHQFK' + 'jVp1BhJc2ilT61DqWc67lf2+Q== sig=ZwHxu+72a0T2XCU6ofoZYytanTGxubKpzE7Nv9sdZHmJr866/Mp3z9NT53XbdokbyR7a' + 'oKWwUk+MxQPD7BGUDA== e=found 126 iterations'),
+    ('pub=MCowBQYDK2VwAyEAmIMQFNgNIqtEFnAL7UUKNaVkR4pq/U1oqd5hGru+A4E= priv=MC4CAQAwBQYDK2VwBCIEIEjc4Yp+7S' + 'viDjcpVR6F5uRGECy5PD9LIQO51zhba696 msg=NylVHoXm5EYQLLk8P0shA7nXOFtrr3pbRCAQOXYem+Reei9u7svzNxid0mYSw' + 'w21HFI61av2xcnLVtAj74vCQA== sig=qWIwPgXSyQC4gvQ3EA59Kc2lolXXX/CJQ3m05SqhXUVCVxMR/QZbHuSEOJdNS6sOVAU6' + 'HhQxCsOKlJn17EHOAQ== e=found 127 iterations'),
+    ('pub=MCowBQYDK2VwAyEAYdHTU+z+QY9yPjN+5AL1GQueMSCy1rx3M1d806OLX30= priv=MC4CAQAwBQYDK2VwBCIEIDrZHcmlda' + 'yL2KAfqJbBoNH5bUiU2V/LQZac6W/q8LKu msg=bjfcDqqNdm3usjrZHcmldayL2KAfqJbBoNH5bUiU2V/LQZac6W/q8LKu27+Lp' + '9HyICeAqccrC8CwhFWgmJcEYA== sig=OCPtS11eq67EU+Y2ZicrzgqTovsqq5Lb5uG7Tk7mpAQbAxyb02Cm8vFIJ4cnSfMdC0Ps' + 'gdhPORgf9irGdS7/AQ== e=found 128 iterations'),
+    ('pub=MCowBQYDK2VwAyEAUyRbp4YiA0rm50jzBL33lwnOjARoaHdEXNn40NK0P/o= priv=MC4CAQAwBQYDK2VwBCIEIHyDIlRjqb' + '+Sb6qLHx2L3Hy5suUruXKJ+tNB4gnnZBTB msg=fIMiVGOpv5JvqosfHYvcfLmy5Su5con600HiCedkFMF37opZtphHd9PZKZD8B' + 'Ku8dBoCxA5QvuASqYFeAI1heg== sig=uGHxzBRY5tN2as7RjVjRQEq1iEs0wB7Vqhb4hdj40T065HA2rh6ce2atRq5pUi1cMXEm' + 'VkIszxozWcMfHUIsCQ== e=found 129 iterations'),
+    ('pub=MCowBQYDK2VwAyEANKGfP0zeLPFc6hEt1VvkjxTJchfDMXRzU2YKz3P4zBg= priv=MC4CAQAwBQYDK2VwBCIEIAepORePNs' + 'eu2WAOKT27U51DbmCfCNm/uUAOAvPUHcjv msg=ovhoXmGlzVfukw0cFSDcFjyyH3wusPP63+MHqTkXjzbHrtlgDik9u1OdQ25gn' + 'wjZv7lADgLz1B3I7wSr9+aY6Q== sig=XSeK/GK7VjgXQaEAJZMQxhLho/Vk6GrqhNzjlNGRoA3n90TESPaB7jgETupaMPc/7tW3' + 'ajHMes0brN/gowmkAg== e=found 130 iterations'),
+    ('pub=MCowBQYDK2VwAyEAEQzJXljPO6he8KgNb3GstmtJf2KAt5rvSS/pg8s/+18= priv=MC4CAQAwBQYDK2VwBCIEIDauwah1wG' + 'Bxy4j86YjZa69dfNrzpAy1tH4xFx3PszT4 msg=wGBxy4j86YjZa69dfNrzpAy1tH4xFx3PszT4w7BFTMFYjJ9js0kgcNW8txOfC' + 'Hatw9dtMNKHpxwUqkLI45l+iA== sig=HnIqSJ8Kec5S9ByX4VJfpeDJpToLJ6Q4kHns/2ClxL6gG7eN6wyXueIgMIIcEKccToIs' + 'JNTcbJ+qkSyEk+0VBQ== e=found 131 iterations'),
+    ('pub=MCowBQYDK2VwAyEALusS6fp6G/FtPYCNWOTFq1ISq8V3TA0DSmN5ju6a2+w= priv=MC4CAQAwBQYDK2VwBCIEIHB/Hep4Wz' + 'nYrotW1sfMtxR+uOGbP15iJ3NchMKlxRT2 msg=w/D0I957dumGHAI4tvnK4HPDn60VcH8d6nhbOdiui1bWx8y3FH644Zs/XmInc' + '1yEwqXFFPZ0C7b4faU3iXLzmw== sig=8IDG4SVEnUOEWGA5mwEBJKFapSbplFOSgpCzONUVsQr/XicA1pIxVZJhd9dB8m1g2qKH' + 'BBI3xBICbff7Ja/XBA== e=found 132 iterations'),
+    ('pub=MCowBQYDK2VwAyEAxfj1xPSyPSoQ0snOT1ez6MpkaD06hzSFubwh4H46Kz8= priv=MC4CAQAwBQYDK2VwBCIEIJz7YoGp7t' + 'ZssgpFv4KVWgCoN2QNjjZMQiz3oHQfXfXU msg=wXiQXg+Ul950ZJPaMWBHz9TenPtiganu1myyCkW/gpVaAKg3ZA2ONkxCLPegd' + 'B9d9dTbNJRHD0FccCMylNgtLQ== sig=2FHnSc+maLipWVXC8THY8D3WAbYAdnJa/ZDe9Z0uoqscna7g/1MaC8hOYgbngB9NcsPh' + 'ELKnh7MfahboI2ZtCQ== e=found 133 iterations'),
+    ('pub=MCowBQYDK2VwAyEAN3sM/Rxz1hYmLZL76OsjkTn6xZw3Y2imuoIWfxONklo= priv=MC4CAQAwBQYDK2VwBCIEIGy19HsQGb' + 'zOdOqudIr42F7VQyPcSdJseqhdWZUJUsLE msg=x02f55Gj0W2wffYS6eqhS4ft2wZ+1Ps+Nz89SkhZK95vXF+wWOD7aa67J5rxv' + 'TPnRKT9L4IWi4GH2mviIjNfag== sig=6wjgs9WuiPEKBYL6AUoP5c6z1m8iyMH/5gXeCwjYyXy9WJvLIlWaDno+cax1aUPNZbz+' + 'pt1G/G4MeYOJBP5YBQ== e=found 134 iterations'),
+    ('pub=MCowBQYDK2VwAyEASNbA63RlnLdSyuyBF+WFNohFKJ9+F4wi/FY4l9JcVKw= priv=MC4CAQAwBQYDK2VwBCIEIBxK5DAmCz' + 'NQ7Iy1GhiyCqgPE7swenOzB5iu7vsQ5YvA msg=SdlbWypKKps5ujzrT4Ioaj1O5KKHWDgv/RNSDP1MMdlGuxCxwidgH8hqkv3D5' + '41+SD7NUbF38hBaHWKwEi4xTA== sig=F6o/H61xcySsNdqmF3r+p+HF0E/vajX7Rk377h0Qr09fQeOlqPLNf6KPy7akyyvdplM3' + '7QyI8IEJIBbjtQkYCA== e=found 136 iterations'),
+    ('pub=MCowBQYDK2VwAyEAtK2N4hAzgo8jxf70zrdyhXjBNIDmQrQveJTceGOuawY= priv=MC4CAQAwBQYDK2VwBCIEIJlsnKHDv4' + 'soVPN5eKAzD8HjsUvkZBo7G6rLraONtxgO msg=eXigMw/B47FL5GQaOxuqy62jjbcYDkNI9YvOPNlpxiTM4zPw7CrKpunaVdCx9' + 'to7mMmJUNFUhdYclMbTTB9qVg== sig=5acadnBTsnNcpS8qE/OAORmo6ww5PMa7puoaC4a39TcAIKx04Mz1hJLDAzK3Yt4l4080' + 'ZE5ivIKyQ5BY+tesAA== e=found last=7 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAA0KPeFKAEZc5+A6xLb7/06poKa9xhKKXpabhhSxh7zo= priv=MC4CAQAwBQYDK2VwBCIEID5GgFmIxx' + 'd8E30MYAAAqhto5RY9QQpvOmZINZcTUsJ2 msg=PkaAWYjHF3wTfQxgAACqG2jlFj1BCm86Zkg1lxNSwnZGIwnDSSdBpU6qWcefu' + 'wNGgKpOHtHO6Smviq7hnpzXiQ== sig=7sx8YX78+QYt9eXmP0XRcOkrlHLa0FkveOOBwdMll0mcgcJEIu8sMuRZa4BcJsfvLmaS' + 'dLQ2BkZPLTPP2/Z4Bg== e=found last=8 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmnIcJ/4T5M/31gQnujbv5h/T4ccJOW9YSJwUBYw7ses= priv=MC4CAQAwBQYDK2VwBCIEICsx3yGMG5' + 'FHTtNynjHRd4D6PvunCas3DU39ZxjPupnd msg=KzHfIYwbkUdO03KeMdF3gPo++6cJqzcNTf1nGM+6md0UiT8yZeWQQLtF70i8C' + 'U99Ty2NgAemjkIYgDzdi5Wm6Q== sig=y0HnMN953kniqWlt1yLE6eJG3YuKCRPCQmYD/uuXkGieJoSLmfkrUn+o9bPCJKAftKbW' + 'bj0B+MC06CqICXBsAA== e=found last=8 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAuxOmF36g51Vn21r7uWj8Eg7j79UhHmaZ2EhkJ3GFYds= priv=MC4CAQAwBQYDK2VwBCIEIJkQm0JsPd' + 'i4V3NJ+uxYAPi6IBnvxnfBMAGNy8ofxreV msg=mRCbQmw92LhXc0n67FgA+LogGe/Gd8EwAY3Lyh/Gt5XvUX/5+BDScGWCHGfgp' + '2pHNLmWi92CIBJ9YABT26j1xg== sig=3cndiSbcEmKDPfC/8ExTtmbZfwPp8OlzeL9zqhlUP59++HkvxabP0lnsI41r5mve2Dlp' + 'bl8D4kOw1OmkPwOyCA== e=found last=8 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZf0og+I/2mW153yMsTAsX/I8qATJsbYgL3uCIp/EiDI= priv=MC4CAQAwBQYDK2VwBCIEIKc3ng3JGh' + '9fSnc97IthMq69vrYaDjzAa1wDlf5lSKBm msg=pzeeDckaH19Kdz3si2Eyrr2+thoOPMBrXAOV/mVIoGZX9zRYHmYvYB2TdK6Eb' + 'ZlEt3MWRe4ij1Ly+5XsJR5CzA== sig=S30dCRLlVJIJl2YLDOJ1gu5i2sErbS0ufQ/18l9SwLnO1V7cTjHO0z7+rxlS2sn2YVtR' + 'ReRk2/N33fmYy9cNAQ== e=found last=8 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhDv5qOwezFXaBQQ0dn/UoHaKsQWQ1FArc4Gv7hdyE8A= priv=MC4CAQAwBQYDK2VwBCIEIGfv99hGFw' + 'hBJ7XaFOJGzINufKOcSQvLqYjd1LLYjeCH msg=Z+/32EYXCEEntdoU4kbMg258o5xJC8upiN3UstiN4Icu20Bcw0EJ3VAxUx8dk' + 'p1dW84+HgKjLKWlJWIfi90uLw== sig=PAoMCOC5QaSwIwYUJ+cLJbRZIh7nF5D6Q5f1LRJ0QtqhBs8uanPU1XF3ueevYQGIq7im' + 'ZafTzylSzuonEpy5Ag== e=found last=8 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhn0RQrj2+s3kdX/Wjop/hJA+e+rGB+WAqiA7HiCIp9k= priv=MC4CAQAwBQYDK2VwBCIEIJJ+gl9Z6Q' + 'oYG8BjDe0YQWFNnUnVpjQ6+8ftbl/YBxxE msg=kn6CX1npChgbwGMN7RhBYU2dSdWmNDr7x+1uX9gHHEQ/1aU9jUBPOSoInnYaj' + '8uOwB5dQsm4IUENw9VTcGMaqQ== sig=XtnSZFQI4EfWsz+HzmoOUda2lgXy2kiayo8uI7x6Ry+nF+SQOk72+I44hLvkzoxDLXhp' + 'uUWSTvAJ0c/JkNOHCw== e=found last=8 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/xPic7Gv+VybpXpXcDvnLY8O1GURIS+XYCNI+ZcHEgs= priv=MC4CAQAwBQYDK2VwBCIEIDEv8hQTnE' + 'zM9jDBe/mKfTUpa83oBRyYjHXjJEYLXIY7 msg=MS/yFBOcTMz2MMF7+Yp9NSlrzegFHJiMdeMkRgtchjt3YFbSfSFGFgwPt6/8I' + 'MeRci1VklvlqwouDk9UQGCL4Q== sig=XOfZWpLcy/j5W4kd1fTjyDww4oZo+Ma/H+Ev313I+a0gH8iX0cNclElGZkyGgcArgNcz' + 'VR57+FS1t6Fh+MY3AQ== e=found last=8 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAGYtOEebYKoq40cwB7mQ25w+hmRojT9v/3OzuS4ByWwM= priv=MC4CAQAwBQYDK2VwBCIEIKxEm8cUl/' + 'ymjrRiHW8TLDkUnZFy1OLhnjWniQ+sEvoe msg=rESbxxSX/KaOtGIdbxMsORSdkXLU4uGeNaeJD6wS+h5WHuD5Ho/2zH9NkWfpR' + 'aLEnn7SRFvKZSD1U6+Nfnyjew== sig=2e0GLWlKwrI8l6qRvrlUQ2awsfftHGO0WwwyxMK0dWU1MG8NfPIZ64qs8T3GR4kxFJiX' + 'WsjH4DnMpgC1DOMeCg== e=found last=8 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9M2wf7buDQGPqLWIDX596fvR+hvbWOU9NUTd/WsAXig= priv=MC4CAQAwBQYDK2VwBCIEIDbjwhJmzM' + 'to0RDL75xJChRXE1QIj2/q7xbIr9HmrHak msg=zMto0RDL75xJChRXE1QIj2/q7xbIr9HmrHakMsRzr9P/p5iH3pV3XndY2cecD' + 'cvpxRcnGa/36zm1Q4Vc2fjyLA== sig=ozhXIpDtjoWMb3y3gXpMF3EoO0brOkNFqlh39UvXGKh6DGCsEZkP0laoOa9CmSNsudW7' + 'AWHFpuDGb6h9TD+BCg== e=found last=8 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnQlX1byz9yXLVplcKH3Q5BVWiEr3/ciL4UTJMh05vME= priv=MC4CAQAwBQYDK2VwBCIEII0XSb2W/o' + 'lx0iwraXP6BIHxSpJ6ppd6zAb3pxbo7Vcw msg=iXHSLCtpc/oEgfFKknqml3rMBvenFujtVzDd0l80J1BRzbc+g3sAClERq1i9W' + '6Lf6p5Q4EKXrhHo4jDpdO1t/g== sig=D32gwLV4Ct9RTKHshmhyOdAqUq980il27KJiIVpEIbzCCN4Tu/Ot14CmqD3DrMWhySCE' + '92mE/OEM/JEIim97Aw== e=found last=8 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3lj7c1xVRL9GifpF0vbVzJhA2W8DM6llkQ5pQm37ICU= priv=MC4CAQAwBQYDK2VwBCIEIJ+CGWFDgW' + 'BD8aHfwm4G3j3S3oc7cOoloSA92c4y0m93 msg=2c4y0m93SRjJAxs/lcmXCFEh+lA8iBT6cwMOPCM9aom7Lj4g4wfaK/EJzl3ih' + 'LZUCsfTGb2FVqN7HKI7QjpzTA== sig=Y1oBzCgNMgOWCDCJCtofjPdG+MJlxiovz3dewzZlEyD8CgU3Veg4PjnZf0/XTyqqbtyj' + 'Zpe6H4xe2LPuNFRzDw== e=found last=8 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA7e+dmJxL+hA8MSGvJmWeXY5QO36yH48Ej3D1qXAB9hE= priv=MC4CAQAwBQYDK2VwBCIEIGTSzmUPgg' + 'VaGDOeBRYH+HUAxmUCd7oNOf6EZIQIArqX msg=ZIQIArqXIWigmeFdfQlOczuahBjTmQpZlCRflabFX8a/5SkXuQsr2j0RneE+g' + 'JsfQwmlR03ypvA8hee7vbgvhA== sig=Z6JzeB+7R0rZUIFBMrlVRKdZHnZNWe35zDnDvUaI5oTfMqotoODBYv9nVs8fhhGNWoI7' + 'ER581271kq0uaf7CBw== e=found last=8 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWbBZIPRGne8NoLilzqGt8t5gIwN+aDV3dtwXlsavt/U= priv=MC4CAQAwBQYDK2VwBCIEIEzZNwhT/2' + 'z272OB953mXMqvSATvi+QgOEyUtfnz0Tb/ msg=m1c7O4i6RapRT/4r8a8paR/D+Y2Mwd5MEfd4+JMcKIeNSAgT8m8bL9xdKLREQ' + '47U2RHjJ1DIsQcjmcsAuChn0Q== sig=5mbvX2i2thc3177yXObrD+o1Azy/+nAA7zugs2UBgT4Qe+rrPW5bnYm6PA5le7+dR8x2' + 'AX2QlAo9ay4qciK9AA== e=found last=8 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAXNaMG6/QO8MW7JXygKXAC1wTiqdZFEMJm6VSppHEYzQ= priv=MC4CAQAwBQYDK2VwBCIEIBCXYtkB5I' + '2zPtAEgbtSuOod2OBTbl8lqonm0uEd/Vsw msg=zQ77IZHxLLtgdfzpej4P5z+ZyWfO7vtQvgKOYbO22M/RnnWPu9aQNYVIc6ceU' + 'pnIUNW0SBEBBbUD5k2rjJ8erw== sig=twCxzMDHJLDyD55Emi8GhdHQGBmMw1yc23DhTVQLVFvw82Cd7c3LxhtywMmtrjOHkiF4' + 'tJnlXvf0MvWaRXlGAA== e=found last=8 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAeXVWB9eA9kvLwcseA7WgPni/V3Ju8suZrgVA5ny5DZg= priv=MC4CAQAwBQYDK2VwBCIEIOK2CDCISO' + 'XlLazxVdFz009cXMHhMZoySakzjEDeojjs msg=M96mO8n+Tlu/bMKVR2unmeK2CDCISOXlLazxVdFz009cXMHhMZoySakzjEDeo' + 'jjsgsSO4WHhDl9aYS48VaZjAA== sig=qOFKE+ETWR/Ji6oZBsFFFy/wSss8QuWvuyp2C4PiDS+IShrikZeOycQnYJa1AvuiEwAX' + '8+52GiRcucgq3BIUCg== e=found last=8 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqjlMWK/99AfUyCCN5nf6y1j1VbTSfCW2N2tDO5u1YA4= priv=MC4CAQAwBQYDK2VwBCIEIOcsjKsvia' + 'KhOp9DnkvWydUDgvdaVc3gKduAIoi+yP4d msg=S9bJ1QOC91pVzeAp24AiiL7I/h1OQL/3vosVSt4pzTB3Vhezar+q00i/KEuG5' + '4xdkouoVBITo5mwITdut8198A== sig=j/oMGa4uQKe+esk9qT4UgVtC0i6H6MkKg+etalg+nkJtplcyxH/G37LLZt8BjgiKmTB0' + 'c+MbpFy4+DuZhl/rAg== e=found last=8 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWWmXyvXKwlqbgc2YwPfCnjFTInMvfCMe4oscv+e7Qrg= priv=MC4CAQAwBQYDK2VwBCIEIOnbl4xnhi' + 'JKS8LxEiXgMUXP3PeM1sRx8LWPkfqoWrg0 msg=mh+ELRgCFk8vQAVSGQWzCk/GRUK+HXIFdgf6vwle+6xDALtcN+n3QuOdUIuvd' + 'DpTdXxA+oxQCUgehjCveNPTTQ== sig=ftdXyEV9fAzdHJJwkPS9e2OgD3Q0oidFj+2lb2juIn7F0rn19bEAY8aX+2cbBl6wOJdU' + 'AdBibHbDLEpmnz1fBA== e=found last=8 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkYwNXxIjO07/jOzUKfwqa5in9Npxv1Nq/AxM1iFy20w= priv=MC4CAQAwBQYDK2VwBCIEILwQkUC1Rz' + 'qHYKebQPibHkCWT/TJDlEMV5sRZIeiSQYx msg=vBCRQLVHOodgp5tA+JseQJZP9MkOUQxXmxFkh6JJBjGixD1uOTGaZWI/wng1Y' + 'S70HNsLXLh+iJ+1Rdq+x1nm+w== sig=hpFMkzvbCEsH1gU+5kh0UgX4aZhZaGJaWb9p0UwlMo0Xu14VdFlG7B3Ep//KKmnBKJF9' + 'vQNrbq1Usz17w6QHBg== e=found last=9 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAV02+cCQrM8L4JKFopwC2Irk/r8IvdTHPFsSpIk28BqU= priv=MC4CAQAwBQYDK2VwBCIEIB0WJu1FrV' + 'CAK6qDO7TeQ6XwTnrE+v8o5icfZc5B+LPa msg=HRYm7UWtUIArqoM7tN5DpfBOesT6/yjmJx9lzkH4s9rCrJ9F08XlZpiw9qaxJ' + 'yXkkWZy9NjB2FgQuuYLfLKjvg== sig=2Wk/i9ez9AHXNU0nRxONp4cXSTE/bvGLuz+7r/wvMeSuV6giEcOI96dj5dlhkZDOMVo5' + 'eGV4lRm2NwEgpscEBw== e=found last=9 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAa4KfKBqr6aYogm4cGelwOKZXt5IoLmg2LkgOZ6MC2dk= priv=MC4CAQAwBQYDK2VwBCIEIO3itNpDAh' + '3vqm+3KL+XYL4JEGxKrnbtTLQA9jxLkB3N msg=7eK02kMCHe+qb7cov5dgvgkQbEqudu1MtAD2PEuQHc3mk3frDhDe792tXRKhs' + 'a9c7AGoLmCdN1TXkeBYMhZ97Q== sig=lASYRIYV4FWbqWpPskbBOuqNYxAGXEDp60ZqAopAOo5dO/A9SluLLC2X6BSJmLgjRdlr' + '0/ycE+XxkocXlIhuBw== e=found last=9 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9pByVlq/HxICKK8qchUErWL/krcCSX+9IJkicy6iG8Y= priv=MC4CAQAwBQYDK2VwBCIEIBgPTZtMsM' + 'fSrpPCS/TfBxB/JdEfk/ykwO3/Pu+zFnjU msg=GA9Nm0ywx9Kuk8JL9N8HEH8l0R+T/KTA7f8+77MWeNTeYlaLDNEmVq5adGbq+' + 'VbkvFbQK+sBIAGCKIeESrNulQ== sig=2olUmwUJ54cnHlXg6GNOJ1ZTToPjJCdx46EbgntQCniZ0+OPctPWLtDyB7cxGdAcRwXU' + 'ctz9Ti926TR4SkMkAw== e=found last=9 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAANnfxxbj6gQfyUeFK4zVpbVWqS+NkZiErRjKAwqTeZc= priv=MC4CAQAwBQYDK2VwBCIEIDX4Pc7iA5' + 'sFwdbq11pHy4oUpswqrzmfsOdIrKZgQOjx msg=Nfg9zuIDmwXB1urXWkfLihSmzCqvOZ+w50ispmBA6PFZNNyNk9OTDE5dCK+d0' + 'zYeo0lZLkLBhcWrZfx2m7Oscw== sig=d7YAPky2medLciKt0p0T8t0vYdPRWnEg5Op+Qt/Ec8BMwxLVazignMi0q0pJtqv0OgK/' + 'Jo0PnAOIDe3N0GA/Cw== e=found last=9 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPTYLTlgIw05E8u3QroDWVXI3ZMCSCPHbFROLNgqlDlE= priv=MC4CAQAwBQYDK2VwBCIEICkg3bbZvh' + 'WoOJXHGQvhSSlW99dNvxsC37HDlDAR7exD msg=KSDdttm+Fag4lccZC+FJKVb3102/GwLfscOUMBHt7EONvGCsFc+aNaXKKE5BW' + 'cEqKq/PbL9CkRtIVi+KdFP3vw== sig=NfExkMHj4/Pp4PPTBtnK3cu/pvCSfcBfl4daGYp/k0R7rWO5Kndcg9glv3LLmmnXhAwy' + 'Qo6s2q7k0bsC3vh9BA== e=found last=9 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtmT+YSWOXfl+r+ZOFS8+GZrfxFyk0F17rgqck9uJd84= priv=MC4CAQAwBQYDK2VwBCIEIApJRMTJ3V' + 'GYFnZBeMOiSKUuJP5cloneLu6iDmRIbOHb msg=CklExMndUZgWdkF4w6JIpS4k/lyWid4u7qIOZEhs4dtH0nACdz53tW/8M/CS0' + '1fUPVecHIV8BTxGmNH1m4CoHA== sig=0oYGnwIENxqAL2KS6p180hAAxYgDzalNQPTeTn5IOU+8J7X8gS7l1OS+CT6gXEhxMT7Q' + 'fAof+tZ/yGb8QT1FBQ== e=found last=9 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0uZpdCaB41K752gkuJ/yCS+GSqbzbUCrZJIZFCHYpwA= priv=MC4CAQAwBQYDK2VwBCIEIJBsyZOs1A' + 'yRoESIwj8q0rGAbE2wKt6mhNHnZa60Y880 msg=kGzJk6zUDJGgRIjCPyrSsYBsTbAq3qaE0edlrrRjzzQpBr9hwq+ON+Zh1buD5' + 'QVi3f+YVNb9i4Cxtq2jrGnciA== sig=EFZ+ptOmdiVI0wreL9QoVBHk3ODW8md4F60rbKxK7PF5cxDURE5XZXP0Rm86Opo4aU8j' + 'Ae+a1XjKCPj9FAwSDQ== e=found last=9 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqiGoAZp3DWqruj+Fp/+XYlZGodqEGafsW+dhyK++RE4= priv=MC4CAQAwBQYDK2VwBCIEIIiCxByaJP' + '/yUxt+BXsS70bzbe8iJkgmRhqGoG8Znydv msg=iILEHJok//JTG34FexLvRvNt7yImSCZGGoagbxmfJ2/NGe6/3JvE2VV0aJILU' + '+RR1KW+KqbAIJ3R7oXl6ynS3g== sig=y0DY/wQ2zyppos1ixORCPwYakPY1n9lYvzs84Miuka1SUoGqxGQnnKUwvSEAiD9/4QSN' + 'mEZKreO3DIqYfF5eDA== e=found last=9 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAG0DkU9Cw0kKK6y4L7ge8OlQ3vgX37/qpa1dXy0ZW3Dk= priv=MC4CAQAwBQYDK2VwBCIEIOUGERxLBk' + 'usITTcRfJjBLueOIYAMYvC/O1O0IRvz5Hx msg=SwZLrCE03EXyYwS7njiGADGLwvztTtCEb8+R8QXqBFDQjqrQUHIv1h902+dfV' + 'M0oON1UH9xJ+yPFQcgnJbrvzg== sig=1G/9BCxaO7LUkc1PUeun4WJeg0E+sQ7c+HtWdA065FMtHApi1jSyeLAghMYD7nAJ8XWH' + '1ZeL79tAv50mQcvIBA== e=found last=9 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA7MnHuT6tt/lCl+TIT5pnyCYU5XFDcSNWNQJMBZPpGEI= priv=MC4CAQAwBQYDK2VwBCIEID3YdiSenH' + '94I9G1Owqrijo4Phmbau6wIu7Hjq8GR54U msg=Owqrijo4Phmbau6wIu7Hjq8GR54U3zhDfkfTkkvy2FfQ67Dirf3bYg7X5DH3E' + 'eyjqJ7nVqSv0WRfd11+ALrnLw== sig=cEGpmtKuNKCVE+S/zz726cGCVsi57RqkSfavuouzKR1vZiztiDI2KG7c4aWEe9Ner8Xi' + 'TLRhG1dXksFNMrCPDw== e=found last=9 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA7wA0xL4EtGwZiaCkEyKW3LjalBDRpL0foWdiriRydbU= priv=MC4CAQAwBQYDK2VwBCIEIBUWjC7M0n' + 'cKM5bWoz04QWLaGjeq3+1TeG9V6JaZlOei msg=sX1K6e4C7icuNDL0p8CGrgNYa51G5NRVMqNLaml5sXh/KcEB1ysB1Lhj4Xl64' + 'K/EBqBEYgOlazNtEXzBR0Yfww== sig=6712YpTl/NP+N+7Ugx31lAuon01yIU16cWx1+Nb3YPSJWFmHefVRS/p/iU5bAR2LTZaM' + '+IOfNEzrnNgFwwZvDQ== e=found last=9 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/PUSpUlNlkmMJL6V/wu1YM9i1QrjEdZ7AB18OWZrdD0= priv=MC4CAQAwBQYDK2VwBCIEIF9kxqbFR/' + 'bP8cPX9xLs/p+utd9zs711Z54OI33KOTGc msg=X2TGpsVH9s/xw9f3Euz+n66133OzvXVnng4jfco5MZzRGyWLlaVPkC4zIlfgw' + 'oRj/klcUSG2r2qm1IkCkgt63Q== sig=k4oTptQNnSQAaM9XTRRdKKqJM08Uh0sLjyVwXpdXMhLVskbkhOO5WH8jq8uNNPJhWPy4' + 'BXSQ8oU9zELC0C4ODA== e=found last=9 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAzDxv6JewiIIhyMvN51dFnqL2iNVcZlSbXZXc6Mdiaqk= priv=MC4CAQAwBQYDK2VwBCIEINsb+bZLSg' + 'e5sDCWmZSxXTSQGT9zyVFfMASt3X/unDSz msg=NJAZP3PJUV8wBK3df+6cNLPe/XPjhD60FN8yrb0RrZDr4ZtkSAUVbdmAVnxeP' + 'eL0h2VRaf1er5JOYcLwf8gNUg== sig=okXEnDcP9+a/ayCrbP5fuE/GgqyHPXTXzYcckPYIjRphsCCXM26jJYZJee1j8GZ9iGGa' + '4NfY3dBHUrAUCQ+8BA== e=found last=9 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAjvYiTOSSJMsUtS4N9vDcHYChbjQrZ1ojbpUN/kOzm18= priv=MC4CAQAwBQYDK2VwBCIEIF0jbm4I3f' + 'MCh1KqsOW2JF7Ji9epRhX2JWf7vpnOYgzJ msg=yYvXqUYV9iVn+76ZzmIMyT0Q/18/7WiceC1ipvFW+MCoPMWgf2k3GC7eYSqgO' + 'cG74QqS74ZyUQgY5wxAwBktHg== sig=k15nJEzbeysp6a3hzly1tAGYjTgNuN2bh3JTIUdfY4pxSb6Rq7aI2+p1TKfs3I7WxMzO' + 'v0v7iixLuhIU9X5OBw== e=found last=9 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmcNAEiexHNXUoCvWg508hPzmO8yJYdjJumnSNv2ycTs= priv=MC4CAQAwBQYDK2VwBCIEIOViP5P1lT' + '7CgNfAGlbQw77Z2ssolKf0y5rl1gCcxKIJ msg=gNfAGlbQw77Z2ssolKf0y5rl1gCcxKIJVz12vKOZVj2yto6hSEfy4xa8f4275' + 'UQfubdg/rfvYjp6MscUcrl9ag== sig=xKMlGqDwTD2Y7AhghforyjtVkj5mDpg6KQZ/BPWNiAXbDZkzGFPqLxQn+RO3ODZaLE/B' + 'OZZawRtKkC4IJeu1DA== e=found last=9 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA5WH5O8LU2VuNmJawr40b1s1VlvN80HxbqRlUaASCHs4= priv=MC4CAQAwBQYDK2VwBCIEIH/UIR0thA' + 'sHZJKnDtjiuK37WpRE3bNFL0vDXfa2NYDr msg=shC6+xGvSAlng9Rxivs6nxjUjo7eSHdo2VOSglzKS48BtXax6vs/wy+SMloga' + 'W+yuRbnvmzXN6AVLvxUl/3abg== sig=N82jX5T2xTUx71eX+pw1/ZGk2lW5mXwJPytuUtGz6UZHij05/EMVr/dO83BnC+LoXj9B' + '9lURl+JGHGFiHDHcAg== e=found last=9 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcK0asppfJji2L05PctFMUNDnCls5vUiAJS9Hfz9lHLI= priv=MC4CAQAwBQYDK2VwBCIEIP3p2HiLW/' + 'JoWRmvGnbbNA0+bvcFYqyVZR5TnJ/Ep1tf msg=nNhQn5P9Nsd14TO1DinQUHdo8WcW4nCTeLNgjK8C+JnDq04SFdYFEQIHZkzns' + '1+GPd751YZq1OaTHKLvxPcGqg== sig=yG3UygI3hYRSGo+9JImcjzTyZfqd0TWgZq5Hy0HuwiTwHBONPplQMo2a/XEVFQ1o6lcm' + 'aV8VbqOGi/llhqfwAQ== e=found last=9 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAY/zIG6Jfs5QSmhzkbhjR+3n3KX40SlneOrSomd6Mbuo= priv=MC4CAQAwBQYDK2VwBCIEIFuvqYK/Ob' + 'cLTRooeSdPpb1MdVkR3MSnK4YUYih1KRpz msg=TRooeSdPpb1MdVkR3MSnK4YUYih1KRpzXxvFIujSDuuXnwx4ryuy+VpNvO1RW' + 'nhb4bKrWz5K3fVjwM3N4Xz0nw== sig=pXs8vQuYjpl/3kouKfoHGL+3NK2cobLi/kdp3SIXpkrEhD7z0m1Ly9Tu0jE/OQ3onYUP' + 'xMbkKBv1iePqMsUkCQ== e=found last=9 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAgtEREehKgJzyElLZdQRDekKQHRsQYliNTM4b/4yyos= priv=MC4CAQAwBQYDK2VwBCIEILtvd1N2ui' + 'UQxu7QIdhOZku1kW5lixXgn8HgNv/UAAPJ msg=d1N2uiUQxu7QIdhOZku1kW5lixXgn8HgNv/UAAPJ0FP1xwL2KN6xHHaQvudej' + 'JYDAAQRfbFzKWhMDam9Z3wzGA== sig=NLQx/T8mKzkO5kXIDoDPg3sJvS7jyrGE4/vu1x5nZ1hYqrhmCHgkYW+keB1iylplin+s' + 'hWJCqRabGOwkxJjDCw== e=found last=9 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZJFyOeWROi4E9BnEiIAaAt0AMMj54bxhymyJ2cHmLaE= priv=MC4CAQAwBQYDK2VwBCIEIF5c0l1a1e' + 'pb0vy1p8fnWUiuP7mAJlKN0CzWE/qmjIXN msg=67z7TPrx7YTHyNV2jm+JyQbqNjEmhvQPE5ZFzvkkSYu/WLg4uiOWnpyOVFoHM' + 'sjC3vgKOO5gvB5ZXlzSXVrV6g== sig=is22m/5APwQTBKqiO326H5dOVKncnV+NcwcS5qV7GzK3pvQns3gpHBJiIeMo+ws2YFT+' + 'kYjbZ1KVwjjs1D7BBw== e=found last=9 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAD5+SD9ck55fh0YXAnJ01UpxamLnT0cj4nxL0gIoay1E= priv=MC4CAQAwBQYDK2VwBCIEIMcoYeZci5' + '2NrQneWZ/w9KXIuAUlx9brTR4P23vM8rOf msg=600eD9t7zPKznxtsqEoAefvhHq8vVetMa3HhStvd75SVSc4VCWJTEGcWj/uFY' + 'n+GPSAs8uYzZFI2YGQ65bQlQQ== sig=KufNow3WBbWH6dv71lzxT0laWZ1RI8y9S5N8v56OWiy51Ql7k6kvE0POIa0hN4HsHxoS' + 'Tg/jN0JRgKfJcDI1AQ== e=found last=9 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAoAYZa1Nt0e+7DsDzYVRU7lz5NUYV4L+ziGWGjYe9sBc= priv=MC4CAQAwBQYDK2VwBCIEIBUWPxM7wh' + 'avZBNoBs1HMk1f37OxVxgHvjCMmqtBPjFw msg=GllQHAyjfOskgeglz77OOMOF4YgvWJdN3KntGV8m425ZYO64pNz9O6NM0zZMQ' + '3dylPMbO5PGHr0npBB509Dkrw== sig=NGdbuHsDSnAtad+VZrtKmvq5RKuE/hkleVnFQgOebNIWJbXz4HWWd8I15fQORnMrtcmy' + 'lkpUVmDpkm8WktjOAg== e=found last=9 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAipKryMwM/0tYkWGKeuWQ2BrLD3eZhoplGBx2pUXuoYY= priv=MC4CAQAwBQYDK2VwBCIEINofJjfOZb' + 'LD0vBp2YvJ2VO2r1cK3hVXSVgasDBrDhYA msg=4TIn+/vaxTWHcDMY9JtioMLg3eL58mc71vn3fCphyc7UAVpIQqzBppdN1NofJ' + 'jfOZbLD0vBp2YvJ2VO2r1cK3g== sig=8GYXZR0fCaRcfYfPjFoYBLqWPpf667gW5j3LCm633VwppYseQl9llSme5HZ4HxpGjUpw' + 'Wa0LBHm3pu79qP7CBw== e=found last=9 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0+r9hsqiTjCjFDcVZJUQ/WnpzKlMPAFIC9gr0UWXsfI= priv=MC4CAQAwBQYDK2VwBCIEIL3hgcrDSS' + 'wEc5mPDHKsilZwVpo1+am7bDKxxNRp4W/q msg=Xlw1fpWAd8bMdBiP8lR+UqkUQ6zKSsIh8pEsdlzkQnIGN0BjP+bho+rBymms7' + '93O2pQtPRSAv2ZqSsGYSVdv4A== sig=KrWy0pedC2y0kGnGHMrRKwcqNCKqJrSJChmDIp6/kr9hiWevv9SzOtkBz7dyqz54kQKk' + 'V7aiipl38eVWpTU8DQ== e=found last=9 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqJNqsVH7WHQqzDWzuBBkpUZ3jo97OAFJwwsYpXmNkqQ= priv=MC4CAQAwBQYDK2VwBCIEINuYcHj/RY' + 'csDZo2xow9O4LUvC9svVIczDzfwfBg6ZwR msg=zj62QbXbmHB4/0WHLA2aNsaMPTuC1LwvbL1SHMw838HwYOmcEdMgHRUVbLlmi' + 'elkrgnMB1TTh7j1/LE0yXi4QA== sig=M7ncAHELwXMVNgmr79fhUYJJz5njUCRp6C3lPCopgRBAQVQ74ZNp7wU96M6TtJqNqqgj' + 'mnWXZdY9+VEEkF2YCg== e=found last=9 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlSB6wk24gl8uMIYOftnOXlAS10f0QZhgW9DtRUD0VGE= priv=MC4CAQAwBQYDK2VwBCIEILVArKqBMc' + 'xgyHED4D0JekGFOoiGR9mU/VuSj8jfZi3B msg=M9yKYgzvBrGVb0qCfgbDrHd09kSe4GxbcsqgxB2QswTg7ASw3FshhmVc4rVAr' + 'KqBMcxgyHED4D0JekGFOoiGRw== sig=y1FaqnbV3A22fYhfPap8p3RSPi8q9mm2ODkwlVPiYPOVmHmQ/XQWG9Te0qQxlu4Ikzmd' + 'N84dLGhqjgl7W0z9AA== e=found last=9 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3m0trGWzujesZ5wBv93uI9jJr8g28SH8s2dAMFUhZ24= priv=MC4CAQAwBQYDK2VwBCIEIH1h8TSXkv' + 'gzu356h7PWV69yPPM89jEolWmVUtSQuL2g msg=6KrNoCQDEWn6eJgxfWHxNJeS+DO7fnqHs9ZXr3I88zz2MSiVaZVS1JC4vaCqS' + 'oHu3PMR9qWlPJfANvll5c2IRw== sig=2skkVrGw7D6+NxD/+6rKR4QZq6O/JFw6Cyoc/yEKEfqS2S6fh1xFntGgzSuKkV1NI70N' + 'BPrGG0hS7TLuEHglAw== e=found last=9 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABmnUosH9Lwbl/jpp1HWPNERP3dVm9NuObFysF9nkajo= priv=MC4CAQAwBQYDK2VwBCIEINuEYV1lE8' + 'tgKaA5fblH0iclSJBP1quiVgSnvcK9lkfG msg=R9InJUiQT9arolYEp73CvZZHxuNIwb+QZEqOdfERwmv5S3Q8oUp58NBqH1RKK' + 'HkZw+0b4+ZONP9/gAo3q624Kg== sig=oXpXy2gJwiL+JqWM/bWGyvqlOdhdzrmF1KZpWCSGuOteqme67OJLJw20DQyw/T0ad/Zb' + 'xsZpSzxOAcBOQ/d5DA== e=found last=9 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPha2E/NsKWms+kDeMREZw2096/jH3Qg2hVCNTZK2pmE= priv=MC4CAQAwBQYDK2VwBCIEIOdOB6Uhu2' + 'oOn/m/RTIfQGVjHfn3vUy4gyQGok9kBJJt msg=LYYP9iKova7ayzxv9v2IBVbf2sA+bHKdJwfDk3FaXv+McuJfAYZBPrbM7NqOz' + 'hmcjEOtJbge8mN3FbGX2QzZ2A== sig=tVXz4p3SeVj5Wu1F7cOVTD6wo3EMfMhzsMQL7DK+w8F42GEupnfRA31XKQ6nbGCunABS' + 'Sp+7XWfrQ1O564K8Ag== e=found last=9 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIDJrbhcKpHNDeU2And5vrjTfoFnrfVq5bNOBa5ciA7g= priv=MC4CAQAwBQYDK2VwBCIEIDnSKvmbca' + 'K1ndX8PAHq/XK7uGtXE109p9bKVPVuGPs9 msg=GcGC8+7ZATrixeIByMfGrWIGl9hzTzPQzWqZ8mzGgv850ir5m3GitZ3V/DwB6' + 'v1yu7hrVxNdPafWylT1bhj7PQ== sig=oooEOxSLirwLOvrHLUPA7lwSu0FMO82pgfVc0aWNWuJSkX1sOgKa/SA/Q+YNeoskf2Yy' + 'kxmqjpQUfRQiQ16qCQ== e=found last=9 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEASdXGBZFDSTHhwH0LVGVdKIr9jip2rcA3khhER4OqAHU= priv=MC4CAQAwBQYDK2VwBCIEIMYtC7NIDM' + 'qmG1Zx7nDsU8qznfPYoebif1tlhARFdc8i msg=DMqmG1Zx7nDsU8qznfPYoebif1tlhARFdc8itk3hViPL1v5zgMkM4Q+1gdOjP' + 'kxCP5kKX//T2uPB7Og+EmlIPg== sig=1ZHDDRw4DmXlzzyY3YvGPrvQocFM4NDpp++DDUsvnRRiR6EI+9P4m45A7UiLIlQIuEt3' + '2XBklicKK3JrX3PHCQ== e=found last=9 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAVlb0HkE69Gu8hMjjVZClUj32j3S1TvMJzdNvea7bLqU= priv=MC4CAQAwBQYDK2VwBCIEILT7hBeRhO' + '6SdBNPGp5zITWWZPxeEYHjcUgzoaUNLGvh msg=tPuEF5GE7pJ0E08annMhNZZk/F4RgeNxSDOhpQ0sa+HnrBZW1//ktsWgKOs/l' + 'VhYQYtmDI+aZJQkr23NmU75ZA== sig=0Imh+/3HzkReLITQj14y2dOrsF7pN7/r/hzD0Mb0ES+RpYUALuoSuOZR/M+ibXbRItfD' + 'XpInXqZjaNyEJJIZCA== e=found last=10 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEyGSb7hg3v3jaRD1coUoO0v1QUAL6avu+wnGLhS2GkQ= priv=MC4CAQAwBQYDK2VwBCIEIKUXz9TfYi' + 'R6pkR0np9usl6VsRw2dsfTi9YesskbKz6B msg=pRfP1N9iJHqmRHSen26yXpWxHDZ2x9OL1h6yyRsrPoG+Zq3/bulDuUN+GP4De' + 'zuGBh8FYWmh+GSiK0ZU6zuC9Q== sig=vZGqSpuz2j1Q4wK5f6dfAD6xh7zbV/A6pit1tdD/h7ouFRCO5+4WNod4QeEXn3X45Kif' + 'd1yzKjhiUq1ntMBKDw== e=found last=10 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/LTQ6dWJsf0x8r4xflrzGu5ob5jomD9Xz5eZudZBP4I= priv=MC4CAQAwBQYDK2VwBCIEIPW0vIq8LU' + 'QaYknhv396XMiXvG3HPrl3Av4rK2/U5FgE msg=9bS8irwtRBpiSeG/f3pcyJe8bcc+uXcC/isrb9TkWARRa//azQy0mojFq3oU4' + 'IL0EQMWIbcMo4otwarf6ugGCA== sig=4XAJOZD5EPWQQlOaEuE84GkqygJVC/44gxANqLF+Bw6tmqHJ11cj7W93osV26Q8sErnu' + 'tn+UOZYWLHXTpxq2AQ== e=found last=10 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhjx1zduYLyPpAm1AFkcZSUn5B71Xdoo/8fORQlIXMNU= priv=MC4CAQAwBQYDK2VwBCIEILjaLTCMl7' + '7XJ3kQ0iQLzEOZW7anp2iOPB2IAWCzVUd0 msg=uNotMIyXvtcneRDSJAvMQ5lbtqenaI48HYgBYLNVR3Rqd8DW3DrII3u/FRgcv' + 'nqzgqg0H3nIQ/pl5+pbJIF6GA== sig=/f1hI2xcSZhG2KD99ULeeo3BmtKbd7eGCbaEdzK4XeSbMn2ahLsRI+p520FPT1I4CXwL' + 'g/o/Huj0Ng3IG9sbBg== e=found last=10 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAb74RfkAN9uRYgqq9epXLudL2eTv7ZYv4iwZU3OjfdyU= priv=MC4CAQAwBQYDK2VwBCIEIH0SNr0d7x' + 'ZPBqtZqI2LHH7O36ltE+xAjsgcWpBSggh8 msg=fRI2vR3vFk8Gq1mojYscfs7fqW0T7ECOyBxakFKCCHx/gcR9Np2rftkeEfvML' + 'Uedxd5OnsnvoB/sYqksRdn+Ww== sig=p+9T2O/LUd5A3xUaGpx+CAphKAkMA+RBuh/8JyO4UxJGDzMNGOnFenK3sliJFO8LFZUd' + '0uWDAXW2pDWVM5bkDQ== e=found last=10 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACwJo6J60IffgxcwJuzJKcM2W5Mfm73pxiwKY5ueMTaU= priv=MC4CAQAwBQYDK2VwBCIEIBpf4YFV8P' + 'yjuTT7iBv4WEIDsLeUHH9yqvbrGkozKTap msg=Gl/hgVXw/KO5NPuIG/hYQgOwt5Qcf3Kq9usaSjMpNqmI2Mx2Fv300kvTSRHPX' + '2xBYVQA3V/1mhumc/l0BsKcRQ== sig=mV5ptzJgqw4Il0LYbPpDuSUXRih4Gj8ZL3LymD3j/dzNerJcpkoc8Q+rFAM/AE0PoH4D' + 'RsiBtw5UK4iorrNKDA== e=found last=10 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcN71iSHVJjl3V//79Z4bN6WLMqIZBKcSYEJYoVYSaLo= priv=MC4CAQAwBQYDK2VwBCIEIDKHweTUgY' + 'fC9tPsHntGddFL+uWNg0Gr83x0dJeGCmkB msg=MofB5NSBh8L20+wee0Z10Uv65Y2DQavzfHR0l4YKaQG6AZF/9O220wMP+rlN8' + '00BUJIyLGMzJHCczw0wrgsUhA== sig=PXOl/Srjj25XUaIx74i8jzMgGzB0ZasYA1oKgTN8zrrCUAfhjXmFUQgUEX5U097ue2nl' + 'jNY5bF9hYpwYNudzBA== e=found last=10 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAuyAA2Re4VIzhYipYG6ShThl6gA2hMIpZXnq3Lzit2yU= priv=MC4CAQAwBQYDK2VwBCIEICf7I7MjMc' + 'y8kaj5rgh09BkNdp2hm4MrGF54Sdiim30W msg=J/sjsyMxzLyRqPmuCHT0GQ12naGbgysYXnhJ2KKbfRbY0cGlxpRRGmgWPDu/F' + 'NcnrAZmIsjfvpJky+VDP+103g== sig=cYipUjeEX6FkjqYgb6kNVDS5j/cN8y4sF0fmqUfRQk9wGB/BogIlCDgjgTL7QJAFFBEZ' + 'kG90FuMAED5O4VIJDg== e=found last=10 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEARCMeILoMCOou6KDO2Ek5Mmag4SqAK2zx6g1Cqhp7WJ4= priv=MC4CAQAwBQYDK2VwBCIEIHxbQJcE5I' + 'qzmV9KSX3XkaB1/3FuqcMPiMU2GJR5uKml msg=fFtAlwTkirOZX0pJfdeRoHX/cW6pww+IxTYYlHm4qaWmDvL9w8w+luvuYjUiX' + 'qPiO+GOVDoEq11c9pNkD/9Tlg== sig=HMMJdYuPXSX6rb250uKgA7aqiyxa+V91Z29wF3/nEs+FIhq7TpDETubb3H4J5qFoDo8K' + 'UH6XBEQOP7eUY+HFAA== e=found last=10 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqPNOyJi+N031E1E4biSAutBdEREnfQG5j6uOAsxpr3k= priv=MC4CAQAwBQYDK2VwBCIEIHNstdLNN2' + 'PJA5aT2xTuOXxxIScfy6hmNlLZ2Pqn+gaB msg=bLXSzTdjyQOWk9sU7jl8cSEnH8uoZjZS2dj6p/oGgc0JE/T/zeo37llQFkCSx' + '/3aRbC8/pUASP1at7T9rO9h9Q== sig=GPawjStneD3u9xDQ21zztsDLh0IldbCQxkMy7/RXyXpbXnydkUHkjHgNMU3NkLwYJYeA' + 'I4vjIsyk7jyaB7nQDA== e=found last=10 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA4Z35dH8/CcN2LRm65u+z6/GXI6TRYxiEGcpEeLi2aXs= priv=MC4CAQAwBQYDK2VwBCIEIExKZwli/Q' + 'lK0APOGNrtuBTqJ8fzUECrsxlJeCNrSRyf msg=TEpnCWL9CUrQA84Y2u24FOonx/NQQKuzGUl4I2tJHJ8W9qxEbtrisez8Y/mkF' + 'jnEcupXFlJ8j2qTGS9XZzB9SQ== sig=wIr6xHZSwi3ZSzQa2mDx3e68YwvlnehAIATZOI189w2YR1ZEgZxe9FvOido7qoRCPiOI' + 'p5qHvf7VTUjivPQ5BQ== e=found last=10 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFSY+d6OU8g1lOHw57XHLafiIlpEUAmGpGBVOiS3rLvA= priv=MC4CAQAwBQYDK2VwBCIEIJRt/rBnUz' + '1pXGVTCs0+UFeKL/h0PutEnRf6wzQAWuNN msg=/rBnUz1pXGVTCs0+UFeKL/h0PutEnRf6wzQAWuNNIZkh1NgxaUQLACQVftEUy' + 'k/6Gl6p4KF3SSgTOmm/FEEVoA== sig=8T4CEiItW7hHr5AtV04qHa6eP8VCwbJjZe9ABr6PRf7bQ+npCGuGeifqUPWLhbj9ctOX' + 'QLJqtoOOat5jZQfZAQ== e=found last=10 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAV7uL+/xqgXThMWDfHPPFYoIW0Gfa7oWBq9PzCMUu+Jc= priv=MC4CAQAwBQYDK2VwBCIEIJtNGKIeKj' + 'iVbofOWpvinLPZxEy7EWt3TVeoel080KPo msg=HNytJfxnrbV4fPC0wCtRUKTDkyzJj6JYLdhNQtdE4ARAd7keEF/iR8NXLEF4J' + 'cf5irCYintWcfe36xVw/xrSEQ== sig=j/4rq7SGZ3cPq74N/YXDlG73qRXcHDljiAy3HNi/peSoSlLirM7iZFEm84HI6CNvOk6f' + 'pfakyhVnkKDFLs8QCQ== e=found last=10 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWMZBMZHJxDr76or2k5Dkz5l1ISaBfX1uuSu9XyTRWvQ= priv=MC4CAQAwBQYDK2VwBCIEIBFLFb9Cca' + 'm98kur2cf8M61x9mgBS70PJuwLJYBsecPI msg=v0Jxqb3yS6vZx/wzrXH2aAFLvQ8m7AslgGx5w8jhwJUpjCjce3hVfuAV+7FLV' + 'BRNcOGmMJ0kfxKXaASxTUl7aA== sig=NQhphVoFN7ruP/SGwMB/11C7gD+EE//LmzG5PSWCVcFPz68z0drfhYUQpNxqbvUpSdh7' + 'Ejr9ucIsPVjNf/KYAQ== e=found last=10 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAMRcHnGvbdcg5hoYKyCKhQdbKPcmixfmbhEAZV1qN3I0= priv=MC4CAQAwBQYDK2VwBCIEICylxlnaUW' + '1l63aNDHpMRukSUlmEkPWooFb0ibZb1Xlp msg=gJbulyePFp5MbZrYypQCrpQV9i2X7mXkPqBx/QxS+i2yxRWXjHNNFl6QzoqtB' + 'Pl9z8IYC+Eux6UNjwFSmWcwng== sig=1ZN0KvQ1QU388vnTcsb5zKd6BgCWZ+S6Q+ddCk55eQ/6Mw4V7GuPmWBrbBimMUq6uc0S' + 'sLnMSMblK/X93EqDAQ== e=found last=10 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATXo8KJbJlqPzvfXmSPDSY/XKi/1yGVbR+RXyvE3rSQI= priv=MC4CAQAwBQYDK2VwBCIEIEJMFXpB+2' + '7KcaoZ1sLTWfq4za+3LnMfuBeNZHqyeYjD msg=Hj83HhWVXaHKGd/BCXyquCXAnFWvUtljaieNV3oEAy0cHyqqu0MIsQKi3Oa8i' + 'AmIJDOAc1TIhOm0VTNBJ6ziIw== sig=6LUk2SJ1pV4Qrr/TS3+HVtuBFIhHyPoFnFqO9wZOZIylHVlK1Y5j15V+UVdi/k7xrsVl' + 'Y39C+mt93Am5t4c7AQ== e=found last=10 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAwYjjGuOAEJKSrZUN3uM7n9jQTpaIzZlOlo5k4HgacyA= priv=MC4CAQAwBQYDK2VwBCIEIEo3olAw56' + 'nD3Jamgby0MAwGxRUt/xrl2HQvlTz7NG33 msg=kA6eRBB3+b8n7NnBwSF59WuBzD23NbqzcfDJGJcbsfKMSebDLmhg36GyDf++x' + 'DVYfyqyAF2FjnZjRYOk0Z8HMQ== sig=4P9rKPx4S0lAMeq+nULE6cph3rAsZvthRRVWIb5WeXFZ+8r3Zn1AfLjJiUXzeoL9Z5Un' + 'eXxpRNlsDH/39ocoAQ== e=found last=10 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABMJYQbNPi6qVtn9bV//RwD2mQ3D8/jTxiV7oXdAj6V4= priv=MC4CAQAwBQYDK2VwBCIEIHG38dnVo7' + 'GPjumQox3tTMlg+5FyO5ut+kuXkfScG9rH msg=zu3Ia4/WRT8wVZIaBZ40felwTg5LkJlJLO6JCzDbcaZbqNBVGLu87X1QdVXXj' + 'k0T31eRv4vWrPQE3eZ9cFlkEw== sig=bKeLxhg/6MQszu4Iv5fqZ1CEl+xqdqxOUrDcZ4JEtNQGVFre+GZEipA0AOA08GUe50Bm' + 'lusCXfB31tAilcmADA== e=found last=10 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqQSEbqatOY5e/ntBb77xqoekEwyieWxIu5hj8G8qrGs= priv=MC4CAQAwBQYDK2VwBCIEIPbmbBobF/' + 'PIKeeJCm7wp+mmEjSa7ilsc5ZRxJ8EvxU5 msg=LVlmCar25mwaGxfzyCnniQpu8KfpphI0mu4pbHOWUcSfBL8VOSFei6Q0XOsh0' + 'zIH1sarOizq7bQQjo5CzZtupQ== sig=ltEZw/l/O3s9r2NCcwdypi8X98ZAUgDkV8imfRqVWTgmyBoPQYXOsv8FDdfEKJhbwvDb' + 'ja9sDvHAaS6Yh+PgAQ== e=found last=10 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqpB1OA8D+a7IaM/L7Qm5zcp8Dw7jDbSeH8jHKQa1kmU= priv=MC4CAQAwBQYDK2VwBCIEIANjMFRGqj' + 'v4rnHLEIEXxlCfdhQZGA93m5DgDtjJTp7S msg=sevxozGLEYZ83MZlgRru9G2fIe2ImRiBxmc9YM80j2vUmACaB6xpsRj/kO3N3' + '+ra+MmNHy63eO/DtALK6/nZYg== sig=9dw7rj/Gapr2G40i1W/5Vgv8YwJA2v79IzODttfJMnf+SIgshZU6Flz0jIv9iGkvpL5A' + 'aUAsdpkGTvAK1/cODA== e=found last=10 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAS4S4ii20i/mBlz5SulqFvxfw51R072Ng+G0pUifnmmI= priv=MC4CAQAwBQYDK2VwBCIEIBq7Kjo7DQ' + 'GGhGRjGu0HKU2u+LD1KvX3SzckOmA2ALRl msg=+LD1KvX3SzckOmA2ALRla+RBw8SmZtsgLOMUsI2T3E4QWFUuQlqSPXEOQXNuQ' + 'FxKBBpVRFx2p4us7WufxwHbNg== sig=Tm+Q+KyZXMfdB9ci1tjEvtR0CHfT0IiSRWEh6MJ7T538GnaHq/2OMsDEyREmWy4oi6sb' + 'FJnuDz1MALmOlaSeDg== e=found last=10 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA8r8zd+TXo3/AcvzsLSz6QalHsr/WnsX3YFJRS87P3lk= priv=MC4CAQAwBQYDK2VwBCIEID93XYwPYW' + 'RCK1Ez61moO6V29kemhvuJmmsycQXn8RhS msg=wOhj7z93XYwPYWRCK1Ez61moO6V29kemhvuJmmsycQXn8RhSEnAa4lBG3fGlh' + 'On7XUpBBPWokO76Zqlm1V1p3Q== sig=R4GTvyLRt5SaFIryG6kpWEsc/kW9at9LkKilDND0fcjcg27olpnqVNCzpgeeFRGGiMRy' + 'c3UgDra9UfuwXKgRCQ== e=found last=10 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA4zUc3dKw2Bo1IwG+G66aUUpsKHihDr4KqRP63u60j3o= priv=MC4CAQAwBQYDK2VwBCIEINsJudM4W0' + 'AO8AWudVWZSF4KwYm2+OembJswyCnxelHo msg=AFjvIonAhEVdA0uqtMLaswvbCbnTOFtADvAFrnVVmUheCsGJtvjnpmybMMgp8' + 'XpR6NMI2SNQI24YycNNSiyUDQ== sig=WPEAtMZO1TFIwl6lThmzCLJqugzI6aBcWm2EALM8cK+fZY4S/dAUAOOO2mxp/Pl4LXyr' + 'SVLgE6E6yGjanaSPBw== e=found last=10 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkdQkNm2GGT3obDqrf/HGqEm+72Yir9MaLWcPWeiOdnA= priv=MC4CAQAwBQYDK2VwBCIEIMC21Eyuf7' + 'BirEkh2e/dX7AlKRI5gh/pIDC765pkWUUl msg=dGAay9vdIjwzvmhvblcduY5dn3WSVMbpKnuIbTVo1WH5i12dAIQsNpsdsBJSR' + 'EyuZNF++F4aDEN/S9vHTvtyHw== sig=D6d3yPXemyF+87iayBOBNUdErt+4bwmZJOeoNaIwDfY+Lkc3ne3sCcYTeS9yk3ormHlU' + 'F64R4i8OBd9SA7aFBQ== e=found last=10 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACZXeoWc7+Uz/p8YbCbZl6KdrhWROE2+75lgAFz/Vjwk= priv=MC4CAQAwBQYDK2VwBCIEIMwnyOrv3m' + 'wWcAyEjtz6Z2XXVoneHaU08fIE80QO806+ msg=Br69k9FDWZpNrbg1JIsuCZ9FvoTmzciTChrlAAbn4BKRmhvwJVK3TBW3wwlTU' + 'swnyOrv3mwWcAyEjtz6Z2XXVg== sig=f3N+VPiv5fshu50pazT8FHapZYgi8YQUiLvxElw3sSsibUgtCAaqqnn4iM8wp8P0VGxw' + 'OE8KUfdiGiVB4MhnAw== e=found last=10 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbxVtq8KC4xo4OZvKpF0/ZCPBKrtSYTAPWx5hrj4Pl0g= priv=MC4CAQAwBQYDK2VwBCIEIOkKLYsfS7' + 'Ql6jK7LNtilHq6ZgtOcyqBeM0sWNukksqX msg=I/TpCi2LH0u0JeoyuyzbYpR6umYLTnMqgXjNLFjbpJLKl8rT8S7gTNV4/ZJLe' + 'PM5bIAlaURyD/IDZKD5WUc1xA== sig=OHAvOqnuQpKmka16etSSBQbwsjZkxgQqR2jKT0emwtUBkJ+uJTbIZt56EXpp9JtCJcZS' + 'S5C42Jr3V6cvOq82DQ== e=found last=10 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA50prt5SC2k5D9pTAIyyRW36S+Ti0I7S71n46e0VYwbo= priv=MC4CAQAwBQYDK2VwBCIEIBa9gJJXvv' + 'ZBMS+RHLyQiYUxjB8C0ZtEVL3olCkwCjK9 msg=jIIgOgAtkjG9Ip9bXhyzI9i6VYGn3HiqksTbBWdU4NoUbg0WvYCSV772QTEvk' + 'Ry8kImFMYwfAtGbRFS96JQpMA== sig=gkzykG06/C35xXUrX1C2hDwCgZusIQ1/1zn6ELHCDgBlEs0QQt56ZpaohnJZfsCSwYum' + 'b894xgCe+HlkhgYgDQ== e=found last=10 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnc66hJZtPTUtCbOpDJM46whnhWV1rMza5DeN4Dk6g9A= priv=MC4CAQAwBQYDK2VwBCIEIF6R51kFPv' + 'UBoFQ9JR27yZi0C0ph3NsQV5S12xoRNcWi msg=yq5pSls4gRmfPAUXARU58qekyW5MnhMN0yx9L/ielQAv6Qtl2b+ayH6+1RkVX' + '5N9u3GfjLMa85rMUt5xTpKIdg== sig=lS8azKVMOpogMBOkxDNGDARCDzuMpH52bQ5PD4nEUpWWMe5Jq5qCLCHsKUrKycdGrcoE' + 'aHRr25s9YAD1yXdiBg== e=found last=10 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9ZKsRgfPpFfwlU9xjHLnGlTRNL1Pser1aYIWNTfMxjU= priv=MC4CAQAwBQYDK2VwBCIEIOFkozS/JK' + '4EUrxeOHbw/Ip+22ql2EE6sHOV/8a28m8E msg=4vt9ncFtozirIg0ah48/maPhZKM0vySuBFK8Xjh28PyKfttqpdhBOrBzlf/Gt' + 'vJvBO+mfw7W3F67FOWjN3qf5Q== sig=MnbhVIzMyuxhtZRK8oPY6ydSLr2SetxHVdkqUcorNDvNm4G0GbVFYGwhDXHB+HgxJo9J' + 'wMBnvovFVNcRoaN+Cg== e=found last=10 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdnEYGyTkdvXlN4olxeZHHFpwyT7bFEr9oEc7HDj54fk= priv=MC4CAQAwBQYDK2VwBCIEIPaDt6jiNX' + 'dd/TStZO7Gt1NXACLEn42mIJUeWSSNbAH0 msg=t1NXACLEn42mIJUeWSSNbAH0tM+zPzkCiNGjuE1yWUlJWW54AaWm3JGSAg8a7' + '/41Oc8uRCnmImGE/rmadkHJEg== sig=Gjm6iNbb456h9S+d0GDLOBmO/3JNiXaYmxHcsq1cWMr37pF8SxuLK06DtMkXjYWJlTGs' + 'Ce7+r5IFl81GKx7PCw== e=found last=10 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJC9DNWFv5HpWMhpRzHs18/rbvBx1npoYhAvL3hOJugM= priv=MC4CAQAwBQYDK2VwBCIEIECTblrzuO' + 'N08UsQOjxvLkgCThpu0XZL2EU7Xf+Tlsn3 msg=WNPX6ECTblrzuON08UsQOjxvLkgCThpu0XZL2EU7Xf+Tlsn3cwACDY4WqOoOM' + 'zgnRmNnXcIdw4x7iOdyjbf4Dg== sig=VwGI9kIX0rhu0UdmpCs5RwPJocPHOkINuN2GrKEl9nO2XRfgdexuegl7lrdhsU4nIdB1' + 'y/WP0FIgHjdnyv2RAw== e=found last=10 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAoNrzyvd6JA4U1lJPv57gJ7h+MCP8MsqBFYKSQwPqYCY= priv=MC4CAQAwBQYDK2VwBCIEIDb4nYWmjD' + 'a11jn5TIR+reqlYn+nT7UtEyYThPKx/F83 msg=f6dPtS0TJhOE8rH8XzdK/jFBDfoIMQUW/kl2PMGF1iAN2Wu+31+gbAZPEHtad' + 'hO+6GchWnp4SfJCyAH4G4Cv/w== sig=BPRs7WWFQtsjNtEHaed7HiaADlSg0l+PKRFXOwj36plse3F/30dgXowjB6/VgcrIZ2Od' + 'EnbKt4d22dwHQY59DQ== e=found last=10 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAKU/2jLBnlWBLDa+1+5TCXJqHiIZyY1OGftYVBR5eN1o= priv=MC4CAQAwBQYDK2VwBCIEIFiz4GkbPm' + 'QhS23yuHc2qL1FzkLgOtkZCVrzHhJ2gW98 msg=u+VxJp5H0JPMIHWhgHhE27LCy+Yi9Zhz6NPYm+mb6HdzoskWICXPiac4XjbvB' + 'dtP7E1CGiIb5MaK1JWaQwf67A== sig=z8Qz11FHsKSjqI0wA3YlPqZnIR4wVRHBOmMF/pdy9yLr31xipzrJJSqHF7uuin6uVyWk' + '4ygHdOoz4b+hJgDYDg== e=found last=10 s=32 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAMfWtTtz4JLILkUh8UhHW/86GrGeg02k/wL1fq0Yl9Qk= priv=MC4CAQAwBQYDK2VwBCIEIBSCZ3huUU' + 'H8ccjilK5MUo7HwUso79RLmBQ0nJCJ5d7V msg=rrAEc+tOw4dklgT7RCuJY0Yf1yYa13BpSbZTNwTREoTQ2a0j3FGPa2rcyNUYB' + 'mw7MUgNu1jY/vdS7rAUgmd4bg== sig=i7TAIFtrQnpTdI+4p1ikjvPjrgYwk1THr505niN9DSYY423YhY+r9NAarbAf3m+NYP8d' + '9HjopzOQ4638zt6/AA== e=found last=10 s=33 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAH67SSmFE2UoeCllSBXENGKWgr8UhxEtMSicavvc7iz8= priv=MC4CAQAwBQYDK2VwBCIEIEXRHvPKOK' + 'unEplY2SlS5Ot1TQp9o/Qx/cG2jzwpLhIP msg=RdEe88o4q6cSmVjZKVLk63VNCn2j9DH9wbaPPCkuEg9JWERFb9rJIzqNhzZX9' + 'BpX18895TmFP4wjAFK1xLbrWA== sig=gLUZNaZQP7V5yyaQDDiph9UH/Lld0yuPyYihJv6c0QXXdhleOuJ2Z6x+S6Y5hqWDWESg' + 'oJjVKTMeWn33TFLxCg== e=found last=11 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAu5/OicpI/dl3JKhXW4/qHe3zyJCv36g+YdMxevtRoac= priv=MC4CAQAwBQYDK2VwBCIEIG3rShHEhy' + 'W/7wK90qhoeatkKD9y6Spih/9vPJyyWs+p msg=betKEcSHJb/vAr3SqGh5q2QoP3LpKmKH/288nLJaz6lpki53PluycjHivsbNs' + '3oNbqHYYZWPEkIOuZVX7lQbCg== sig=CBW5muCujXDu0izreGTdqNB+7POtAu+DlfMS4DnzQDYtlgxigHW9AMoZRgbXRb8Hx7Ii' + 'eL8lNtXREBSSWB/WBw== e=found last=11 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJNy7tOGnvPNxR+w2xU5j7Ff9H+9dabmFhMFIvFYc2qM= priv=MC4CAQAwBQYDK2VwBCIEIL3e6NSAIC' + '7j5FkEUWg3LsXgk1LXHnv0shJVGGPfZnqZ msg=vd7o1IAgLuPkWQRRaDcuxeCTUtcee/SyElUYY99mepmZ54VwEJi0ntlvcvJhi' + 'kf/SId/eRRng2e1uTuPPmJdAA== sig=xMnEhmn+J3Xf+qqAAna4zQ58b3/MJac3k9qjrtU92B5S9w/HwPTK586KqEyG+iZgJY4Z' + 'gQj6iKRxHKQNWR0JDw== e=found last=11 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhveHcTGTusRrwHInOckptycpDK2nZdK3wr/so/FHtoM= priv=MC4CAQAwBQYDK2VwBCIEIISGSQ5tjw' + 'T9CHAF7ddg9cLLFoTey//xs4JtfQOai9Re msg=hIZJDm2PBP0IcAXt12D1wssWhN7L//Gzgm19A5qL1F44iBNr6rHtK/Gn6NMx4' + 'lLM66J2KdX9Eug2M3vE4TzXfA== sig=VInzg4YsPsXdfY04N/z1ZISqePfIsYF66WIvK/GIoSwh7nyIBjnI63zJ8nIZv23yL74Z' + 'Yp9UA9GlBn2yIm50CA== e=found last=11 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAr25VJ0Nl8pOwup3LDTv0r8EX2MRFOunoHs6EroA1qCo= priv=MC4CAQAwBQYDK2VwBCIEIM6OoUlxc0' + 'zsds3cO9WlbtG2Q7NgLSSGRP3II3XhxaAn msg=zo6hSXFzTOx2zdw71aVu0bZDs2AtJIZE/cgjdeHFoCeV0kLg8ZlHHwxuUsrbf' + 'aeaWvoZBkMZZVFjIUShJLLn9A== sig=nsMqFs0WUYoDxi/p6sJCbESzwdtqnMNzseWeIMRsNo8FBDJ6SC7Fart2tPo3b/nW6HZm' + 'unMxR/yQI0JTuKFvAQ== e=found last=11 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIFzDlBSlMAyII7GkwYCmvCEHdOHzLV1Ar2hnQCYt7VQ= priv=MC4CAQAwBQYDK2VwBCIEIFmyCNCTE7' + 'aBDI+GhcDWxu5r5I/+SwW4o7RxxiQjzkAh msg=WbII0JMTtoEMj4aFwNbG7mvkj/5LBbijtHHGJCPOQCFDm+Up4/yjD1+uUTc7h' + 'FXXev6CLS3BcxW3UWb9zI1OFA== sig=uuGz6SA+raR32Nt+AkTvFElAytDC+zVcvScd+w1c+4wi6HqsLXc3KHeJDFY1cEmoosML' + '3cLno1PHngsai55hAA== e=found last=11 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPkvPcRmCirNxX3716nKRaiNXbeM6XmSYAXCE9WjDwHI= priv=MC4CAQAwBQYDK2VwBCIEIHkkjPBbn2' + 'dlOmQDq0ANs5W8o/oRhJNjKKNOq12QmYBf msg=eSSM8FufZ2U6ZAOrQA2zlbyj+hGEk2Moo06rXZCZgF+0qprXj+WrnmQr7sc9v' + 'wcFtSzfnz/yLFFZeCJ3FEXKPA== sig=diDsW286QNlKwB2pfRiFydq3JkAwD34hPjWNJ/Z73fGLOVuJ+OqdpRs7SgNGbT5y/IRR' + 'Ubxt6Y3K27upV2KqCA== e=found last=11 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAKO6JRIkJeYzB6x/cJqQTKnHiUgPWTlxI+G+FP08bOuE= priv=MC4CAQAwBQYDK2VwBCIEIA+YF4XsQi' + 'yJA4poxuKSBAqMOOeqLCi4l1vieHL1T8js msg=D5gXhexCLIkDimjG4pIECow456osKLiXW+J4cvVPyOwSbKg+8JAfE0yylUcCi' + 'S00YHROutOHMMftU0XgzC55ow== sig=SkyBy4MgE/KUzB1+UU4sEwIz6/xzO8Up5Jy9pj8j+LLN7xYLSShg0de3E81U8f9zp3y0' + 'MlLg46JS2YqC5UavCA== e=found last=11 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAI/9xOLfZwT4OhWPuEMmAyfS17KxKNyyaSWhUQOedDQs= priv=MC4CAQAwBQYDK2VwBCIEIEktvOGcSC' + '57HhkT4tCoM3cNQDrDssUX1MGYfeivwVno msg=SS284ZxILnseGRPi0Kgzdw1AOsOyxRfUwZh96K/BWeimiQptm8+D0PgYoWK5S' + '/VwMGAAJRc2ZWOi13ngyAdmYQ== sig=+WQ2XEQ1bEWPH4KPqqtJ3ZJYoC1wLE/L/GR3GrxGo15i2hOKADowbq9dQCujCswlbOs4' + '5XmEvR8glxdLfBWADQ== e=found last=11 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAH3pupeRM+ImzqeXLRZ3KiBEeGJSixQLTn3HwJELBjpw= priv=MC4CAQAwBQYDK2VwBCIEICjT/cTsZK' + 'T114yKU69XFquI0Z0Dzo4I3stF1idrr2Gt msg=/cTsZKT114yKU69XFquI0Z0Dzo4I3stF1idrr2GthwRqvQLwzJy82LcQToQFS' + 'SZ7/Awrm2pam3rm338R684iNw== sig=dfhrEjDsXrfr9Xnvx/y4F0E10RFdrnlw12Ab5Hv9ZLNyTZGj7MeoHDXDiE+CbmU+ChqX' + 'jO2mlyGQJpdLC+WDDA== e=found last=11 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAc1lTNNekCBSQgBHSWKNSsCigq3niuuEwl302agk8q2E= priv=MC4CAQAwBQYDK2VwBCIEIM4rllaaHY' + 'XgHpngGLE4siGc5CjkQrjL5YiDCF/6ChXe msg=ziuWVpodheAemeAYsTiyIZzkKORCuMvliIMIX/oKFd4cJE0joNoVJzm7tJBIi' + 'V6wgqwpCF3DQvD/KLm153s8HQ== sig=8dh0R4fSgyai+gMaqtqn1s0IOZ2NwUgyhqk+HgGPN+GwU+Pa8zTLEpEk6U5C4MFnifD3' + 'pGheNuTHFV+Uoz9QBw== e=found last=11 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAa9JM+bSVNb1HGtugdGUMFvaNheU4s4qILCbQOHsYWM4= priv=MC4CAQAwBQYDK2VwBCIEIDzng9n2X0' + 'ZS4OUh4mObO+D/V69V4fdcVRBJkVqdIeWf msg=54PZ9l9GUuDlIeJjmzvg/1evVeH3XFUQSZFanSHln9txvxtqC8ve4bvnkqx5/' + 'kAsvO3SN4s+1BaO8h/SskY1Eg== sig=zcb3cvMbGkfWmBsvPsD1Kij7tB9SCzeYtAV+nv38epl/16Uw+I9mnF99AJ9lQeI/bbH5' + '8cB/ky73snArv+lMBQ== e=found last=11 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFf7CWcNudycFYYLUxzoxK/eL49YfUfwf8SSPZhgJmhw= priv=MC4CAQAwBQYDK2VwBCIEIOqbiByWoz' + 'm8sTlavmtfCeMPEPQCtZ/F78x1RFA4ZrbC msg=m4gclqM5vLE5Wr5rXwnjDxD0ArWfxe/MdURQOGa2wogAVidgOfekO3a3Uo0NF' + 'Yut7E7FDQeWdPlCCFC2dPdJ5A== sig=+DEgL2lID7/Aar46WfIH9VmS8rXj30jHCau8oIJO85FZLBI8lUeZkIF9Ryk110q//nE2' + 'Pz4xbD8jYziOU7TyCg== e=found last=11 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3usUzG1o6zXMXIioxcnkIE8Sv8+q8tnhPTOQoWl1zwM= priv=MC4CAQAwBQYDK2VwBCIEIH60m/gied' + '7HNipFIyKQga0UIum65G13ivIdgYDFco3S msg=InnexzYqRSMikIGtFCLpuuRtd4ryHYGAxXKN0uEPonimdv5MeZu9eAvNAtxhJ' + 'TndWlGsNIT55ORIA04aWofp8g== sig=M3jb679zGQrz9CjMb98spOevNoU4NurvQp8Yg/huSolc18+KXWPxhc4lKC/ne91oCk20' + 'wAQx2PEd8iSKu53pDg== e=found last=11 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3aktVCM10MLyCN6qPw0jpH16edO7bw6dRXE8RLtym4Y= priv=MC4CAQAwBQYDK2VwBCIEIGmcWwMp6H' + 'g29CCkpRPRjcIR02HYYKvDzYVc93n6WjlX msg=lPzLeAFFj03UdUuhPhGIi4vqKZj0rDeXYr/WXD5AWQxZvdfgq6glA9/yY9sj0' + 'xgZXq4UOQ2QjkNQqMpjnaPBPQ== sig=4o6jr5G8tRdT791yhVTLLoTuxdM02ij0wobQ3tcEJNrsdYw0u7Gljy3wMkqKCIwUsQc1' + 'VxTEsIU2pBDihYtMCQ== e=found last=11 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA2xsG709fe6bm0YpBA4zFyLSPnFCDGv3gKLkwXZiZrK0= priv=MC4CAQAwBQYDK2VwBCIEIOhf6ZkMh9' + 'muvv0af/JgYcjjh+K6STn5/lbKIEspf62W msg=d4yVHg3rokgAPMagYLoGPQHlfzDB8fmKw9+CAyWBUaQTapJhUsg2eGFLsyd9e' + '5L3723nbKIN6l6YhrMCU/si/A== sig=W+GWFQQcBX/JC0FvpCPViBD78ZszJMijxRKcXtRnpViCdP39olXgiccICN3Og/ahoUmK' + 'TklL0Xni+0287i4wCw== e=found last=11 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAB7jTjiu6AluKWhPcbMJFxoAi24wtHKNfMU9C1PniXSM= priv=MC4CAQAwBQYDK2VwBCIEIO0ZoqvZg5' + 'pH2i2txjGUfOVOLZhWbRTaS/HkjFhhXMpp msg=B1jtFojanqkiRmMRMBcHoXrq10HWTMQGucvBd5JOg9r18Sn7GQ62tH/365AZ9' + 'UcPR5L6SI45gkRyeRH0GtfG4A== sig=3QDiyWD2EzAYzHcu9oemchtN+nJHrqsfs+VUP4Gnx1CPEAAhV3Yrb73pk5uj5ZNDuL7N' + '/wKGV/j+hsoj/FOaBw== e=found last=11 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAD9bVrh7QvLnO/2vh5Ssv1pMOKjVKCIOUeBZVxPANJ5A= priv=MC4CAQAwBQYDK2VwBCIEIDaRkc8G43' + 'z4YX46iKJWbtML0Gd1jeB5kaYHAhsV4boj msg=9Nm1ZwF9OHaO+6c8byxT7DA4WcWmRqNbsY6DcgwAqp6POSpz9GTijG37hrjxN' + 'Ua8u+e514XeU6brDx2OuM3HFg== sig=AMm+NxaFB2ERAG+C5Js6YH0LuLfxdXaGjgUB4l4BypQuAIPFRWECPDUPiKFtkkLd8m22' + 'smwXWzbBeBQmHz4aCQ== e=found last=11 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAwPxVooOYPATcnM4+VVuRFH6F211N1I94pjL9FQ/qaVs= priv=MC4CAQAwBQYDK2VwBCIEIJgyFhII36' + 'qr5iVvqnS4v4dyUnhfsf1mZo/zv0XW3XY2 msg=q90lajF+u0nS3GSLKARwD9aM09QA28S/HLsAiLB7joHyAEJfFY6ys+McToGXM' + 'bHuAyKAUXhgY8J3pCKuJGH4xQ== sig=9VWMtuCUJnWwuyGKqfL5oVMc7aoGuhtQmRsMsI22UCInlv+CwozmbZ5f+JszP2oHVW2x' + '+oACsuSkn/m3TAasBg== e=found last=11 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtty5UzHE5OjNM0dV+Un73nWCEpEX9SXAOtdVvnKOano= priv=MC4CAQAwBQYDK2VwBCIEIOuJCXjVfd' + 'EpSxB40cmWOEHuN33Vs7XEgKnzXyVQuuus msg=fdEpSxB40cmWOEHuN33Vs7XEgKnzXyVQuuusU2CLaD8AYY+2HbObQnvSNxava' + 'y7NAVLA5wcjtlsRbhBfjdqeLw== sig=1QCLxLtalY+yUP0xWuMOhdpl73+Kbkb6OSUlLBhRudgl+EwWbeODq8sefed87M5/eU4b' + 'GXJZ1AQbYlJTUrxLBw== e=found last=11 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABIzpHZ/q2FRYIVolgXSty0IIV78SbNgeixUAK4dHqYc= priv=MC4CAQAwBQYDK2VwBCIEIESfQP8ltD' + 'EK09sdBeuBdJCWCrZ6lzRnV+vJDeqj3zFX msg=r+Dl/d7mrsmd+1hMVv90ptjpWxd1bQQoITnm9bZHuvNaoTHpOAlhUU4wImOkW' + 'cWDeDm8Pgbw8swYJX7AxVwNpQ== sig=9iILIdx1HiCpfk9eOEhb7OA1CJzb7qhBfgc8PXX5H4H0x1ekMC+zgNDRxmbg28BiHq5Z' + '5HWJxQ3fDhFZyscUAQ== e=found last=11 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA943BWCrqddCPqWxp4I8Mr6jC/QSvDw46c5LdHjiBuNM= priv=MC4CAQAwBQYDK2VwBCIEINSb9/HJM6' + 'D6V6RJ236xkdOc+UKQz5s+/2KqNXL/KeS/ msg=msRXIJwIyDJrD9orpYMn5gLAXT5jswp1DeryqWxnK9teF7Z9O+fH3Uu8WI3Um' + '/fxyTOg+lekSdt+sZHTnPlCkA== sig=snNCOoUvGWavs3R2ZqFg6Mf9Whs3lBTPx6200KKCReRpuM9vKu9q5U6dt0bhSGdr/K+g' + 'PmIwQYAya1OsHcbACQ== e=found last=11 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArvDvmY+Xw9YQcMFLZfkV/vhO4dx0V/y498nZZzw9EPQ= priv=MC4CAQAwBQYDK2VwBCIEII8C4L9oKp' + 'u19vBJefVwskXJhfV2AKEgo+cVJnSd9kCI msg=gdAv56cM6JMyIP2txs0MPQjS5qNtJ0E00Bc3ba7ya2qvZvl6kCEqb9JYCyXgl' + 'wWFFuYsnfRHwUgsZb9B71w6iw== sig=2OUWoOnrcUHb6IKYJWC+/gKiMojX2JQ4n1RamPgYKDgbb2zdSxDE6vu2n9DBcvi6Rd9Y' + 's//OSw5lYWAFnqSXBg== e=found last=11 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAjZ9fo188feZ3Ek39EpFAX6OC1rE7PRUBZIm2Eyj5qCM= priv=MC4CAQAwBQYDK2VwBCIEIPwXJLdsjJ' + 'EJ3Q6q84asxlWJKFZylGNaeUpjndCVgEXf msg=eUpjndCVgEXf6n9kNyIydJRiGK16gGo0+8QJ8MzV3vKLzBBsbrBQTL7KIzrKX' + 'toIlH4oro/dDaa97VU+iycDVA== sig=gURlNzID2Em5zuQpxi21CP4huCT97DJfKVJNtJKiYRidUJr0M5Xg2ffM0ySoeaHaw7yn' + 'a+Bp0uyFIn3jg3idBg== e=found last=11 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOff3r56/XDlzQpcmQXsAaGPUJXoTaMxWT4JB3QR6ApQ= priv=MC4CAQAwBQYDK2VwBCIEIAT1wftFaY' + '+xSWt5vRqkwKReGc69fDuyaB4+EHlDEED7 msg=irBUnXl7Wt+f+6eAK8skK8L8jZne5GTTo2KTuPofbTdWhzy/aDVHCwT1wftFa' + 'Y+xSWt5vRqkwKReGc69fDuyaA== sig=S7+EnEEp21tm3fGPMJ1j5RFX/lCLU5OEiCqfZWzb3TrJQqlPdoIsOQ9DX2xC+QuYbM0r' + 'cXmGb8/cjenqLs2bBA== e=found last=11 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAS8n5JxAl5aXpOc6IumYPgzaq+EGhl5gCjv5/SYteKxw= priv=MC4CAQAwBQYDK2VwBCIEIGacq7r9Dv' + 'z0HrcROukmNgn70AtSBbcFgMuNhTmKnBJY msg=TsW39+nqc7muxR8fEoh5da7fERd48uVnbCwLB00TagB5w/c7z17VwlPT02acq' + '7r9Dvz0HrcROukmNgn70AtSBQ== sig=o5Bg/3GLULzpO0rEJVFA0pCBDvYt9qv19jDxq5kSG90nKpe2TZaXBbgsu73rXb4nxZGP' + 'YJb4cCKafprI1fC+Cg== e=found last=11 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA8AacbY1mAXw6ibYvCdT0i7rKvzyX8f7UXcUjXjcdYIw= priv=MC4CAQAwBQYDK2VwBCIEIHEQL9at1Z' + 'dynBSsKcUXHmvfuPD25T7Axsd74VFV4fqW msg=Xg/2qyCC/85dy0DK9JqfHHEQL9at1ZdynBSsKcUXHmvfuPD25T7Axsd74VFV4' + 'fqWZOKu+oF4v69YU80WKyj5Dg== sig=GFMcZKo9UlyW7lc8UPohXh6ER7YPaOILejFp+aunfuojT4mFwSavoe0GLYM0K541jL2K' + 'WfeHYOtOTTbRWCiwCg== e=found last=11 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAX1TNuehcLRMwcmoD52UpA+7dO4dM9ip4BO6ukXMbJxg= priv=MC4CAQAwBQYDK2VwBCIEIK5wAdf7Ur' + 'MleZOEcaesrsQpd+LL+YjBSVolCkHoACi8 msg=TkSuKdge6nb2Ehjk5q5wAdf7UrMleZOEcaesrsQpd+LL+YjBSVolCkHoACi8t' + '/KfS7UqhywLQLaJ93aWNsmLig== sig=LW9CVbobw19sk7FCapc+KVxDDb3800c2YqDkddE1lVpYsW0lcv4DxtpjsSBOnVwQ6DKu' + 'yYUxYk10Lh15SoSdCw== e=found last=11 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHE4LmYF4PNv4lxODWJuxi0A0j6Pj8PSwmz+Y9ZtPdDc= priv=MC4CAQAwBQYDK2VwBCIEIC6uLj4tMp' + 'wKL5fDGE7AcY2ooEwIs4LZpWBCJWoouWA6 msg=t5xHPUo1BHNEnxd6aMzS2oqWinNSh07fTC6uLj4tMpwKL5fDGE7AcY2ooEwIs' + '4LZpWBCJWoouWA6rA/t+ob7EQ== sig=su0Mw63Dnu5GVTV8O4q/5Pa+d2aFe0z6PP/mMgHimh36YMwWGhEbQLjPbw3Cm4dW9i4Z' + '2bZ+ogHXsPjSTcUMAA== e=found last=11 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA779LBUMedNNSCjX7XaLV/Md8xwycxhVbc+YNqJCcqXw= priv=MC4CAQAwBQYDK2VwBCIEIOW/k5Myjv' + 'rrfTAoSRVTjhp9URY1kQDUUJReEy/sHPPO msg=ANRQlF4TL+wc887mZDCtz3hcxVDaP9pMrI7H6toaFmlQUJQSz3xcyo5V6lYaG' + 'OPmtHtBPpY2ZwI5aLtIcj62rw== sig=4hkPA+RDygUJoJGkvdHSqx4UTAP3o3bxEEInC318NIzM6HDvhiAWGBtRSiuMmQ+O8AOw' + 'OO+F9XIENUrc0VeAAA== e=found last=11 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgMnMT/vNMyNUnUKj5xdwUp+/m1cVN4KWKM3A/5HU16Q= priv=MC4CAQAwBQYDK2VwBCIEIFdLUd2yZo' + 'LmyA2/dDyQlwySeWeZ//PW0bw72XNqoz/U msg=9ZdUu4BL6c+GvVIpp1aDN/Sqj4cKJqhOmz4sxPPj9ZySNTtGuHHLHlNM5U1B/' + 'lZDvYq9fI72zndmFITt7q6uwQ== sig=J51qu/skXQLXLwPlCs6ewjUBX4SyDzMIjwJ0i/SQKUSD4FZbtF7oHsgB1edbaXFZcW5T' + 'WONwVVPdiRDW/xBZBQ== e=found last=11 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3guKyasUs1kozD8zvM0VirHC/VvewiVDnd/LiAy4JaM= priv=MC4CAQAwBQYDK2VwBCIEIF4cs/YxaR' + 'QLBsJDD6R0kFwhYSm/USQU7DiBzeSSUTgQ msg=Sn84dQ7/d9AFVW7Ti2rvhhyMMp6j4AEg/Qvz7eBJBAkDMTEJl2ZZOpqRGq8rJ' + 'T5uZlqH2qkMTqN+99AFNuOtkQ== sig=U3/i6yeIoSfTWUBiowAZKvdm+EpgYHuAcUGKd1yacBcp2XlVcRfrhqW9SvV7ajOzfMJ3' + 'pqSuNisQY8jz7LoZCw== e=found last=11 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1EQS/jv1XrsTnfSmdX8gfigRaWC1ijFu58tWErTW65c= priv=MC4CAQAwBQYDK2VwBCIEIJCV35Skiq' + 'OXeuk5neoQqoaJe9vRx3CyCyHsMRTOZ6uT msg=xyOc2VeC9hIbFA5PyRLA+8EpkFeampswlQztLvvhYvFXmoKbyXzh13x2fjboH' + '7yeTecXVnYtFMPe/zIeqm2HcQ== sig=vBbWaI0YnV539dv6Rp9lI2uhTLODgkdfWfD+ygbRzTiJtjvzHLxyZqmpVWZCjOzk8dQK' + 'rCn85S5hm76AzXHnAw== e=found last=11 s=32 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQm8JYWxnvtOOnXzqq59esG9rOsStg28BD41SN9cJ8wc= priv=MC4CAQAwBQYDK2VwBCIEIPXKA/f8wA' + 'oOvr+TrSrm2FQYl2ZHGWzhbLLeH2HH2w07 msg=bOFsst4fYcfbDTsy3+LB4QyGTWocVGLCcCf4MgOkNfs/Yn2IL+6W8yvBYyyl1' + 'l2bE3xS3YgwLu6Ro2Xyl5sMeQ== sig=JMxekAUV0af5UqMlzOrtZYw4sGOmQzdNDN+PYimZlassiRyj1OG73kn3QnPQ/llCXSPr' + 'SHMXbZNFVUoDxpCxBg== e=found last=11 s=33 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmU/ljaiwso42qg+bTDFhnMeZFySmeJT5v/YEBkiRD78= priv=MC4CAQAwBQYDK2VwBCIEIPaZLvV/lQ' + 'OMVNjxxSy3B7FoQxbcrY3/OpKBOBpW2Fe8 msg=oMnEI71JUEBpXB4uEFIkYmVr/Om1Rf4Qvwf3E1dd1DHYlGK/brEJ116MS/XuW' + 'qCkZ5n2mS71f5UDjFTY8cUstw== sig=CTe1opltJKHcucc3in4z2ECuTAAXsWGMCNZKm5XSYYZorSEStRaAyhB8q4Z9hSME/Xu1' + '2pI/mcbXKb+opkbiAg== e=found last=11 s=34 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAW83IcFI5yOFvbEWOEBVCCQj1yJ5vB9NIKJvx3GIkJmE= priv=MC4CAQAwBQYDK2VwBCIEICy/9Ak59X' + '8S+T9ewx3tb+MW3C6IgxEBfHSIYjpLJBLx msg=LL/0CTn1fxL5P17DHe1v4xbcLoiDEQF8dIhiOkskEvHlU34MeNgRu0cpgfu/v' + 'kEdtXcXkhZiinDP9f36sbUf+w== sig=NVD/+BRF3SbF64JUoMdjkMfa9JAstToqnAFRjKFjaN21jU9HpJyOdU9XN+f+WLD9XM5R' + '5pGN35zt/q45cYdHAA== e=found last=12 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEm+9ZGyK3v1OBkrllTnZfa2yWaFEX3qi6r+J64kSvS0= priv=MC4CAQAwBQYDK2VwBCIEIN1pCRQZKb' + 'Q8xVDd66JoBvdnMTOo2oY8ArqjUKXI+x0w msg=3WkJFBkptDzFUN3romgG92cxM6jahjwCuqNQpcj7HTCM1uAUjADKqaPRumnYJ' + 'BgxbrfTPf/E9YyHK3CvrEsB8w== sig=TmreIp/joleEZZ/opU4I6PtJRBnJXdRYSDJF0wUeupIH0GwhIrti8kwtG8d+rNcRwiA+' + 'ar3c1hm32bcVu7LRAw== e=found last=12 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFJeeUQg6+lZPMn+zMjq36V467RsPidke9a78aRS1uu8= priv=MC4CAQAwBQYDK2VwBCIEIK1akVONTO' + 'BoIMqRQ63fgUYyj1o7DeNdsKrC/Lgcxbfm msg=rVqRU41M4GggypFDrd+BRjKPWjsN412wqsL8uBzFt+YE01vYgpe5xg9yFRAIO' + 'WrLrm3bSottKXGqj3P0gPMQ/A== sig=5xQ2b0uRRudIlO5LFq0sAbtHcndGyrPzdpKpPGJikm9IjtNLQ8K7UU+uukA2sowTw1Dp' + 'l9+080EBdzd1rKVGDQ== e=found last=12 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOSK27uFAUHEz+iej3U7ise+To+dgXlZj7qdGIc0pBk8= priv=MC4CAQAwBQYDK2VwBCIEIFsjV9xhZO' + 'DpsNePXOBpgpvJIfbymUV3BmP42IJrE8sF msg=WyNX3GFk4Omw149c4GmCm8kh9vKZRXcGY/jYgmsTywVU152GWVKE7CnCs0MRG' + 'BqvgIMkt48An0F1EdfEYlQUKA== sig=J8gHAPaOT1C1szZVLg8ZyHDVnmBgiov461c12M4AadegzaJNW1BzfzKRiHh5zKTUkbKo' + 'seb9fL1DDMdI2VyfAA== e=found last=12 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFTSYYcPJ9QmYXPbA7v6C6hhnHpqDL/xUzYUX4DnIvIA= priv=MC4CAQAwBQYDK2VwBCIEIJ7nDv0NCD' + 'Aiv9NyFJSIqxvDmP5lncPm+lbmgPF5Wdaj msg=nucO/Q0IMCK/03IUlIirG8OY/mWdw+b6VuaA8XlZ1qOHmhVULN1J+hL7AHJGA' + 'mNP2ZLk+XrHZb9Hp12Fgs3TFQ== sig=csuWC+zoLp8FvnYDf/8xq4bWUmGYn+SGMStgYBgAFrOasBNptsPpaN+x0BcDBnJjNz5M' + 'SO83XkSAQOCXvGkhBQ== e=found last=12 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtivgcUIUUJhkhbDl1vFfz7Mwp+HbetVfxSeuGZr6rus= priv=MC4CAQAwBQYDK2VwBCIEIDg7N0fOrl' + 'K2drBjkm005gAM+awo73mzXp40X5CZvk0c msg=ODs3R86uUrZ2sGOSbTTmAAz5rCjvebNenjRfkJm+TRwi69iX71pfV9gLVCh0f' + '+nZRIsLCbyUWGuP2ifKiwtX3A== sig=uf2UKrhJryRYbIXF1aEyxyHUKw9nG1fU+K50rNudXNKPftgH+pS0u+IO74TPS7Z1NZMR' + 'a17G3JbwLuGj0aPTBw== e=found last=12 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmzojeuftrTUqKbXSsvym3Av9JMkY0KtljAKjwNfQ0BU= priv=MC4CAQAwBQYDK2VwBCIEIPkUAa8PUd' + 'Z224AYbJqmvjbW8+sqWcCplJxNlNpK91ul msg=+RQBrw9R1nbbgBhsmqa+Ntbz6ypZwKmUnE2U2kr3W6W3mDs8Lkp+C+deHO2ms' + 'PKMarqW+gDL0C0nLAzClVARRQ== sig=wwtxSI4FQ6Q8t6hvv1Puws91thvXs40WnBvyTq4/9MZla0l5dMiHUc12akkBZpZuPAMM' + 'TQzfjjEwp03eqqp/AA== e=found last=12 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAequiZMG1y6AaLfMFdLm4Wbf4AIJv49lRhxdoRq4cGGc= priv=MC4CAQAwBQYDK2VwBCIEIGtSt5c58Q' + 'bHsuU6GzR1s68bJLWxeArMajBfmMnv0fE1 msg=a1K3lznxBsey5TobNHWzrxsktbF4CsxqMF+Yye/R8TXvQQ0N4euyI2e2aXObt' + '3x38ZNMgqX2qq5KoI0KmOdtQw== sig=qlK7CB0SBHNzEyUnrQMQcRkUGBGk9E/lBb/oqD9UF4xf+FLyFrMQIqzrWe0X7zM+q3ct' + 'jba1n57OHCQmgqQuCg== e=found last=12 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/ULn6wzVVVQq6kGbfA0+E6TuBtDbS63UeWDmPLZc0hA= priv=MC4CAQAwBQYDK2VwBCIEIP/1OwI1xl' + '+dz4QwU0I97vMjjXmoeVnIEJDNH1eznu+9 msg=//U7AjXGX53PhDBTQj3u8yONeah5WcgQkM0fV7Oe770O0j/ZDrFplGEMqnOXJ' + 'ldC+kfBoZAVt1joyh6YHvnvkw== sig=FfbMX4SEZM9ydqCtMPJwoeKjW+AaET+BkkJ0m0J9Piv+Oad9Pcjw8DnsU4zShVN/ZVuv' + 'u6rrPavbToSSMVODCg== e=found last=12 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmhP6v7V5ugQBoAtgf4d20a5KBD8VyQhL/CL+hGd2vdU= priv=MC4CAQAwBQYDK2VwBCIEIBgyzg9CuN' + 'IZQm7+1IV4iL9pSK1sinOwyDIJ0k5UNS/0 msg=Ms4PQrjSGUJu/tSFeIi/aUitbIpzsMgyCdJOVDUv9Fj+z+hVCe9D69Ptn3pJq' + 'ux78REOUb5xzgpIbt2tOFKF3Q== sig=UlGDokcJHqpd6cEUx7akEsYUXF5/rLz25e5MhR/t5SRLv7ufFkFPyGG6r94RlPvtgeG6' + 'xMtpW2rBioGMMOFoDA== e=found last=12 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAepAtZIq+a6CM+1vDB51EVo8EwtoDmWXdgFWq3qigo60= priv=MC4CAQAwBQYDK2VwBCIEIMwtOfx1KB' + 'QfSItOIP+zlIClskqD3BIIBCLUWDiWMmMk msg=FB9Ii04g/7OUgKWySoPcEggEItRYOJYyYyTw15PeuxBl8wt7V+S5Z4vbfjsIF' + '8nS4MHqWbYVHNewk5i6gMvaTg== sig=MZpuu8Iredwb9MhlYcABX5K3rTsorsYaEywclDfKmSFEWDiTev8jYnvz2bAmKOoRacCU' + 'HHB0zDRvt8DeM39tBg== e=found last=12 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA69Ilg5U3k9/aNFsWzWUyePGvlJKy3YQo7j0OziyLmsA= priv=MC4CAQAwBQYDK2VwBCIEIDA8TW4d3U' + 'T0SHVEkpIuQJ26Ypq9czE5V2dPosi9n3rh msg=RPRIdUSSki5Anbpimr1zMTlXZ0+iyL2feuGJlvvx1ZOft2R1NsIgUyY0d7e23' + 'xRkip8eKv2C2S1fbcVODaKUJQ== sig=0YoG2ZEEIrzSJsKxx0UetO2rZnL8TtiSRbJivGfqksdhusGOrks6cHvQuvMB0gixdydB' + 'zUDowwqXm+vB/qtSAQ== e=found last=12 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJst4paVQsxtSI1xhRPvNW7gg8B6aAGwmIrl3tqpv1jA= priv=MC4CAQAwBQYDK2VwBCIEIMEFKNc+VI' + '4o9kJ919b7xnmRoQffnODUS3A9HlGuFsdC msg=wQUo1z5Ujij2Qn3X1vvGeZGhB9+c4NRLcD0eUa4Wx0KC9oAgrfoBHeYnjS8cJ' + 'xdOhZRZqPAeEG/BxX2RgfJWwA== sig=TTTycy9qze/aY5Vwx93WEYClLWYLnFL4TncJ937fVVILRwI+2V8yBS01LYlwj0ID8lDd' + '+HxDTvhOId5NcnU1AA== e=found last=12 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAo9fwcEHKuH11H/JsQDk11kQVxtot2R4rxMTF19TUabA= priv=MC4CAQAwBQYDK2VwBCIEIOloRnMarN' + 'ksIRe7EJnvv3pkg/yxneqP9nG+NwU/KWx/ msg=X5OdrbYcf6fFvEsdY35n92oy7ygmxXJF3axPP3GHlKKLqlpUlJ+Ah68pKkFHf' + '2pbupCSCdpxPUQxBHJEbkAYkA== sig=98LPk1Qe3lcnNlwXX+DiKDK+d+PDR9TBFf3n1f+f+W7YVsRe/NlYSj2VHzgXS9gqygXp' + 'k6q88HiWKyDeO1/jBQ== e=found last=12 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZPbYTPjv7DY4oZGhMDQKETWh3yPc+HeTl5eZFwTI8rY= priv=MC4CAQAwBQYDK2VwBCIEIDAZ7t0fFx' + 'Vb30Qn/HhzzFdQxOA8f5NGWpGLXfe9cQjp msg=QLKbwsAYAJjAPnVDhgZgVlGKAOTm5v/5+ZYwy8hhclFbAfbpdClikuw1/DL9R' + '9EPcuPKlPtQvNYoDD7MGqVI6A== sig=CozqDl5GV7dD88twWjB/0bgvuPM5wWI3a4HQoOwyR33NLisM1XdVnrYiIXP2s4Qc/vdT' + 'nVsFh6/CcLZAsmxHDw== e=found last=12 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/Kck1CUJbr1/3T5cr7kLrdcBMkk+FPEvYBFuIF1SHqo= priv=MC4CAQAwBQYDK2VwBCIEINHyisn61/' + 't+tWBse5UEP/xNO2QcvhCKZ9kku7djemZH msg=e5UEP/xNO2QcvhCKZ9kku7djemZHaEYu1RyXEdSQ6ttS7KeBqUv5c+K4p8NtN' + '4xOMmShW8t+6jbcaIsEYndzYA== sig=5H3GweaUrPFECqwsKJCkH47Y0/WGRzlJM4I/MLpdn0lV32j37NYEnMq32+P+bG16vJjC' + 'Sfp2/ktvNRz6rgKxAQ== e=found last=12 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1dxOtQWuKls4NylCfsLcgvtLSynhui7Awz882Eqhmbg= priv=MC4CAQAwBQYDK2VwBCIEIBDbu4zBmr' + 'Y++EJ2DhcMk+6ypPfT4BTBamJnQs7ysqZS msg=mrY++EJ2DhcMk+6ypPfT4BTBamJnQs7ysqZS1THQPXP/8CYJqKCaiQtyeKub7' + 'mxOO39C0aLD3YG1BcILR5WESg== sig=8Kh9qxOfD/gDqYZwHI572L/9ofvdPnwV6n1xulNhuqYCDYMPuy3GvuA9b6RXKOBlYbBq' + 'xmqfwwC7RodoY+q2AQ== e=found last=12 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATJMDnSuY3FTuoIs54vbRLSgqd5rnd007B7bc+K6sJcU= priv=MC4CAQAwBQYDK2VwBCIEIAD2g7JPRK' + 'F3+zDLSZn75cGesg7l5for7yVOCS6y3/tx msg=5eX6K+8lTgkust/7cYKUxa6mcvt+dRmCOVwsP4Cn09E8QbE5TCH57TN2kcAkW' + 'vUIMbGHdtb32qToyObyIfTuSQ== sig=R/rkvbOp+Ce4e3fr224ir98dupq6jQLFowMv1xMCbLvz+r6QDcNRw7Cxet+7JQC8co/P' + '5qhBUwUyZiNl8qX2BA== e=found last=12 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHGMP3MXWwAVS/kaf79qjrTKpe2hVwpUtkuSRfKUTxp8= priv=MC4CAQAwBQYDK2VwBCIEIE41vi4rws' + 'Z7xnn59DSpySOLBJF/0MNKGniVzThv0Hbs msg=p6ifOZ1/BNOnjoErAcPgQaZTuxaqvA/gZmcGrcu+jYqrlCMapCITN3ToX7Opq' + 'xPr53Fk0VSxQWgACEegc0hSCw== sig=boTwhqxV08H/7Bi3c2QfPmGC4b8bXE9URd8E5Okqo0fdjPfJN7qPqwxTjQTLqRQUZXfJ' + 'nD6tb9/ejsr3gKIyAQ== e=found last=12 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQtkg0iGRNyPYVE2/sY3S6efT3ZXB6RhbBviGtS6GnyA= priv=MC4CAQAwBQYDK2VwBCIEIJMux46hEt' + 'Vkqt243pAFevumK7wxtyYJ8zYRj/oOAlNz msg=1WSq3bjekAV6+6YrvDG3JgnzNhGP+g4CU3Oq4tHjrMgeAIsHWXciHLrIPi6UK' + 'jlX/1dXS3ydzoTfbP/ZeRGbfA== sig=lydECVEyiqE/w8JoFnxQzDS7Xt1eHQT4u9fTCMDRcXG8U42b2E3Yq5OFACmQKn/oU59N' + '7jrf71tHSjqdv9NyAw== e=found last=12 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/OmFLvu0O0a2ON8O4TS40VGn0vJZSW42Gg2lm2Erly0= priv=MC4CAQAwBQYDK2VwBCIEIMg/+wMPwv' + 'Q0/+qTKt1AqcoFid/0yAuvQ9AQrn92J+Vi msg=Pi9r1cHjxVXVFs7EShcESjWNjRHFTfGYV9mBnCK2GjV2EETY4j40mqxrrj3VX' + '3raJ8ClLPBFJCGX7JE4QpENig== sig=bxO56ImQg+BRwxkUHGaP9HliKV1DCBOljlZQD7srPCxY37mDVsmJoCzOxadANNjnaw3X' + 'gWnH4Uycabxv8El/Cg== e=found last=12 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIzAZNck1AFc1c4RErSpah+vayo3L+hscNcjO+HhEzWE= priv=MC4CAQAwBQYDK2VwBCIEIOLO6dcp9C' + '8jwKOQ7tbZx57AyuuJZ3T0zF0igVQToX2K msg=ajkRb03guHR56eLO6dcp9C8jwKOQ7tbZx57AyuuJZ3T0zF0igVQToX2KJ+a9a' + 't5Zh/Ju7bKqyzl1VsHnZpre6g== sig=eMYCzL1cHPGkilCJUZl4mLuPbUYEBzeMIQcILs63O+Wg6rmmZmaXNVReCBjEPyE/62PK' + 'iTro+5+jq05UBRQcCw== e=found last=12 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPOnmSUAOJw3LEsxnAbTvJ1Jda3NKn2IzfA/ERwhA6eE= priv=MC4CAQAwBQYDK2VwBCIEIMONbT7N14' + 'FeoYPtftKu2kVubr0y0dr/s9bDndTCXjR7 msg=fYmjOCcg+1Z88UphGoc/lgy6r4Ve/WKNXdqjXSy8viUSLVXQR6EB1oZ5cSwU1' + 'NUufpYEjb83s0xIzQAgU80Erw== sig=tDi8YGJp2Hhzh8iGNp5ydO+wLyIxRevqHBhizRPHjEhgjLuHmBBZPVBodtCkCGRxZX6L' + 'EqcWWL0jLTEIHXTACQ== e=found last=12 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAfKd4tnhN6rsfQxQZiDLNIIN5GlVWVwHjNY4kAt6S4fo= priv=MC4CAQAwBQYDK2VwBCIEIOcJBImbAL' + 'p3mbS9SanBcc6l7kaUV5P58ZDFWMco/jfV msg=m+oFP6Xtbx2WmuvkkbCtE8P8kUOOw1+cKN8UGI44C6hW2VJA+b8icAq4rQlu5' + 'wkEiZsAuneZtL1JqcFxzqXuRg== sig=T0ufCo9+um3cjh732hy/kAzWCxpXsJSwG1w5ZbC4cVP4ZygxlRWecxA/5WsMVwW3qMbY' + 'jU7yF9Gg8bOdyhTVDQ== e=found last=12 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvUYdF8RPPcFhFqquCn29vCjVFdvlNJ57DmxsQX692rI= priv=MC4CAQAwBQYDK2VwBCIEIFWmvj6WfN' + 'lrspGPgOVyO6FdS7hSki5D/S38xvGZRUSM msg=ri0YKU60+V60OpnFLMlY8dUsE8qGmxkeirNPGtnVqNWLp2gNFHIjzwWq3QkpA' + 'OVAA7lwR85HvnDtpYjc1hTFoA== sig=A0jtHx1jXDMApfw8i30L1GmI5dmjNjhYz8uGZVw7LHO6ocPitho0l8a0ogFkPmGm0Fh/' + 'xSdYPEcDn+g/vZBhCQ== e=found last=12 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA7n6N0aLdB/G6ul/WCLDBlIfxmOixL235mJoyaDfBONQ= priv=MC4CAQAwBQYDK2VwBCIEILbXQExs2T' + '1ZP+KQt2fHapAMZNewXwhHtFmpQuDtm2ne msg=YMszv0bGihq210BMbNk9WT/ikLdnx2qQDGTXsF8IR7RZqULg7Ztp3hn1csqGx' + 'NciPHHKT0aqzvnJeoz1MaHu/w== sig=SkQ1zvLWEct2dHYH3yAFwSOROOdrX4ycY4eEOoH6TY+9sAO374/dvj0RdxghlGArYmdH' + '9wrIrkDJ9NsE7UIYDw== e=found last=12 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlpjggGfj+IvKfrHJVT4sr8jHfMKeAzOsKugzlSUg2hQ= priv=MC4CAQAwBQYDK2VwBCIEIAASQWVl9/' + 'QdtNLQdNNkmHCsb6y11nzoD0/h6RDcYd+A msg=mTs4+1HFdIJZj3zDRFicO5M3XRJzNT876agDrvkAMabJS0LQbAASQWVl9/Qdt' + 'NLQdNNkmHCsb6y11nzoD0/h6Q== sig=+GUcXpmgIMXjHukGMMQO25H6AmGlxygHQw++YmPsUIpbTzYZ78X3lNSrUSp1cSVaC6Ad' + 'XpzOg4EeVGsWNQv6CA== e=found last=12 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEASlyElqW7pbtb/30iG639z99G/kTt2xZ05jreOMI1vME= priv=MC4CAQAwBQYDK2VwBCIEIAbY9YnfF0' + 'JC+Oo8+qCIC35kK5FG7AdPZQ75MdRx5c+z msg=IkI1IekmAnndmThaZ+ySER6H+Hzdn9eS+dUIE/tJGjFDKpZfZxKK/5eEkEXW7' + 'yBJmp+UScrRb0va+SHbBcXgsQ== sig=JF2QMjpcTnMz8UPQ7cJbNbNsiQb/e+0ZzQYZm/9ZOfXxPxLoifQz2cYoXOFQKeJnVwnM' + 'eWpmBMnW8OOrC5R5AQ== e=found last=12 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAoG1e1et824NdcyVNIYzoZKkyFzRREizJ1EcWS7Y9XEw= priv=MC4CAQAwBQYDK2VwBCIEILOYDXNWua' + 'ws5z72uuCq+cMUvDIEQQ/7v6DNPcLth4xc msg=APsJZgnIYOF5hhlwMBMzfp05MkyUM9sAvdrdgZWzmA1zVrmsLOc+9rrgqvnDF' + 'LwyBEEP+7+gzT3C7YeMXDW/0w== sig=2MRqHwLn1U58A7uICCcAG3Oqp4KschHhCGQ2MKTENgIV7vXCQUwdHaxTsZtPnBEbg7wX' + 'XASFepkyF7e+bqUWBA== e=found last=12 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAuyNaLKSQcDYRFUSfOmkdM8LrXpbZTBweTftg/AJjlhs= priv=MC4CAQAwBQYDK2VwBCIEIBH0Jr7nVx' + 'xvqERti3jHUuYIGqAZ1rpjqQL7rP/uX8bi msg=vpTYKheGk+qz8aaiSn+RsZYM0cAsuqtiEjP+Y17niYlh4d1QEfQmvudXHG+oR' + 'G2LeMdS5ggaoBnWumOpAvus/w== sig=3LDCKVlRmNGpKuvH1Fx2RzbvHhYKFwNrLkNZIOiXozPqzZzuiQQIm2A9gmdynniH5PRR' + '/rVM3zANySf6AGtLCA== e=found last=12 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAGieV9F7tI0EbSSdPYENA0m1Ev5ARTu0eRYGqdpln0Pk= priv=MC4CAQAwBQYDK2VwBCIEIJVIgzzDEb' + 'osyqseFzZ7QJFxjQiUMe7qgLcgTV3dCma+ msg=cY0IlDHu6oC3IE1d3QpmvnDQL8muUBxj3XSOll+0tsWRbbtvZ5IIKXR3in7CN' + 'zdZJWrpnEzZ0QyOb1bPZWJIsw== sig=FXdlfVNjpAJbLBuJmpaWbLUfgpRS9Fvo4V5/chb7JNXIySGcrDYguF7WiMc6Zjh42IAy' + '95Ho1IQY2up8fv+oBA== e=found last=12 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEb5rFpjJbMqC7ARi3LG2WE0inazxeULil6RuWr8zilY= priv=MC4CAQAwBQYDK2VwBCIEIPbCxtrfJJ' + 'mQfskKZTLuE51/GTWKONfusAoTkyg6zioB msg=TcYRfGbWk9X3iCuR8w2Up8rLfUyMYEj2wsba3ySZkH7JCmUy7hOdfxk1ijjX7' + 'rAKE5MoOs4qAd6NHwPVwqpwDw== sig=fJ30iTh92YlAKdkdFKjoNfYiNcxj4hHg24zra04P/dQI1Ddjd7dyWfcZ9xDX+Z07A3DH' + 'gJQtzEDGvVMfbJWPDw== e=found last=12 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAyRBlz467LY6UINeA2Dtofbj7W++8xhuhoLtX0NtyriQ= priv=MC4CAQAwBQYDK2VwBCIEIGaX7x4PDT' + 'ZS8tAzllGR3KSHccJhxtzjCFgrviQvTbKt msg=dUU2xq82I/cXXRbNegr8Gwb9vOgU06Mn50oYB040xBcA5WaX7x4PDTZS8tAzl' + 'lGR3KSHccJhxtzjCFgrviQvTQ== sig=uF+xokfQPW2EeKqVt6xs9K1xa51HwCjlOGPFv9Jk8Qh9mO2RBuaOSSN+SwWrr3eVOyYM' + 'Oop4EIZnlfyXtt5HCQ== e=found last=12 s=32 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcI757lYVXr3vD+c6uVDQtYUMxAeJzbK8ZEYjznz7XGk= priv=MC4CAQAwBQYDK2VwBCIEIM0O33PpBp' + 'pcHdqMKKi9IHyGPmpMp9dc3VDPBs7CESjq msg=KOoMYUIo+R/Qj1n/J9oCxL54Zgtu+3gMg6ga4vSeeNraFXWJDwQT0yiOsEr0R' + '/mIfUjoYu0Nm6OfOr+FMgz1YA== sig=PD4btTeGE9rO/48lTQ3ajKOvP6zCKiGLVT9nnYRaOC9yXNUNlXPtZY1fFLCyPOcSSD5x' + 'rTOx0Bckx7NQ9TpqAg== e=found last=12 s=33 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPJjaIfpDLOspifabH6D2aDwg7TpH25/VzHGSbtVvDSU= priv=MC4CAQAwBQYDK2VwBCIEIOnr4YF59s' + 'c/nZrkhBQB4Am4ENC2H8bpDDlsDeYja+KV msg=iyW6xe/p6+GBefbHP52a5IQUAeAJuBDQth/G6Qw5bA3mI2vilQmDn0qF2CY8/' + 'g6QkzVxXu+f/vfastRhJjrYng== sig=qLhDBZ6PhheR36GoZg+yDljuvMg3SzJRfEiv3qo9hzuCPStyKVkVx2iz/e56o7r4c5Nm' + 'N36z9KrSmf0RzsddBw== e=found last=12 s=34 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0aF0QLsxlvFFASEPI+6gV3SmPkkr/iZmxmBrNXZCkz8= priv=MC4CAQAwBQYDK2VwBCIEIONNP2HD9O' + 'u4XI/Bnrspd0k6vfLflkWQG7b1gJHMEW1A msg=vw1PPX5U0/JkTyWUUZfxfVs2vW1pObKc+gpbHSozrb9KH2vnc5PmNYl6tkT7Y' + 'Vudp9e/VMEtD5192IlPZgH4GA== sig=t1jj+Lz1pMmtKZq6QLWUQrT+7qJKmoxLAmee0GfViTq6rzv8hKW4aUJu6391DDnEdglc' + 'tvIm7brb26+tu+yDCw== e=found last=12 s=35 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADpZMbzPavsucERbuRFdHH3+6JBMz2XTTZ2jIesLl4cI= priv=MC4CAQAwBQYDK2VwBCIEILWt5ixReJ' + 'ZYe4f2XstytJPmTR8y8ZrRZHcZHPUm0NJH msg=XI/HQWkU+bdJA0/tpg6XhEtMsBW4pxfN3GsUn3lUM3rUkCwduAWm90l4uZBFl' + '5c+RsR81Ca3yiaeStoBvo3utQ== sig=C0bitsFOyYAha0A6Vkom/DsQyxZ51abNay9B09xnSAzZncpDbPRmMvDk5cjPiuiUOfcB' + '0u/ZpGoeTbxxxoifCg== e=found last=12 s=38 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkmn6//0jrnVpn8ogZoIbMOsAeDnZXMA236IoPAeT4b8= priv=MC4CAQAwBQYDK2VwBCIEIMsq116JYX' + '61g8C8OB9OCZasVnThds7p2iZhKPZzfhDQ msg=pvJekBSTmWn5BduyVE2IZDrSMnyyXok3uDq92niROMJMiKl05dmMlCzgoZZ4X' + 'd/SBXx4f8mowqjwMwyxrKAByQ== sig=sbidO+fLkeEQctgZkgNqEvGBxxN+KP/7BuD+AmXFplixpmkgmu+bmqkICf+uhoZxIPix' + 'Fq4WYaO8DVMyd0wpCw== e=found last=12 s=39 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAG64VYGT6s9NGenUTjjYPHU195IyeihSrCuERKNoRnAI= priv=MC4CAQAwBQYDK2VwBCIEICe71DJWcX' + 'WoOp+bfiEuHFUMqUo3UcZGjkNflThdz81g msg=J7vUMlZxdag6n5t+IS4cVQypSjdRxkaOQ1+VOF3PzWAQxItjFNWhWkams4pqd' + 'q4L/r6iGvrX8XR7NVBn3xfPtQ== sig=eO2lLJs6Zwk+Qos80FbKQzgbRXL5ZenSyUKdr+iXAy7YBM1lrQhabg6l+ZYbsSSdwXT2' + 'ys5uMfCdrOAUMYz8Bw== e=found last=13 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlhhN4dsZYSmQiYmbgc36PNa1osuDEmg3VmaOC/ekrHs= priv=MC4CAQAwBQYDK2VwBCIEIFzg66vWe9' + '6qbgRK5G0PeTofkgtIHbN9yJOinYNYbSLG msg=XODrq9Z73qpuBErkbQ95Oh+SC0gds33Ik6Kdg1htIsbbd0RKzWoS3OckzdQYS' + 'bWfqvHy7cQxYbfOl+j2+75A4Q== sig=pIR2HzA3Z9pVNoSAYKA5cxr1x05y92yJc0XlRPFnNUGLLA78RLP6H0/Yl7wyXIoM7xci' + 'CHF8BUJm7p+EjKWhDg== e=found last=13 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFsiQ5P1JWvVonc68/C+8cySEt3gJ6R7b9WBqpFaNIws= priv=MC4CAQAwBQYDK2VwBCIEIKNHp5drcj' + 'ffIf6d4Ya4mJl5i7b7LsoiKalOpSYD27OM msg=o0enl2tyN98h/p3hhriYmXmLtvsuyiIpqU6lJgPbs4xPVuNCKbQdG2uUpvhv5' + 'CM7kX9kW/A4CyI8+szm691dFA== sig=YSIJYOb1MXLDSLBitnSBJHyXLGjso+WHY2qGQtnzxEcaSrjoszlOsX7wDK41EqqxEh1Q' + 'xEzzAERwFCoz9ZrCBg== e=found last=13 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA97gOtAmQSeK7ARsCH91Mq/7LfN+m2s3VtZ71xbtCzRI= priv=MC4CAQAwBQYDK2VwBCIEIPipiHDZXv' + '+TKgIz5HMkPjoMnEbnCbxGT/jPZvbwomNa msg=+KmIcNle/5MqAjPkcyQ+OgycRucJvEZP+M9m9vCiY1pnPjeDEbX19ZhZpXnnk' + 'dVdmqtKw6C43hF6jXBeSrGMhg== sig=2nTzMWeWuMu9hdq4KJ6HCk+/ojosFi7ESqtmoM2ghKG5OXHkw0RGz58jeiSjsfqGXhP1' + 'fzH6ju2sLowN9VL2Bg== e=found last=13 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgCymeYN0uEwxuIpSaupcY9+Zf7fERcPtL2FQ+EuZZsQ= priv=MC4CAQAwBQYDK2VwBCIEIGRa9bCJTL' + 'KrtUkTHsJZur9Z6YngbXsYMK0Oi4zb6hD+ msg=ZFr1sIlMsqu1SRMewlm6v1npieBtexgwrQ6LjNvqEP67P1jXrkb6C1EkC9wd+' + '/mvH5Hmiz3T8Og5leSCJtPXdw== sig=cW1VLAeoaRH8s0zJlF0vQ9bZbo01fc7fOr4N0IrvzmD61dqmhp728hCHld5/6V0IBZ/a' + 'sMsFse5P89cfjdX7Cg== e=found last=13 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsvdPAxLAT8bEiLqTr0Yxy/21h7KV4VrLgbVe8darptE= priv=MC4CAQAwBQYDK2VwBCIEIP59ecmxOT' + 'f71CS7nc+ExobtRb9eeHYjGffMwhEXs2Ef msg=/n15ybE5N/vUJLudz4TGhu1Fv154diMZ98zCERezYR+Sifx0NKL3tLixYFWRj' + 'L3O10jtyhzYxiATbsyrqOnhPg== sig=v0Ys2hpGUV3Fh7QApNxavPoqC0TgItbKDprJb38VbNXFSQBXxq9CQ9sLiEELgEcG0o+0' + 'TFxeX+JEZdhCsTS2CQ== e=found last=13 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdIABRVuoo1UQCYokC3CX8sANT6ws0RjFEz7sNirtKAU= priv=MC4CAQAwBQYDK2VwBCIEIEnDb80n3j' + 'NdAyd/AiCBZa2wc8t9U/AUFLO2nkeXB874 msg=ScNvzSfeM10DJ38CIIFlrbBzy31T8BQUs7aeR5cHzvgrFVgktZCh62C9iGPoS' + 'fCd7GGJoJh+MQzJPEUR6Gzr+g== sig=7TQcpPHVoKNDwKtCaXXnLBre8K9u6hbJDcUOA/HhUtnhldAwx2TO01EWHHNu/0VasqMD' + '98WtHVXWGr5+ACx0AQ== e=found last=13 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAh8CPfDa9KaNy9LxLwLIakynEgNSwr4kFAYvrg+vRyo8= priv=MC4CAQAwBQYDK2VwBCIEIBpe5GIP4b' + 'FF00tL5et4rHhLFssxLj8ivJy2F+t4IF3i msg=Gl7kYg/hsUXTS0vl63iseEsWyzEuPyK8nLYX63ggXeL9aFLawzwKWsaoZy24F' + 'hEZ+xY/41NZdsr+5Mp0i7VdrA== sig=QjWXXiosKt8Q8bqgUe6q5mnp2NlVNCStQc/MYUHssNuNMrmEuqoreBx8tFBDlXkpAH/r' + 'WFmEPbZN8F/5ZTzeAA== e=found last=13 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3/1d+ZjhAKuFdijcaryEfNNhjpYEqtbCQDeAwCfiug4= priv=MC4CAQAwBQYDK2VwBCIEIM19w9f/Hb' + 'xiiqH+gZ4Xnpa47h7HxE4sBbwLqm2s+PEr msg=zX3D1/8dvGKKof6BnheelrjuHsfETiwFvAuqbaz48SsMOuWE7ZJJ0X36AOIGl' + 'cv+48QSGEvNFIcnXOZju4Edcw== sig=JzpFAcAWo6RGenAfpcKyLDyF/luaR6+x2I3wkIWY3/wzY0QQKq73STCTQ/rB4fYp14TL' + 'tJ9EToSZ9M0cFlDFCw== e=found last=13 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+OUjgNQFXn5upYUIdJZwWRN6J2PkwiBGag9t7il8Zkw= priv=MC4CAQAwBQYDK2VwBCIEIBVwJm95j+' + 'PaBINhIh0pODbdHt81xtAwLoN4lo66zlyI msg=FXAmb3mP49oEg2EiHSk4Nt0e3zXG0DAug3iWjrrOXIiuGmv1+Px6ugIGJwzcw' + 'J8QAOCthorNWmPIo34mZn8W8w== sig=8D+LS1dUKz3oC07wZv/M9TH4QmSmi/IwsPWW8F2I8Q/rjCnFe4DJuribZlsK7/Otqoe7' + 'B55nd3WHLV7hhU7TAw== e=found last=13 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgIPQalfnDN8siJ/xF/40xZfWI8ITus3QYv5Hu5F89hs= priv=MC4CAQAwBQYDK2VwBCIEIMEwVk8jif' + 'yN9oUKrtJCLZwn37985MhpOQ5ceRDVD5EP msg=wTBWTyOJ/I32hQqu0kItnCffv3zkyGk5Dlx5ENUPkQ+tiqcgkT5Dzkxu0oort' + 'VlcuE81sli+sScNlQ9XxdRKRg== sig=F7UfmBGyYna63JP8anFuiltralSo/1LtBZVK0UsocxsniI3/M9ha+rpXvvDOZNsNQ9SE' + 'RU9mjdpxpO+bUpBCCw== e=found last=13 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIMWO2oYT+4d8dndcvx7VItYE3jq8sH67tXKyjKSuYJQ= priv=MC4CAQAwBQYDK2VwBCIEIP+ua6gsob' + 'hQVMAx8z99QGlPgnAZaq+65ZIR54MstXLi msg=/65rqCyhuFBUwDHzP31AaU+CcBlqr7rlkhHngyy1cuLBntgxtLSWIv9upeCHE' + 'p+ubJWzVlQzouwSod6JXZueFw== sig=dPyfIMCYvCpf6TxQ0IPkjT6zz2R3Q1Orfy66aVTOQ0SxEtqtwbJsqvNxBPgzaaCI88Bw' + '+C4q4mWnIQWc+jLgCA== e=found last=13 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAG6JI49VyxH55EHbPaSYO/hQ71fiQPd8tY/J/chSoYE= priv=MC4CAQAwBQYDK2VwBCIEIDS5SSOfeG' + 'kTkJLXMoKwMhkyZzeiVuTWlndHxoqLTO3h msg=NLlJI594aROQktcygrAyGTJnN6JW5NaWd0fGiotM7eGf+9O6A3v36QIAG6sCS' + 'hhmmhIVKBRfamU+yuqnMfN4pA== sig=p3wKfXjQvx9+cz5pUa/huKeGnlMxyGrjyfQt0/w7RcVVSQAwsRW92wlUNBTgO0m8uHY+' + 'lWXjQmkyGl+zDQPjCg== e=found last=13 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAXYXLxRI5OE+1t/JndjW29EWlzs5HKCNSZb6u+AtRKto= priv=MC4CAQAwBQYDK2VwBCIEIJ3/2ikjdD' + 'dhU5MBQiNmFK2MiJ/vKbY500OQXmdCQ/OH msg=MXV2ry/9xnrlNu4zEfvCkHVKmqfqp3QZI66Ty9IktpkFNc3XwVqCpiC3CHW2p' + 'uEXtr2S3iiKoLgl2GjB87ao3A== sig=WDs2IbSLd3o+SQWbMJaNVtcuX460Ar0comq62eAjZleDFRFUQmpdFufm+kIKz9qsvEje' + 'YfV+BXlO9X180vbtBA== e=found last=13 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAGE+PjOmZNpcVIfYnWzt/0ViwqGTJhVeWMu0ya2XKK9M= priv=MC4CAQAwBQYDK2VwBCIEINxvwwkL5r' + 'WwoAI6426Su3Tzsqrr/ANPuxhZkh3kriOR msg=wuLwGI+qWSeMjtutH+olth+X44f3jiR94sX1hu/BepN05QkSbpMZy5hCcnXBN' + '85VHgaXp/DrphwjRk2kT2vLUA== sig=1/9HCstHrQCF1bVP7kYfHPQXeBZcfOzIzMxtaZz3gEQmnEo7EanHwaNLx4npbIR4ZFyR' + 'cDVOtOV+yim7Mu5pDA== e=found last=13 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAf9n1Li5LZZbcWaTde5yNdlHb8WcUugboX/coNMVz2E4= priv=MC4CAQAwBQYDK2VwBCIEIBZMs/NQGt' + 'ORzp11s5cRjI/RXl9sHRWDkcChB5e7yuLG msg=X2wdFYORwKEHl7vK4sa+ylqIK6HtOECV9UZSvAUJMjF6T2qTEwgzN/bAmbolM' + 'gou3V6AVnzWOagbBYAPALjqIQ== sig=TxzPRJoYt8iGwNiCI6KQTBHERHBEUrISMqdx5fHJTI7G7+3KhaSktOtk4WEI7zxGfH+N' + 'WmbGBa2lwxN0icqOAQ== e=found last=13 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvKqMoL7VgmA5dWDZw189/4HRBCYvoiLYLuU3KeWY01o= priv=MC4CAQAwBQYDK2VwBCIEIAxCo/oQ0Y' + 'ih58oBUtCgWmLMZDYdftmAt7x4b7dPuzcC msg=T7s3As7GTzTYcnHjC7fSra22lR7vls0jWX2FrTdJGmnFlVPKp6IfmfWoEUVUH' + 'HnOk+Eu3ELstp+y6LVsvWWoAg== sig=xXsUuN3RH20+Uqol/AVtGs28KoMNM7KQFJKTL0hIx38KqYyKUxV3kz43uFrmV4PcNuAG' + 'OU0DymwzTUAH7lv+BA== e=found last=13 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAelYJJyFx7IdoZs6z1g7CBCpHPruui4xwo2P0h8w4q+U= priv=MC4CAQAwBQYDK2VwBCIEIPUSjXiMV7' + 'ypdqen34XYZL3HJfmZQtrqbPnad9tqHjiR msg=V7ypdqen34XYZL3HJfmZQtrqbPnad9tqHjiRGivOzugCgMftLtcK9J091ANOQ' + 'LKn2/2X7O4vAHFJ/oBZ5+WvCg== sig=zJnZpedFD6fiKciaKKoYjEpDw55JDv2MYD+l1J0Bty6D/7o/b6w9M2WDxOt+UoHWwgwr' + 'fxYz2Zpu0U24VTPPAQ== e=found last=13 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgw1dL+jmUmbWzTu+hjKmsCyuIFdLFyvV9GMeCIKnZKc= priv=MC4CAQAwBQYDK2VwBCIEIDA7SvJbOr' + 'ra7xFAfcKPAsJ2B2QpH8FVZklgdzteYNzZ msg=kBo/byfAHl5EKDkKPArZF7CuzeZIxAIPmrRK/0WPeQEgXUiharWnho753I/O6' + 'AJ3v+6Asc/ehV+rZqZK6dtpzQ== sig=eGuGh8b5yMliq2ZxzlVZ7fbf3MmQ0B4nLe7mnwC1wAYdwmg/EFy2fl10ZbpwiyawtivR' + 'V23OHe+uBUaUobzgAA== e=found last=13 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtELrXeG+8yIDXQqT8gYKcGQ8nGgLZ6WUfLULbJfook8= priv=MC4CAQAwBQYDK2VwBCIEIIDxLx0Nlc' + 'bF4i9+rGRqek5gQQ2akdmYRiYCaHFZkLV3 msg=HowidYDxLx0NlcbF4i9+rGRqek5gQQ2akdmYRiYCaHFZkLV3wqFawjue+g1Uc' + 'j9QbOcthxLgDL2O+OUzudrT8Q== sig=f3J6DB4OP5e7MYFGqmvJCFRsqB7X7cfTkpduhrQW4vKh6OsCT+EtCWx+0T7Wa3kyNoZa' + '0arXZKOD8RXKwgWlCQ== e=found last=13 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEALbvXaM/R5Qszs43CaDIvxW6gTLjJipmYuR3ZI1ATxoo= priv=MC4CAQAwBQYDK2VwBCIEIKjGknu7Gi' + 'kB0t5vJ54I8m4Gt9TsKcHxTcgUmSYzz7Rf msg=e5UVsPuQpCw48QI1Sa/Lf3rlxG14xy1dsYaEejYnNYrIGmJYwg6CZ17I7mEe2' + 'dw1PXPjA9hF2kbFt1SvbWEEwg== sig=WBiGl68XXNcXSbNsM9QSNqrU7j7FAdiVHJ8zVb7U+s57q2EJDAwT1j+oFffmaT614THj' + 'NMptjxovf7e6m+S1AA== e=found last=13 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAw0hV/197yK/mSBkPwPVOajiSpEHayoiVdiBcXP0//hc= priv=MC4CAQAwBQYDK2VwBCIEIGpQaCKO3r' + 'zM+xcdmf3eQSnULylhi3AMvm6k4PqPGDEO msg=5kEjqQSMIvL16zwogjq03GAazRdjTuW0VDBBOKHQAuOIhmpQaCKO3rzM+xcdm' + 'f3eQSnULylhi3AMvm6k4PqPGA== sig=OBJpdrJdlHqSc0nmGFh8AzYhKIZKtho242HrYVPB9NxFydsig6qAj/6i6e+yxOYCPToe' + 'yGBJzFhtV5s1dVkEAg== e=found last=13 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACOK/7lb0Zpwt/RSRH8/i9xI/nnNwL0mIenvddV9B5vA= priv=MC4CAQAwBQYDK2VwBCIEIIdJ3yFgW9' + 'Glm9OTJTcw1rypoXhLf5Omfb5kPbNW4SM0 msg=OmKlhwOSNoi36f/hDvfVnkHR/f9+lpNx1H85Q/58xKLFLb1Y7f58vxPN9f01s' + 'UbDj928O0lRomQ07UOHSd8hYA== sig=dCBBs5NdCwCW225/tgGbWWJYMoOmWduxV10Wel2SlY1uwpp7ySZz/PAUWYwlb8m2AT5e' + 'loY6l8o5Y5KjnaGkDg== e=found last=13 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/O3ERGwF1QdI22iyEuFEI4rTbnynGD+eI5Sb8z2Op5g= priv=MC4CAQAwBQYDK2VwBCIEIFmc0dVevA' + '71VwnjKcl9RQbh+/vaCoNHKurJSge0L6hq msg=4OPYnEzR4v9ULeqilGtaMBUmmytGeQi52KI8v3fpmSqdlA+wzK2dKWCMlLicm' + 'QOVCWNZnNHVXrwO9VcJ4ynJfQ== sig=6NBO4S248jZ6IHxjwX5gxPuZBCgaWZ2yaglYtA9ORvVReBN8agDEYPQ4baY0M2xY9Hr6' + 'AxiaKgRJnfGm4o0sAw== e=found last=13 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbfgmWlzR8hJhtLucXm7Aa4fNG02hmvTQ1kXc5lx94XM= priv=MC4CAQAwBQYDK2VwBCIEIF+jF470RR' + 'p8/yn5JSP9T3hFX/CES9/yGMXjdJ33PEhS msg=P/8CBiylpO4FpRLlxmPFSOs/XFHtcbDuvS+yZux0PxnxY4j2iRARSc05f0VyO' + 'CtLWB/Day/+shEStYVdeb+QnA== sig=atxFL4cX698JSvqEsutaojBYbV/YY7dOnCXwt+zjiATqchsdviRHiO6Jgh7e0BuLptz5' + 'IvgqdYXd/mtdSPdLCQ== e=found last=13 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAGeNi5dOxYEGPTTTy7wabn83cgmMYlSgEOUTk4Q3N8T4= priv=MC4CAQAwBQYDK2VwBCIEIHuYQxkLhT' + 'wilCkA0SlIfhUGI8lGOrPBfjfH0vg77Er7 msg=WewkUaAkYsd8tAvJZ2e5sL7Bt+zucb1uRNiMktnljVYqzUiM/S5ZJuKqfYLIh' + 'eMbg/0lKuI77Uy9FTXc2wlwzg== sig=xZxagOmPMVTgGfTRXXkgEP7UwXWaUtlFkqGvidmSpJ4O6jTKx1b7UZ4qsBEgVS/P9mVW' + 'UmVRutAo1FYpmwzRAg== e=found last=13 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEARs00IZjxLwFg0HfKBEC9E2qVNl425Fm2TRn84g2h8Gg= priv=MC4CAQAwBQYDK2VwBCIEIGr+2HjNcx' + '/9A0wPKlkbYNF3GQXNvMO4TJsLsIfNj26n msg=1Bk+TKrcbjI8z8cf2vExTMRgEGxNZCqmzBsb0JnHKvs6690dVEsZRPUFSfODr' + 'MueHHg6F8fYXxQnubhN/CS5Fg== sig=Vqkdjo3nLmX1SX5a7Remo2IpUGj2gGghLsTNTHTUGcn2MlULWXdNQOnZL7E8100jgJk3' + 'tw0kR4gXJK/fAPZzAQ== e=found last=13 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsPJq6G+NNb3QmK35iGLssZaz9nGDex3rJA5bDUKvbd0= priv=MC4CAQAwBQYDK2VwBCIEIIftC28enE' + 'VteoyBpv7I0Ok/lkS8mKrzF+qIKxiz47ie msg=U0m3i5weOB1op/8WAU3fPIrrcvWBswCrziHZiwtkZc7h4PwEk39BrBim9iMOS' + 'aQz5kZRqq2FdFFquaL/Iq9gtw== sig=GK2BAgWhJP2zGG7fROhV875MDp1kDb9P1f+LE9jTq6oLjGGdua6HUf2A91ezsZNr6LJB' + 'Y9g92gQ2puzLYdp6Cg== e=found last=13 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdQC+chlYOHlElYKovixji/6AvIM5ftwOUYDlQkkvRyE= priv=MC4CAQAwBQYDK2VwBCIEIJZ5oBTdbL' + '9KJzsUtJnD9+9C2sZEp2r4FmNQI18TTS5R msg=lIKWLmYU/5UoajP4Pge/x5oA8Uty1LFeN+7jBgReo96s6x8Dpy46YlgS6IKvR' + 'iS40vNpEFL8W3A9eTt4Ao5WVA== sig=EihlZKkNNOSqWpM+NxU4lcULHXa3dhd4ODJ8slNawm0fzfGPjwzssdqBFQ5hZxjhnXWS' + 'qug2W5Y5zIFXjAjcCQ== e=found last=13 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAx1dhb+ZgWE9O08L66WeOuwo0oZrS5y5skiH+CJXeCD8= priv=MC4CAQAwBQYDK2VwBCIEIGHNhfdFIY' + 'rMmGadzZD8gb/IByGtd7/ZoHtgbnadVT8a msg=K+mvYc2F90UhisyYZp3NkPyBv8gHIa13v9mge2Budp1VPxpK2jBlpiygrs49b' + 'CBMn7acsIyhw+POmbaIWCNZGA== sig=DjKdQwGEy0LhEp0kmSz36WKnC/yM7Kr5uVpHG89yDug5XWK1ojomXeHSKulB6z081UFc' + 'r6fZLlExLoNTphOGDw== e=found last=13 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgDofkq0/5UZIe7ZuGeUAevwMDP9rnemCmBPuDVz/Ze4= priv=MC4CAQAwBQYDK2VwBCIEIFLUzoYodO' + 'Nr4E9m/0YDjtiL0+Qe6XKksz/cLXKlUQoe msg=ViZvK1zby/g5NgXGJ5BsffUkz3BKCpvxUAA8LVLUzoYodONr4E9m/0YDjtiL0' + '+Qe6XKksz/cLXKlUQoeE+l+SQ== sig=jeSuMXq6j7rmCXRrgSGoQkhokMME2Cfk4RQnocxoaJufYJ9th6vZeT+d1Jtyg8S4FY/j' + 'gjAoIICKQxjVfdxDDA== e=found last=13 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAKzRc+zT6RqQc5JpT6h86fryHv2+mZllEdrsnwQsUtIE= priv=MC4CAQAwBQYDK2VwBCIEIKm5UZRZXu' + 'N8EZXDwhsESptkGNZ8Hs7lh59p7eO6d6UB msg=BEqbZBjWfB7O5Yefae3junelAascYAIaue4TzLeyQYHvaUc9akhXpwL/0kMEr' + 'GYWWJ2tJipXnJQzMHhaE6EHCg== sig=WwRz+nQ/SNUN1rjU7tt/AmfjnQRnRMNns1drxDGEbJcUBoIDHxJZxZaxvP5xBBpOzEqe' + '+M+Ga7MRu3ePOMO9BA== e=found last=13 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmZlleu/HD5HbPDf/cmpOLe0aiDY+3hksDgjeSgfvg6s= priv=MC4CAQAwBQYDK2VwBCIEIJXmL1p+Ku' + 'eyAWLyJ3DkXjAEyKps3I+SHBuuD4WwWhJZ msg=5sgIrM4cdQR4iHvCz/qerrKpcQZ8HiWS9YdOItHHHsdHt9ZH+QK6MLUVN7Nge' + 'gGl/1MRVlPZ9oDvVzzcuZbnAQ== sig=v26b6Lj7k38MwRqchaT+Me5DGrUL4RpWq3PEbUDwePxGxCZmmpCk8mUXu+Bbf8Q3o9ic' + '+Wb72noT1Q4VgnXdAA== e=found last=13 s=32 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAm+TQGrX9GHO4UnbOictk3C9r57tMuHii5sM2a8GMTbs= priv=MC4CAQAwBQYDK2VwBCIEICEN4iLrQu' + 'trk57jfvU4uGSQH5xk+JNJLuPh5Sbia2jq msg=O/chDeIi60Lra5Oe4371OLhkkB+cZPiTSS7j4eUm4mto6r2lFSBu53Y1+2VSE' + 'xXmYZFFdiFMGew3a3jK+PuaIQ== sig=yhc26/4dO35PcDvYMugZcvgpM0TAaIRYBS0b+74w8hJg1+mbcle90jEJnQMnpSaj0vrR' + '/PJLMC4NGFURzQEJAQ== e=found last=13 s=33 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAMoc0i4PsjIzyqVYllo1fXwq9faVjPUefA8dO7C7uvIE= priv=MC4CAQAwBQYDK2VwBCIEIBmIc/owUT' + 'm06JxF7vdKvNyIRWQmzbGGJICb5KPodlnw msg=mc1aJBZCEmE0muzPEu9DOeAsPuel2oR0p/Z74w3TIiZJDnyShbYZiHP6MFE5t' + 'OicRe73SrzciEVkJs2xhiSAmw== sig=6YQ0+PDqEbUD/tdOwb59+3M/gLgZu+jwkKzaPNA7tqvVks7lpO+YswQ5xIglHVrQaMUf' + '7P9FUhIb/UOXZTu6Cw== e=found last=13 s=34 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3XQkOCwf+RFkk5TZQ8lXjZ8LetYJsXbnjAR/G8MLiCg= priv=MC4CAQAwBQYDK2VwBCIEID/tKLfi6z' + 'sRa/XRzz2yrrFS1Kcm7EtaBioS2twKdcGl msg=OxFr9dHPPbKusVLUpybsS1oGKhLa3Ap1waXqQHcRquJ4NXYJs2CkDaDeUnKE8' + 'DOdL5kPKWIA6W3Zt+sDHwMoVA== sig=eMEJ5WY11ZFxocGWO8RWrB/dbDuNETQZu5FHo07gabwJaHPhpZAGlNHnKHsAf44JkN1l' + 'k40WWSQ7CvcBiOY9AA== e=found last=13 s=35 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgnfTT9aJFS3dz0Cm8fly3o29BWt2TV8SX7k1LH/7NT8= priv=MC4CAQAwBQYDK2VwBCIEILEQKV3r/a' + 'oFgwbP+C1D4U0CGZBcZZgFLnqtGtbddyQk msg=oO+5nG+6/NdXYA+gmHUqV0rA9KqB/kW3lOUAo5TQCozTIQk2PKwN/XuJqgpFh' + 'baafR2AaVHyX0A0NmqJSrEQKQ== sig=xS25TyZDfmXBWrlqhxsTD424IhOKHO8tB0emR8io1Y2Xim6+OAptyFzyzfgw5GSJKi7u' + 'p5/fadBdVfgTCDqhBA== e=found last=13 s=36 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAalhMTR5GewKzwQp093RnjkT7XeC8P2IhnknFUf+iaiA= priv=MC4CAQAwBQYDK2VwBCIEIDRZqPVUjR' + 'hlEl/2BsQJzhw3ux1XiuWLq8iZoUgW+CRx msg=NFmo9VSNGGUSX/YGxAnOHDe7HVeK5YuryJmhSBb4JHGHXCMb9x//rVjJNiud2' + 'hmLU87E0n5Xj/MCSoZVtzDhGg== sig=cTAbOor6j22tvjPFSyhnqp7HcYFuIBGCN6w3xNwX0fsnFeff92J1Wp0QkhJJ5OcbuwKG' + 'U9rVVXUM+cHFqtVOCw== e=found last=14 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAjCVWw4bKywgqnomHshS1UdJ5eU5LsqWWsle5yGcJ4+w= priv=MC4CAQAwBQYDK2VwBCIEIBlGwMotRj' + 'viah8DTaCMHDMhaKpaOceFSR+QMoLsyDIV msg=GUbAyi1GO+JqHwNNoIwcMyFoqlo5x4VJH5AyguzIMhVErJyBmKqSDlK4Di+Ob' + 'TwTKZbU+dFVFLylfBbUT3FdZw== sig=oS5/BDgfKqkpX7RZkfclOYwGW+vaW2bioYrAqBC3lUeOFj8Yx53DQgU+IuPMJFiem7/y' + 'kJzJgYYZVGZ1Wr8fDw== e=found last=14 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnIP97EdvWheZX/nFOt1iIJAk/dWCU8ihy9IPGS1X8bs= priv=MC4CAQAwBQYDK2VwBCIEIFU+O4btlE' + 'J7INidQ8izFw3Wx4HUL20mRCGMJUXK5QTC msg=VT47hu2UQnsg2J1DyLMXDdbHgdQvbSZEIYwlRcrlBMIXZtfGQPBUYVXeanKcf' + 'MQzsrP7XkJ46itO2ZlNHkRY7w== sig=UV4omuE5t6KBSDq5aW6s1mwbS9R9nwU6lC0MonGFIhvNxB0crCZgnRAGWch3gxea8mx6' + '9eKANPP9u4AxUbXXCg== e=found last=14 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1pzjLLlKW+nbf3BXU1U8EdFFv4qRTRquEiQhlm51uBk= priv=MC4CAQAwBQYDK2VwBCIEIM+4YC5hXx' + 'oyWQay2JKFuBJTy/CwWBfkuvEipq8BSGRh msg=z7hgLmFfGjJZBrLYkoW4ElPL8LBYF+S68SKmrwFIZGF3mKwswmZmqBZvz9r1f' + 'ZY4xEMjOSFDyczgbjKrdwTRZw== sig=LvPmMkFLojV3UztPRK51eB3ITxFVN+72sz3hCJg4d/KWXr6necqo+mQtWienp1tr4KI/' + 'i4Kqjz2NoTLTzORkAA== e=found last=14 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAy4Kh6AIXHgbT02itCtoGIibK0VqaJNt7gob1UUsa/xE= priv=MC4CAQAwBQYDK2VwBCIEIGP1a46tZY' + 'pU9lq+kja/U/4IrgQxQ4nm7SJH2XRNiwf1 msg=Y/Vrjq1lilT2Wr6SNr9T/giuBDFDiebtIkfZdE2LB/WbIpuSfgcy/Sjcs8sXH' + '+oBmcSFNrSOMvaaLdyKKQyuyg== sig=8xSLthxKmijCuUjE1OyYuT+DizMc5Wa6CQ703WTJzwAVeOC5KQfrmkeCRhlsQD/YlOQS' + 'hjM9bX2ZG006SoysAg== e=found last=14 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAktQJcODwixp4d8x4i0sazV4aDhtlppP5uN1sxxi9j8s= priv=MC4CAQAwBQYDK2VwBCIEIOA5k2zVtB' + 'u5PhSeIySC7gDZK47qn5dbT6uDN5Nsi5Hv msg=4DmTbNW0G7k+FJ4jJILuANkrjuqfl1tPq4M3k2yLke/F0Rr2Wq6Orq3DSnoJe' + '5vp7QeyyYEh14V4aFnvnd79CQ== sig=sLZUdKya5+LGTi/UskPkKLU/h+Pfe9UPvmHkpIA/3OOmunU8/gpJwRcxaWT7bvNyoTGT' + 'F4D5rHqBsIUklpA0BQ== e=found last=14 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA8Vu1Whv1H8woMRamRy8S2bMS0H7ab9l7c77LRVKW2FI= priv=MC4CAQAwBQYDK2VwBCIEILZEAxIf/9' + 'PsCK8iQGZoOAEZjuWpffhOWBI48Xk61O4f msg=tkQDEh//0+wIryJAZmg4ARmO5al9+E5YEjjxeTrU7h9WAmhQRh1daV00AAICq' + 'dS4G1LOLPEOv5hIVimwBXI3KQ== sig=2XiMk+Sadk6PP+6nJaLpr5006I77MYkV1hOAMaYsOwQk5TTVQxxQ6pNrSXwDo4TOT+DZ' + 'sPTBwSI29o6YrRsMDg== e=found last=14 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtevlqRpPeJU0ULvlPna30uIFJrrMLAma1Ml7TjjooK8= priv=MC4CAQAwBQYDK2VwBCIEIKOuM8evEF' + 'yRHee+Zb2KzPhOcXCzKcblamDvSKjWEfDn msg=o64zx68QXJEd575lvYrM+E5xcLMpxuVqYO9IqNYR8OeJ2u6HE2FOmlfL5A+F4' + '8EDujrqq45U7ef0dkfyArHGIw== sig=kkPUnjn79VlBZny3K2r4OgtCuR9CEGOibzshLd0GOftgWSFJEWH36Wh1zAqBYYrrLdbD' + 'WkSUDH8b3CtBFj6QCA== e=found last=14 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdCLm/vIJOXdiutrv1EfsGPAGBHlvH4NdfVkXTPk1+dA= priv=MC4CAQAwBQYDK2VwBCIEIMjoHwuJA5' + 'eIOdRmS+ghh/IZj3B7D3PO7ryfV1b/xHSE msg=yOgfC4kDl4g51GZL6CGH8hmPcHsPc87uvJ9XVv/EdISpq45RsgpASeEYHIbuK' + 'YNg7YyhUOjbqDB5GDx6lfnyIg== sig=MbW/0EtXK++PRVvftPsTJfPa25AA3D8dY214/wIVHbYjjOWApr7JrFxyQSScOPjFPSew' + 'pUHGjVsys9tnXgefCw== e=found last=14 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkVW2PfKqa5QbPDma5xWYnqRH7sJjp/SZlObfjeIHM94= priv=MC4CAQAwBQYDK2VwBCIEIC93EXIzoE' + 'tBYPV1x5ZTzaV1M3LDdh8QXmRfT4urIjBS msg=EXIzoEtBYPV1x5ZTzaV1M3LDdh8QXmRfT4urIjBSXYKGP/IPx4UxZN4kv/7lv' + 'U1y2ROKNlz7BfRD4cpc0kKgSw== sig=symhm4eves/ND9On+/PT7ziE37KAbLGb78d6N6flPIH3Nrtv497SotY3Asa0K06V3TFX' + 'xVb82trK1d2+cQ9NAQ== e=found last=14 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAYRzqTQ5Ea/GQkKfvwhvVABs5zZnYFGqmyEQkiWwf/Uw= priv=MC4CAQAwBQYDK2VwBCIEINghi4zLHb' + 'G0exb4BCAIHc/285OUOZjXwJj2CNB4fm/u msg=yx2xtHsW+AQgCB3P9vOTlDmY18CY9gjQeH5v7gWThbGlfvBwmwmDrSgXjeAfZ' + 'kEkAQt3eg2uRcw4yoZAjDuf0w== sig=IUduEcVrXxlC2GMiImscHsTTfWoxt67WIMjzxCWW+u0kYG9MV8jYUzysGsyxHfYPelfQ' + 'hsolMyRgkiqfqIZQAQ== e=found last=14 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEARGLw7ytONHmcHBhAn59IuZwdV3tEGX/bWl96qxCBMcU= priv=MC4CAQAwBQYDK2VwBCIEIC9DEp5jNV' + 'Wk7OH8QbzCMs4cmCnZwqmjg4z1GGvtfTTV msg=L0MSnmM1VaTs4fxBvMIyzhyYKdnCqaODjPUYa+19NNW+P5B259sevNkrtAzuE' + 'ZZo3fZ4REjZYcR5zuCs1DXRdA== sig=EWxmX686sWuB6I6wSj6OBUoizNIYtpcN9lIVR5AKzcXTH8+tVhxobOZP2E3URA9dSVbi' + 'RVkNesPbujv+urJDCw== e=found last=14 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAGaavvJQkYApJqFCo1SpwyzbvPlEI04RWalQpUki29sM= priv=MC4CAQAwBQYDK2VwBCIEIBNdcwVj7i' + 'btrNYyKo/LjOHWixM4ZEUp+DgdIE/xgq7C msg=4tNBWCmYbiI9BHhRDc9Z2Ee5jgejIhyzc2eQmtEj7r82M1MW9jeaAt17yDTd4' + 'TozLuucq97VrUnMZMHomSlg0w== sig=6sTRa4ly2OJVdAYbCFZKKg7NPBxWT7CmVhpcql/EQTXy+F2Ob2dwtAdItoH9QsnaaODW' + 'z4BzqTusM03IxLxECg== e=found last=14 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/BtX8y6TtfB6J16osePQ2goWNS73D1aZgYe0dIu0Pw4= priv=MC4CAQAwBQYDK2VwBCIEII5ma4tvCG' + '6gwyyRDvQx7OLcl8BklEV5+q5J6N4/672L msg=NlQVO3xzdbXc093G7tiM8zzT53ePXlmSMTy3BivJP8hk0g1WkuGNNSkdiDxQ3' + 'VvE9YhjxIvTfqInp6SHl8FJNg== sig=Yd9xwMRGfljaeriA34F92A4Gz/Xx9gZrmbr8+7WAhX7yFwX8vVBikX87UvFbsWhRxUyq' + 'SNSTFCy13XOrsJ18Aw== e=found last=14 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA62CWMSh/Z/rQLG4tG8Cuw8JmdGXW+N5CgFawuiOSNGc= priv=MC4CAQAwBQYDK2VwBCIEIIhjk45YAK' + 'iO1zFUlM2InBE4UFit5WD0bVvl9NJuvuHC msg=zYicEThQWK3lYPRtW+X00m6+4cLZcIJxXionNlwzJdvLwRXfW7VO0Z4nimq3l' + 'aalBsL0VMXU9wmXZDe2F2nhEA== sig=YPVDKuhjy6PmI36JY06cTnvEomcpqaoXszzr+5OYJ0diXvRUcPyRMc3sEalWiQrIUnbn' + '1GzVyQA7l37vg642Cw== e=found last=14 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA2uM9enIkR/oM/YXF+BnAvvIoRXCQ4pPOpc2dz08tV3s= priv=MC4CAQAwBQYDK2VwBCIEIG5eVKErc+' + '1sU+fHxzRL0odQG0eNjE28tpgS0UzSlJZp msg=bl5UoStz7WxT58fHNEvSh1AbR42MTby2mBLRTNKUlmllABvDcFvBOis989kT5' + 'UJbIaVRQoqIGoahtnOVdDbEYw== sig=WdNSg/M/ROmyIowfwS9jXxUVRmgyy7ClhrPL0XlXV0zUAzoYoiJfS3pBcwAr4nx8OXBi' + '479KOHIF7OYPG8A7Cg== e=found last=14 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6EvDdnb0llwlZ9QOdMbb2Bq9+LMZ6oD3CScnuJU1JRw= priv=MC4CAQAwBQYDK2VwBCIEINaQylwvc2' + '4EXS4GjXAhzSpJ3YIHDCME1dzbVg/4ylaZ msg=hsh5xDQ+jD4TtbaOsbYa+NKQDYEv7TMTlx11ogo90DVIxk0FFtadRX1ILcgx/' + '8lMp2T2IWicj5h2gv7GLW/XIg== sig=MukIYeEO6/P6zJrvECkCK9mC+lAKiNU9gIv1U975EoWcGvLagRAnsGUu75quWu9kz5kr' + 'lnLEYGTKjW7/5T3bCw== e=found last=14 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAaZb4qleF87VuKdIWpniXxqYx/ClnngejZQgecqkGFj4= priv=MC4CAQAwBQYDK2VwBCIEIA1q/26f31' + '3uDNOo04cFTOHIDUnIxuBEB5VkRa/fAZET msg=FeaQpCWPiI0Nav9un99d7gzTqNOHBUzhyA1JyMbgRAeVZEWv3wGREyzEPZ3SQ' + 'cHL+w1CSMk2L29s4DajHlEigA== sig=QwwL+szv/IfJ1I0iOf5XRqG37y25Y7e0xPawD7PNKauFaFnDOeRP4RH62wUt8seWPa/5' + 'ZTmZdOOg6vVJed3zBg== e=found last=14 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAaIVChkJbndXOtPuW4X01DSV4zyfYDlGiXjXj7sBBlQQ= priv=MC4CAQAwBQYDK2VwBCIEIIIPFnXjEA' + 'GVKUqJ5CzWs174DcPJ+xX4Vh+ulyDYi7pj msg=xhvkgg8WdeMQAZUpSonkLNazXvgNw8n7FfhWH66XINiLumPY1UyLVMVnL8Umf' + 'B/NBhj3Gjv73ORLZHiPqnQrMA== sig=gjl0P5BykGQtidaVXZ4OapR2kxIV+hjM35xMqxvKEV0XOjje7SB1b50DOYZDdHSYbzwH' + 'MOuDKzP1bVYCcnjECA== e=found last=14 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmeiFD21Ehm8mxZJzqOfprFvVc1NA1Wga4DwE8QzWkZw= priv=MC4CAQAwBQYDK2VwBCIEILBkQAvrXd' + 'n3NW9FvPByDgpDTLfVbw77Z4qXFAnXGlxX msg=QDDuUCGPsXhXevhN3Fxvk1dvTGTLs7d+9uwLwPwUfQdU5W3j49DTbCXUhRjXi' + 'LfKgUawklCjkPoB9LLHS2/vWQ== sig=ABDsl3kDVlM1lE8pRlphHP8kY/rvrLRC8YTOyHF+s/3ngCOWQi5i3qhoGMChwAfhmQwf' + 'B2R/IV/RaSo8NfeoDA== e=found last=14 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkia57Z/UB7qW/coLTgwWZduZVVAVBWApP5V3rOwgPZc= priv=MC4CAQAwBQYDK2VwBCIEINmYIaCAqh' + '/1kYU+9ilg9HKvrmhdD4u40BE1GtmIMoRn msg=OZp/hXcmkKPucKrD9gBgI4eCXfktUclWBKz13UpRvQvaNDo2htqZxz26Bm7zh' + 'sqXoODhpc/lFIVRW5vWzTTngw== sig=ygj+kP09VML+z4+1aiasdLzZcJoCXlVeq9pN0qLqNoyvpIt58WXj8+pvGQ6y0fS4QD8s' + 'dsQFBE/gYwmuqbv4Dg== e=found last=14 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmTB+coZ2J+Mu74e/HyX+JmHGrvzKHqce0YfkLjOyZzU= priv=MC4CAQAwBQYDK2VwBCIEIFHEz1/X7Q' + 'rMX3t6Amhq0wi9w+pVzLFeCY77pam6tOd+ msg=2aSjhX2Q5yVBcSZsmU2UEDySzOmzphMuDVwAcIg27jdRxM9f1+0KzF97egJoa' + 'tMIvcPqVcyxXgmO+6WpurTnfg== sig=ByEyfMNXU+golEoLQWSxqo5xFJb8mSM5RVYtIVoT9OV0kZo2ryAxCDrISlKnvfy8uTWf' + 'wzXLIw30jBhmSWHDBg== e=found last=14 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOAtVakSIZMTFWkuW1qcE3QDUUjzNQRPCB8MK+PenZhI= priv=MC4CAQAwBQYDK2VwBCIEIEexwQuuiE' + 'NLEJSZ+bm53rhkk88zYN35tw9DiBb6rzAS msg=tw9DiBb6rzASYE6kl3SK+m+QKAvKO/D0d+LhzGNFgRMd1tKOieUE0TlCEhfTN' + 'yowguWAM2Pc0p2R6IsWmuNv4Q== sig=e9+DgxlR46Nczm+prDRUavvENbC2sStK6tx6MQ9/KIRUT9STmFDdVRr4/XQ+69ZOVYLd' + 'JI6WRfY+ZciqqS4KDg== e=found last=14 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAU8RzwoVIfNwRVX9X9OSnvQBCbHeFf+t4N6DanMJHnaw= priv=MC4CAQAwBQYDK2VwBCIEIC71kdEkII' + 'UG08HFAqSak1O5WtR0n229yh5ZU36OUC3G msg=wbWmuB/9iPwI+iIc4wteif97dodMulWC2lEK2fOrY0tOa7o5mc0UczDNHZbXW' + 'Ij9LvWR0SQghQbTwcUCpJqTUw== sig=x/ppbpEbvUjz+uCmIWl5lIOitlZxrGvRN4ZlPst87a/dBMcN7XYuxHkXZKbpmTsmdhnF' + 'By2r00r02fGFSpfFDQ== e=found last=14 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACnDDfo0cBXw82tDq5HPCHd1lDgavvbmz4v1VzhZcmlM= priv=MC4CAQAwBQYDK2VwBCIEIAQOBniYtR' + 'l/lJe/tBc9iLAgm/h3Y4OaxHuZ1/1rZHsP msg=uFbaGVdVirsoS3e9sEMjaaN1Y48w9qc5APPf6PmvG+Hnz1oitR1K8KgOIVxNw' + 'KbyeawSahx/GmJd0sQyZ/uMbw== sig=TkhZ+wSGathHomqYR/+QdRO6Bb2PaB2qOBF4WrHYOdprOhvYmC7svOagH24lxpnUWIYA' + 'Nk4EpyVIlP+TiA/ECQ== e=found last=14 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAa2MRGNSORs9mAmccujEEr5I4piY0yevnoqilf0uPAbI= priv=MC4CAQAwBQYDK2VwBCIEIOFeIxD1N8' + 'e0yJ/h981CSjOEmbueZx4cut/VuP7daCIp msg=J1dNGjn1pz74R6VkDeC21HcaatwWpeEW2UndWdkli8OXCjjfYwj9rhskGcdre' + '+3U9q3SFQE8mR2G4IaRabCQSg== sig=8c4BLWoMzLMxUTJZTQfKuFKU8kw/SI9bJrvlDnmOMngAKxZK2R0FwzoF/jmcG1XZIQXs' + 'OFBDv4MXR/QhsIRBBA== e=found last=14 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/TVTG7WQt1XIDLlNyl4yAhbveXq/mPT23OK2p671Vm0= priv=MC4CAQAwBQYDK2VwBCIEIOew8YuwBr' + 'vvDDH0bIRq7+TMEEByVFVhuVQ2O7rh9t6g msg=0cu8hzH+Uel1+2Zqm3utnP3eDuew8YuwBrvvDDH0bIRq7+TMEEByVFVhuVQ2O' + '7rh9t6gfRtq4VzdyB+flp7pJQ== sig=Gk6aJHFW7x/3tAr19Q5TYH/nUCR6H/tHFxeTluH7MueOCP02lanuRPi2r3SbNJL3Nbop' + '8XKAze4qe8WfYS6JBA== e=found last=14 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATnkhKuQcz6CTCkmUmxBbqJ5CxcAiSvXXVncT49Nvk18= priv=MC4CAQAwBQYDK2VwBCIEIDWj/k1VYQ' + 'MSkN2xhrLtLH8bi2uvVQJ6wWNlBS6Hq0Bn msg=EFUjdTWj/k1VYQMSkN2xhrLtLH8bi2uvVQJ6wWNlBS6Hq0Bn949u9uGvqrA7i' + 'vtOhw4l65by7M9PVpX2gGZfCg== sig=y7BJPBTBm5NodkBWVo3XLvdGRWeD9l0tO83bg2rku7rzr6uYaE//e+9tDP1pWmQT8wS3' + 'WjMB2OlMsNCHh51+CA== e=found last=14 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA8JZb30nb0g1x14OfW1W/nukoX2z5PE8kwdoOlPsRXzM= priv=MC4CAQAwBQYDK2VwBCIEIFiVw01jLq' + 'dl42ltnw+B0J92oF95nW1dqWME9EVEd4YK msg=w01jLqdl42ltnw+B0J92oF95nW1dqWME9EVEd4YKi8vfN5VL0Qcmhs/wv2VnL' + 'E25udC87J94pvFhbnOxvnTzaQ== sig=B8iXl/lYGVuoNcvdSaAYH9Ny1zsw9y0+/v5IwZ/9l4EYyAFe7gOLVieaUxGr6oTexk1d' + '8ESdvJCYCFnR8B1tBA== e=found last=14 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqdqwhlD0Ao0FOs/k+aaCmzMbTsuhp1evabO80hBleQY= priv=MC4CAQAwBQYDK2VwBCIEIAMv3Bo3hU' + 'dpOTdQZjUoAFVhh+UjgVR4QBMJRNx3xJDl msg=L9waN4VHaTk3UGY1KABVYYflI4FUeEATCUTcd8SQ5Vyi3nxmJas8TeRhOiVb1' + 'y2GayEZ/zL7B6HL8zvOecUGlg== sig=wr99uHFzM3PXphB9TVHlCm3tf2kaYJ1OBxFdHAfMGYZ1X87hWNCBzA6iCYuGnL10r8QC' + 'zgWBo/lebtcVJ+fyAQ== e=found last=14 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAF51jeLxl1rYM1rBSJ5gLJMXHxD8CFZUBK3BB1JW5DSU= priv=MC4CAQAwBQYDK2VwBCIEIHky5Np8wU' + 'dkBuei3Pt9rdADXrLPxmaewdB7FSkPUYGj msg=p3ky5Np8wUdkBuei3Pt9rdADXrLPxmaewdB7FSkPUYGjATtqqE9LM03m7rqK2' + 'f+Rig+kbHFxYJlAkIMmnT73gw== sig=kvqehogHT00vPmv/ghO/nS8i20h1iXoItb0WSeGwjZkNiQW3F27mnfV02WszvM6SwxeB' + 'tLHbUHAb+NNufPF8BA== e=found last=14 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdO7JFnLdvf8zH0rs1SpdiypIv5TAY3d9qhoq5o27X7E= priv=MC4CAQAwBQYDK2VwBCIEIIu7AWSTwP' + 'gMQQb9SVF0nxWoTvwgAe7NGxnTBERgzbyL msg=xIR6xVrXPxdx0cgCWwbgREYRi7sBZJPA+AxBBv1JUXSfFahO/CAB7s0bGdMER' + 'GDNvIv4s+2YzydMZvgfm4ivww== sig=KJLXT9FnCK7seLb4x0boJROG68b9BHTYNBeVe8IoSFPW9sSIzQPcq7Q/GiBtKpxCl9Mg' + 'Cl98U2DaEsnWLqgfBA== e=found last=14 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZ07XJoey2kjQ2hjQed9aDBb0Q7fmwRWq+QnPusXhans= priv=MC4CAQAwBQYDK2VwBCIEIMRxbLSLpI' + 'NPpCfBjJFESwHvCIHIVBhyeaOwgWNafo9h msg=EI2cR9RRjYdqYZrVzQa3Oe2c71Tzfu1/5V2K6Z3uMxPkRFhTj4oGucRxbLSLp' + 'INPpCfBjJFESwHvCIHIVBhyeQ== sig=VDmoiUFjMUj8zoJDK9NBDlWBqsRRsI04rFpNcyShP2cJ1/LgsBUj/8/etNHTVl8EUFXC' + 'q5VxfinioBl+rRaMAQ== e=found last=14 s=32 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3qX8W/FO8WgHq6GQsLFCwWFpEZh9+oY4dqSFRYc0PFQ= priv=MC4CAQAwBQYDK2VwBCIEII4KLBvrrl' + 'uOTkiaFQC6SN9femr4iAtF6iKg+qJzkABe msg=khcD7Bym2d1PLe/HQ2sM7+IEjgosG+uuW45OSJoVALpI3196aviIC0XqIqD6o' + 'nOQAF4TmWMmaKllHDvAoLRG7g== sig=5bFiD1Q7+lhkr0GXjOWTr2Qi4Hh4X3XQYQglMHQ9BEEGQD2EToHy1KC9thcRiPFA71BR' + '9gJhwsDCftzh+/FLCw== e=found last=14 s=33 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+b0dlNC+xjKtPyJ68RTL2LORfDM8m11+ERIdpCL3G50= priv=MC4CAQAwBQYDK2VwBCIEIDSb5VHQzn' + 'WyyQABhaP3UoYNPaHMuD7714zmIpxmcMhk msg=hZ6gnRnv2IggMQRNof7DnqhWxmrTIRLRr4Y0m+VR0M51sskAAYWj91KGDT2hz' + 'Lg++9eM5iKcZnDIZBWzWFDDkA== sig=U4+L0Qe42Owgqstyb8Im8XNvD6BxkcpbgQTdmQWdpphKssAxIX5t/8W4S2sjf0njHGxW' + 'nhwOXWgk45numzmyDw== e=found last=14 s=34 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdrkpLk8EZ6zrrF+K7ejlPkv6ZWMKkbM9PFh/dKKkHIA= priv=MC4CAQAwBQYDK2VwBCIEIDnxg9OEsK' + 'zD7ua96A35VD7nclFpUqI39ShNuGnR1KN+ msg=k4BP15XQB+8yfxEMC2csIPQvrC09vV2RyLc58YPThLCsw+7mvegN+VQ+53JRa' + 'VKiN/UoTbhp0dSjftx+cuXIoA== sig=2LXBbdBtV80y26jIkHcOOXq7r/pSN40Shu4f7mFvWwMjpDnTXXxTkRkck8a/hpuMtOWq' + 'ckgrf+AHA8+JQcEKCQ== e=found last=14 s=36 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsxFcwDcLojXUEiyyLdu0obw8GrQrJuH49phvSUswKOE= priv=MC4CAQAwBQYDK2VwBCIEIKKiYMz+tm' + 'r/m4rR/+kZ0NjgOqhqJb+AXXs8KDkEb3VP msg=V53rmEee1A/bQLG8OwX1ajQ0Y871pOjlODMuDMsCPVTWGJ4xEaVSv7rMaS9i3' + 'c+0Zo2iomDM/rZq/5uK0f/pGQ== sig=tpan+EcrcfGTSNsUEWu0h1Dc4YxwNiX3Haxofdo7Gr7B104Xb1NbF8M+E5a8FTdE0+PE' + 'PTIDqmdYMIqAsmuUAA== e=found last=14 s=42 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWNPmakqyrHHejUO7H27qbFzcylW5bEr+OPSqus1vPIs= priv=MC4CAQAwBQYDK2VwBCIEIBCvTw6Hoy' + 'n5JsxHYSdNnXElw85SI82dSaxqtcNo9HAs msg=EK9PDoejKfkmzEdhJ02dcSXDzlIjzZ1JrGq1w2j0cCxSCb4SS8M9sJjvKJLG2' + 'mhjl9EWuTkMH09B+E/Y9LklOw== sig=DooigK1dWSZplUqtfll0eJfvf/iEzY35snfb00ejoaCO1Rv+YVbAMJwDXCF1TPUeEqNa' + 'iegP5a6afqiaXK7/Bg== e=found last=15 s=0 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcRgbHN9sPEoAeBLd8TYxQQoE5nzCtjqReIWZHTkseRM= priv=MC4CAQAwBQYDK2VwBCIEIEG5uYTnQf' + 'GD+DIKGTVYEBzEz1s51v4iV6JzNqXYt2DO msg=Qbm5hOdB8YP4MgoZNVgQHMTPWznW/iJXonM2pdi3YM4vgB+3rUaJ5ku8qRCzR' + '4O+aMYnX3OrtoLi9oCpDgWE6A== sig=eVpayQhFcfEnDAEitsHTEOVOTW6rLxnlgbOm/xteUGekfpeCufPCq1Wq5rDvV3PTNY+V' + '0Er0brHy1WvxY7REDQ== e=found last=15 s=1 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbuMmAO6GnYEZLiZM4HNHBkCNiszgm9BOCFTdYiseA2s= priv=MC4CAQAwBQYDK2VwBCIEIIRh+MIVXO' + 'T4HRrlILID8LMJjNmdH7AfqU2leELfJqsq msg=hGH4whVc5PgdGuUgsgPwswmM2Z0fsB+pTaV4Qt8mqyr7oMPe29ZH4+R8aPgl7' + 'M3o4jFO1NO5PgQL3MIFRRixFA== sig=V0f5iy+cfx5oKnY5CwZ4eP5/IHZqVQiqPsK22kJy0aBBQfzU0zAlyl6h5G+c/97ZL+Z5' + '05Xuzgnx00IYZScLCQ== e=found last=15 s=2 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAe7yI4bJRIweGtomYKBmCNHQm1x08weTktgojd7uUjfk= priv=MC4CAQAwBQYDK2VwBCIEIDHahbBLqb' + 'jLMKZuhCDFJsqaroa0KPVgiuVvtatVp/ak msg=MdqFsEupuMswpm6EIMUmypquhrQo9WCK5W+1q1Wn9qT3m/n2f71WgLtuBad8t' + 'tL0A7TLI1BxdS+GZs720dAYTA== sig=74QERXzquku/Otp7j5ALUxVT8+1vsqIo1/Rog/Hp/aOFX2w4qm+MFLXNogGwJhyW8PHv' + '3uLzA9BN1Wtno0vNAw== e=found last=15 s=3 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADaA0iFmpirfLRE/jdjuybbNk4u/+VukP0weiCurZN+k= priv=MC4CAQAwBQYDK2VwBCIEIDFiSUuUIp' + 'eCvaVL5AQyAalY3EFcfofaSzE0eYv4O48U msg=MWJJS5Qil4K9pUvkBDIBqVjcQVx+h9pLMTR5i/g7jxQJZjgUGAbYXq26rukea' + '6w5K3tAZ7WylOXsygJOGb6ZFQ== sig=dD9kDLaNt378wcxjCP4kcHM4wUBprZjT9nMxowKElnLweTsTxtmJeHFvI0IHNfAK9wYN' + 'pu1ycBL3bYqkS2hgDA== e=found last=15 s=4 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAXtNr3apyDyAkNEeLUXTahcfAGIR4LJbjbi+e0HsKxZs= priv=MC4CAQAwBQYDK2VwBCIEIFWBu5LbX5' + 'JtxZGAG5FckyMyiPnwLPiztNNhaF4ZTX9e msg=VYG7kttfkm3FkYAbkVyTIzKI+fAs+LO002FoXhlNf17knsuY8UhJEMZ5lPYst' + 'vTltnU1TuyJhB0WJqPM/vpzLw== sig=S6/9rLrfIJ41UZPYp9LHt/4RTtrwy4EkgKafgPqL74idsdJ500gNCAoVk0NufJH0VPQJ' + 'zMUFbM35z+D5fsJDAg== e=found last=15 s=5 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqgCSVaGc4AudoMr4//2/fTsLJz+CGEXjqI3NgOQbvGA= priv=MC4CAQAwBQYDK2VwBCIEIAZlNwFjEA' + 'XWysmihFNSnQLnYphx+7VomcRw+8RfBMQq msg=BmU3AWMQBdbKyaKEU1KdAudimHH7tWiZxHD7xF8ExCpIsviVBLX0z2Djerysf' + 'w+OYrwKN7Lf12u4C6J295SAVg== sig=rFC0mcAF6HN9JF4tFY7jT4x93gNWMrr24WIZ72tnMdVq9Ik/5uG2cNeQDtx/YvEgQBhL' + 'fSVfZBhtS29hLl9JAA== e=found last=15 s=6 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhDm3Lvb6tsQAwcAjpP78gSULPEQzD3Ko+GT1peMOp/c= priv=MC4CAQAwBQYDK2VwBCIEILVVqCmAqJ' + '9H9W54OxKMcP0ytDIRwqu5QpUPfiurjxRp msg=tVWoKYCon0f1bng7Eoxw/TK0MhHCq7lClQ9+K6uPFGkIdjHcsbfsdsoxdl6UE' + 'PHY5A+Tt8yH5MPgcXLkOkQCzA== sig=eLAZwBbNhI30Sv6LfnQSIPqapc78/OXfkX2V25TKf4ZbefAAs1Gq3UT5NAOMOBD2FQHl' + 'tefNGQrPHqAE2OxbBg== e=found last=15 s=7 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAn/9yv5NyZdRp+/1NavuVSy7tVGOJ4sMI/HwhzPPe7gc= priv=MC4CAQAwBQYDK2VwBCIEIGwS1kDyBW' + 'uk1FA0gk/inYZsbXSOU56fIn6zU7+vCcGT msg=bBLWQPIFa6TUUDSCT+KdhmxtdI5Tnp8ifrNTv68JwZM/XLTdGVTpf2eX+54Pu' + 'aWY9Xs6fNfmPEJQt3hb0vLuhw== sig=uPgjbNZ+iK+rD+qtYQmdkcNClrFbDPwF7XqI++ho5K2nmh1xu0L9blIZHhddfxpPZNI2' + 'nc6RZ7K38s1dMKjUAw== e=found last=15 s=8 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAVVB9a2cdMffP3NZnFctw9iG3DpzewzI5KEMG1V0K8pI= priv=MC4CAQAwBQYDK2VwBCIEILH66tKKUf' + '+0eETnw7Jlfim9JKG7QNsxazANvEBNacMv msg=sfrq0opR/7R4ROfDsmV+Kb0kobtA2zFrMA28QE1pwy97W2475s4C5bOeW9Auw' + 'ZjhMe+aCvqM0KujPaHz4y8KvA== sig=TSmVhUJsxXGxDZ1bf7CF/h1dN/na48d7xMOzUNvKsc01ZpDfiGY2YvtvUUoI1nuYyMz3' + 'D4tp+o+gd+HaIXdIDw== e=found last=15 s=9 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAwUQIo4M1qy6efc4w7fy9w4794IQSas/9qFl05h1WcA= priv=MC4CAQAwBQYDK2VwBCIEIMhJq6xLjt' + 'XELk9aEoHE01rNCH+j38K0YQEamjssRqAD msg=xNNazQh/o9/CtGEBGpo7LEagA4uswFEWy1FNgkQx+d2yIwgRx5lDhirsnnFS8' + '141Ru1fJWXeQA4cGsIvEE3GPA== sig=EKpMVwjdFq2c9aVShr9h+NqX36uT2KPSQxlP1hz7cHy2qXdflf50xUB7g72y6e/Etiu8' + '4OOOkbzfupFPvcTOBg== e=found last=15 s=10 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAg0uXLg26eJhHIP2EuV5VMwkZ9M0EqBGbSnMBLj8qU4k= priv=MC4CAQAwBQYDK2VwBCIEICiFe2OSiR' + '1uRxEu55Chsy5N8GtdWh4Kue+aUS8ugOGw msg=KIV7Y5KJHW5HES7nkKGzLk3wa11aHgq575pRLy6A4bCQygddkX6sMQdBRxzB7' + 'kHolECRDF2IuzF4G0TygASbGA== sig=5zb5O/zUnoa3oBOZYg9aHHHszbrW3zt7UAj4HhU6D/qRR6Th0wVRbTWfZdIz9OmcRbbV' + 'EuS54qEtNgctCrtDBA== e=found last=15 s=11 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhDqAxB5WzgL9lnfCzHk+G8xaoCvKE4FR7nd97r2SwUk= priv=MC4CAQAwBQYDK2VwBCIEIMCr4lM25B' + 'DZ6Ewzbw6y1HQjwwEmozSLdJ8ZnAw/+loR msg=dCPDASajNIt0nxmcDD/6WhHulqT9yepiHLDh0IkC6lUYxYEO47oDUNdiKuP52' + 'ZkcH6kFLWxvLU3qonrewaS7Vw== sig=y06d8b2CCfZHU+VG9sgIbi3B2kikJIsuRdHIKv3zMwIaHLkAYolQhA9xOy/7Vijz7fWv' + 'G1z7BZ221b8KCHLQDg== e=found last=15 s=12 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJ/YL1hsAQpPFOn526Cl0U1aIoCmFM3MJmxCmng7Ecto= priv=MC4CAQAwBQYDK2VwBCIEIJztITaSsx' + 'FJFxSSQI/lStdfomadpDVBc7OQYIPTcO7A msg=nO0hNpKzEUkXFJJAj+VK11+iZp2kNUFzs5Bgg9Nw7sCkOcOwWeJQmy0PtifUq' + 'K2ijNwHoz/H/117INH42qw7ew== sig=hhsMtJwNEcV252U6tsAilLv7RkL4DQm4V22w/HllCu0EU/ehQ09YuhJBSAkucR4cKg3O' + '1FibBrFmmQYDcVV4Aw== e=found last=15 s=13 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/RGUcow7+t89TEYW5T0C/pQTY4C+uXUMnM8TCJM46l0= priv=MC4CAQAwBQYDK2VwBCIEIGbtJhEiX0' + '9W6FfESZ+FWWKV+Yb5q69Z11eH8d0f50sQ msg=lWBRMcKQfzg4ItoVY8s02Xzca5imvow3wMkf7AVexf2mvxgAJDYpjGbYvQAJ1' + '4yLfnQi6sSCbxHJo5OrbfP1Sw== sig=vSdP08bMaY6apW1QfrXU8q20WyCUPou9zkRjlVF+CwMLrsft3HStpMpDtRFqIRwRwj3n' + 'SVKeBlC1hKsG9RTqAg== e=found last=15 s=14 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAXZRDI0Xz98qFIoZWMUf4uYej+4Y3sLx+2fQ+61/Ip0k= priv=MC4CAQAwBQYDK2VwBCIEIC4ycR/Pg+' + 'EvlWb9nofu/SEoGphxh5FQ1ydVzKTeEv2f msg=zKTeEv2fDpXsItQ4NX63x5O5JbLUJAS77Y2mpHzqb1vpqR1++wCuJo7tVC+sN' + 'vVZ9j3/6z4pmkrl5+38NHEUyQ== sig=kmuV3W9aMiRSnhtqQSfIOsGjUcGKmcSa0apr3cBSSI/V20YYZTMO3UTgv6DG9DAIvxHi' + 'X+GKt5bM5RZC5dPTBw== e=found last=15 s=15 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAR9DKim6AFz9D0L+oEVfTARHniLVxGhpQQk6OK/6UjpA= priv=MC4CAQAwBQYDK2VwBCIEID6nAPJIMr' + 'V5c4Q5L1ggmOEx0+dFdxW63k88jX4GF0cf msg=bHyD0n1LgF7WqM97TpmOax2QTLw/SDiqoK2BcICQUVc5/U+Att/y10LtigLxB' + 'BHH/NeAdScpdAwGJusBO06bMw== sig=kUtn3Hux64xmPBEk7tHxKySscj7xvWA8D/FxGAFTKtA+0EoSfXi3lT/ZBdhatQJ0GOcR' + '9gZh+qiamHPAA+qnCw== e=found last=15 s=16 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACW4+FQWXjtCYSSMsBHdojsTuDAOmLNoAeXXi2wfeKIg= priv=MC4CAQAwBQYDK2VwBCIEIDdk/4sT0/' + 'betFtwkN6YbtI7fbFM133ioFBR260gRfpU msg=LP+f6rFEFoMHN2T/ixPT9t60W3CQ3phu0jt9sUzXfeKgUFHbrSBF+lRCgrVQ3' + '2eOH7tIOQX1V3xyXDaj7BAO1A== sig=Ysd9z55LfRXUt+BxKNM0356yjhDR2VohdIhzgdZjD9K5eSM+QjMZ818I3uCv38upJ3UI' + '6g44x+NLXcM+5H2CCg== e=found last=15 s=17 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWpG0npFRhbH92UGlmsdLcJ5K+Z5XCJYh36fuaHz0qhU= priv=MC4CAQAwBQYDK2VwBCIEIOAVsqAlrF' + 'Cg0k+rvoz/3qSMHdCGxswj2F814wNG0jxW msg=wd8M7e33U0tdWlZFgtXI+fOWwDcgPg25PFZspsla14Tz8f4jIK2CsQrSxtZgS' + 'N+MEaCIgy3p9cRIp1afGTITxQ== sig=ZWbUkdTeJpADQLwRiGH4RX1WZwZXDPugxLYU2N1Pao+vObfViQ5BWm3NXpTnHJPjnrS7' + 'VNDGWoG7vTe4l6u8Bw== e=found last=15 s=18 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3k7BzDYQSsLY64V3S273re9BuZfZeSgdheM7l4JpXug= priv=MC4CAQAwBQYDK2VwBCIEIDdvw4Nhg+' + 'wrAOH2GLqxTtot3uPnVcbu2mX9miEmRgXp msg=miEmRgXpwsl+ns5PYUJbr6dTPYWRmlkqYjO4alal9RjcdSnwEyE+y8Hqm6CPt' + 'rJsltA+PgBHvvDHEGuW/hJGng== sig=4ChblR75A6ZM216R85mj8MZIhe1xt83qqrt2trHCsq4Lh25L6/Woi7bCVD0pVWvc3lD2' + 'BDJyjbT3QCD2+TYIBw== e=found last=15 s=19 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlfQqLgqBFHehUOWnU4eN/gm+CKSkLmSEo2n1K+ELKx8= priv=MC4CAQAwBQYDK2VwBCIEINwW4QAMDF' + 'HX+ddkvy/A7wRycB+ahyKgLtOdQFtfaxPL msg=dDajbxZOplSoV4lyWIaQHXqHNcXXHojUYoc5lczMklv63BbhAAwMUdf512S/L' + '8DvBHJwH5qHIqAu051AW19rEw== sig=zu2yGljWkC6D/Zawl4LUDA4XcdMguA4OAW3zb9Ui4EmhMLjfBrOZ752oGjC5PpwzPwhU' + 'Omy6gxB9mfMi4Z05Cg== e=found last=15 s=20 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAs9MlN6HWo2TsgLW0LomaSow4B3pBzPBXv8raChJ+wdM= priv=MC4CAQAwBQYDK2VwBCIEIPJ4b3lQ1l' + '4H9WQpccfz25THdmBSSibuFNtovFUUtU4p msg=4FfucowYvTAsVRfxVHpWUTh8XcUP8JkLZ8eKTz1KW5WBFN7N3BwTatsFjgYwE' + 'VOoMOlLQ+zqIMPdzsHStkZJxw== sig=PhWrVJgl2jPJbEP+jsAJjlYhH/9ZU/akRPPC+bjZJASfGtLF81sR2dtnEJJ67IOrmrn2' + 'VrqDyCmbaJp6mPMyAg== e=found last=15 s=21 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArqGiXTDjJCRBvXI3MlNRwyuLil3tQLSynDB3QUHSJlk= priv=MC4CAQAwBQYDK2VwBCIEIJFCgCW0JY' + '8ueKKD/cJ4ucM0BdZtx5pZ/Dkg38uoWyL0 msg=g/3CeLnDNAXWbceaWfw5IN/LqFsi9ModeJ4fggVFU4vojDWIaq6IwmzymEwYh' + 'zDgYkvkROA5V2QagJYmC1j27Q== sig=s7dchSkDITB2wp8tjoM8uKhXm52Frej/g2pvJ4Stq0kJ+uyuiGQWTtPiub/9PXploJzd' + 'd8AdOyJsrAaPcTFiAQ== e=found last=15 s=22 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEASXFlHAHXy2RrnNrM60PBTaWA2tokGbavOK3DyMqRDL0= priv=MC4CAQAwBQYDK2VwBCIEIEJ968k9xw' + 'r745P0kFdd/0A2cPKOqXhmuIiLPYNnz/1o msg=GOBQueZP5hzvyveAeVQKkHMT1dMB3UJ968k9xwr745P0kFdd/0A2cPKOqXhmu' + 'IiLPYNnz/1ofWfYdsoDJXcTkQ== sig=eFcuG3DdOPYdBQTo79MKfDN9ZPzmq2NhVHFgs2PZPerqLsWm99Tyd7OC0qxwlwHLnPIb' + '0jZavOT8RrD2YkP6CA== e=found last=15 s=23 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAydzyd2wztJHVVpRd7QvF1/1/O0uW+0CXI2g5/5r+6Ug= priv=MC4CAQAwBQYDK2VwBCIEIGgiz/cBNB' + 'H71WkV4DvATy+hnF/xLfxdCL6yyEiMzSpZ msg=whfAgLqpkFc8gpVfLLIjpYRMX2HYhE5IhiUZkzEuTj7J7meT+D1WJgDyxlpoI' + 's/3ATQR+9VpFeA7wE8voZxf8Q== sig=Cein4zxKbMhz6VHuGVmj50forw8RKeBhYM9CJ6WEy3EKRuHpPivmRi9lWqGJB5EbtxMY' + '2mU/QuRvuUD+Oq92BA== e=found last=15 s=24 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEANQPE416EO1e/YIfYZwokJzJW91j5FNWLI4swn0gjmP4= priv=MC4CAQAwBQYDK2VwBCIEIJmNgRfC4y' + 'HNaWrqxXrsWJKFIh0OWjsKmEJ5IWfsA6Nv msg=yUhk92hrerFdxOl+q6q2FjHu3iXHlfp5HJdgnfXszZ4tk5meUPBMTESdSY2eV' + 'WZnL9DULjnZihjHX5armW3lzw== sig=1k0Njd/4NDnJ9WkuvTZnFMZ1NIfG395A2P6yqhJHV5dcw4SIAY+IWxQoQEmTdxUrH+IH' + 'G1m877YwKnDuuWn2AQ== e=found last=15 s=25 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsMWGI3+oO67hdRp2aSpGVGYBDsaWyLki7aWs6HAS6m4= priv=MC4CAQAwBQYDK2VwBCIEIHehqPYlfB' + 'fYH90FLccoweWZpMM3Evmdp+hdcWHWuJR8 msg=TMOMgHpnLgnRa5NAh3LwMx5b+r8duN4Bo9LCl49kdeQrHBLKgwRsOM1b8NzoI' + 'Osq2TNO8m9K5bpw4VlImnehqA== sig=fYLpXn9C5x19l4cN/emKTDM81tdIg4G0nN88nuAMqknvuNMdmMhPUO4KTBrGP5obyo5s' + '39MJ1WTK+fe8L2+VCw== e=found last=15 s=26 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkiTmVwCQkfzx6JjgC576f6dw0+Wo7PTp6xzcNFGxzRo= priv=MC4CAQAwBQYDK2VwBCIEIFgSkJrNtt' + 'ZPMxJC757hYtsjF1ca2kacH/i0Ku0h/mzS msg=q6riLhAv/Ypbki0gVo/QiyLt5hORyMPlof52FyoujQS09l9gA/ydd4B2QE8dL' + 'oWSRFcwKJIGHN4gpaZWZuKFqg== sig=Iv5NLvdV4kc/cJAA2bvnHgMXibj6tj6hWl97sZz5LA/Ix+Vh0VgsWHlEHEc0ccVZwGX2' + '5BqSrghL/abxVFz7Dg== e=found last=15 s=27 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEARnKigl2gKR5lHyyUuORJYruDxgUj7O0p6rNG51VmcC8= priv=MC4CAQAwBQYDK2VwBCIEIC9mp7zcDm' + 'rPd+sTwmZr/LaLlXBGvsOLxpNicHT5QgGb msg=aEVcx5Xb3s48Ip3cG98+XLEhSkJG8q+W3GEyAGodlzK9OemVEJRMat3FumovZ' + 'qe83A5qz3frE8Jma/y2i5VwRg== sig=BN+ew7sg31lM0Or+YY7hhYtM29C887tHh/cEcXT9sOLW3d/5x7hQN59QyHqmQ1Hn+DpY' + 'IhZQPqEiAf3zNbbSCw== e=found last=15 s=28 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAn+8vHv2QlMeijiySod0yhElhWPghcpH8RHfY9tkT7vI= priv=MC4CAQAwBQYDK2VwBCIEII3SQkZSpQ' + 'QX0mZDz/iIlHWX0KMJNIMYWraCOL8yIUfg msg=R+C0Dl7wrlYM4046xoAOnfRsh0PtUrf+QH/jvDEHWpz7yNeCHI34NQH9nZnmf' + 'y9B0LWhS0dyeK9iODjOQJG6Eg== sig=M6oJH1fCDACrWcGoLD6LkuThPgUQLUbmAT4cqz2V7O/2JS0YIqSZYM6Cpn1VZHwLEsu+' + 'oYJaMi3LVnsnLU6QAw== e=found last=15 s=29 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIMh/nCVYBLpo9bGoFamZ6AlkjUWSFjc1hwflbTYzACU= priv=MC4CAQAwBQYDK2VwBCIEIPfQE8rpMw' + '8Rcxk295Ltio6b2rynJAsk1wnNmIRIZbSt msg=tsDUiGmiJBMz9vfQE8rpMw8Rcxk295Ltio6b2rynJAsk1wnNmIRIZbStOkQv9' + '0OkGM9Ussrj9ZTwkyQL4A2tJQ== sig=u3/pWM8j1SLylE8+L3W5p1aETwMEmu2bmfrb/6q5lr+oq1gaTJ4rMEAyEbvA0RQ8b9oi' + 'R+LLCQBdTBqz8F6TCw== e=found last=15 s=30 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOV6fvMN4gZSuTKffd2zbGskWB99hr7res2WhHevHuKo= priv=MC4CAQAwBQYDK2VwBCIEIP6a3wkUPL' + 'bsJbS/EMD6XGo9/yAyEslZqQ+GH/q/tyE+ msg=PLbsJbS/EMD6XGo9/yAyEslZqQ+GH/q/tyE+pPlvTFtdT/MscOwng2IuQ4WDV' + 'oumejzPuqC6Wf9pWwoGlJDb8w== sig=q1tizST7iXXD54JwMFVilPEkRvKl/M1E+WGE9tRXsjp+1fg2ETAV2rjxvWwJQjH/Yy92' + 'zPQElYF4WI136oB5BQ== e=found last=15 s=31 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEsGGSW/Gu3HAiv7/MPHz2PswMvQM2bOJfuTXxFWqRQk= priv=MC4CAQAwBQYDK2VwBCIEIFkwoE6pPs' + 'uNV1xsq/cmcWbZVL+mL2rZT3OCFxMMQz+i msg=y4qiB5Qpz11hMHNMgKISD1kwoE6pPsuNV1xsq/cmcWbZVL+mL2rZT3OCFxMMQ' + 'z+iYvuoLyjeZB6EK2LUFQFY0w== sig=8yXqIsBxr7OtWWGg67O0HP7dPWFOYv5H2GbVzNMYo280/3wRCYMmOP2Tq9MTuEfUlise' + '5EnPOUtaDEFEK1JvBw== e=found last=15 s=32 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFhE4dGE8o/tUm/hx/aP4lTeL+I+aTtO/z180zOJYVqI= priv=MC4CAQAwBQYDK2VwBCIEIKGfcdFXVq' + 'OXnS+XEI5thtOtaRULhGYecjjOYX4CBQPV msg=CTOPoSYin+Ap9x5x5DkEy/HxQLx0kVh2gwXDZWJK5HTJOK/ZhIFKnsI9QP9hB' + 'ez2KqC4/hgni7kysfll2488pQ== sig=nti3YWNNWQXJ+17TRji0aTgToPBZ5TEx7UfYOelGNbO6DVHrplr3elQ3lOzQdk2lsIb/' + 'Vfs6GyRBEDFprwv2AQ== e=found last=15 s=33 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6bUz9hWfvAu6nzxcwUpONCWGks18fsDqk7AqFS7PXPE= priv=MC4CAQAwBQYDK2VwBCIEIMp7R8yHwf' + 'fb0d1CQfD9mVF1k4pC500P7R3AQqAZRk6i msg=QL/CK9Mw29OWSs0hwU9alwfWKSsV1hERVwoFO1zVHnkq4tpuBlPp2rnzPNPuf' + 'RbeIFnKe0fMh8H329HdQkHw/Q== sig=o2uvOo/nANVXhXTHnzHjzOpNJ+ONmE4cbXBtHxo50ck6zbLGevizJvjO5H+YkGjsRvY8' + '+DsKhREwvcax7uJLCw== e=found last=15 s=34 in addShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQOWjVLS8HFScIrUbwVVgRP5D9jTS52XeaGAuDmxYAxQ= priv=MC4CAQAwBQYDK2VwBCIEIOk2lhkb4h' + 'FslloPTx+TmYKr4NxMxUlRnD8PQ4craCtL msg=6TaWGRviEWyWWg9PH5OZgqvg3EzFSVGcPw9DhytoK0t6CFR3PZeN6edgjxrZ0' + 'dW1zVP3rgaEqleaFNd8URBEfA== sig=jtRs/UGspouo0iYaFfBd8wa91CSa0pQV6xSeLCnsZluk4AYiVNBWjFZZ9oU1HsPLzdDE' + 'GpGbmU193LnedXFZCg== e=found last=7 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHpDsS5HdjkJb0dCYT5hhddSm166G9HQoC2k3GDMD99I= priv=MC4CAQAwBQYDK2VwBCIEINw8Y9Rsrb' + '/5kqGsTPwV8STseqmv84Q6YKEcEv2w2ovQ msg=3Dxj1Gytv/mSoaxM/BXxJOx6qa/zhDpgoRwS/bDai9AwMttrMoZdQ4iLnemnl' + 'vC0ZTWWwwRPXcEbopP75BvxrQ== sig=3EJD6U6e9fjBO2Ju2rN8P6UK+IsJ2uyLMj4wD7fh2/AHDfwpbFJTZMXsl6EX5OqJ6/W0' + 'Yq2nBEA+fcO1zo2YAg== e=found last=8 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6DIyqh98QypyNljYuK0Yox+RY2chi22UFMQ6mKbbvys= priv=MC4CAQAwBQYDK2VwBCIEILUJF/RnkQ' + 'pvBEq73BpXpaAjBEsuCA7SojGFSm2uVZW/ msg=tQkX9GeRCm8ESrvcGleloCMESy4IDtKiMYVKba5Vlb9l9g6m23Tv9nd2XfUwC' + 'NrBRtrCpKiOZaufteVa7LXCHA== sig=WRWiex3AumHOjuLndKw7p4OdjJM8pidHgY8YzsTjSjtTtwRJvzLgbBOP1rPqxFF+aF/U' + 'qloJclS/gda7o5uEDw== e=found last=8 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsOPphmmWs4k9ctn9dMnHIkNZXI5vuvTckkPaIrwiNz4= priv=MC4CAQAwBQYDK2VwBCIEICFqwYdweT' + 'EkVfkZ+ffquTocIx7s8ZgPGe6AJdCewL5D msg=IWrBh3B5MSRV+Rn59+q5OhwjHuzxmA8Z7oAl0J7AvkO0ne9GYj1yT4wSeunnn' + 'b1VcDxjtZ+w8qN8lBfZDzVnzw== sig=rdFSJFIg0Hqky2z7dPucCjxjrqJQPHk8bMkby0AnuRkKA/E5LLPuMt5EdPMYrCyxXPHK' + '9vSBkwahgIjwS+jUCg== e=found last=8 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAUpNUaZcL+urJA17UAKo4Na2VoztV/aVyEyQj0SDBjIY= priv=MC4CAQAwBQYDK2VwBCIEINvxglX/8m' + '5YI+eDzCvDM0nRlUlc+qwem9TnZuCHORda msg=2/GCVf/yblgj54PMK8MzSdGVSVz6rB6b1Odm4Ic5F1pDLTRl2QeNY9ip4/jVf' + 'e59LnUYO1ot/Mf1FOTl1ud85Q== sig=9EpPk/qHoEZURIE1CR9XJfmceZXedjBkCfvWaI+sGTawJSEqoOrT22xOwVhYbUWviC9W' + 'SK5WSZwt2PRo3IqlAg== e=found last=8 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6MHneu2YsrotLji+Jd91XULghdgZq5xaW8kjkGADM34= priv=MC4CAQAwBQYDK2VwBCIEIBOC9gDzHH' + 'JcD2uJi6iIeysCHFwlwl6fkfW22cuoRvYm msg=E4L2APMcclwPa4mLqIh7KwIcXCXCXp+R9bbZy6hG9iY7oT7Qv8XnP5Vc4tZMv' + 'OeWDFf82LQleiHlZO0p5w881g== sig=j3k6/eCF2wO0x83LpLHD4Dmi2HCrAcd0me9QL3y8AIbRiutQJp2s/1Jcp8tRTaAyrLNY' + '1lcPWuFEABMrzF1OBg== e=found last=8 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJbm2aEiyqpX8lQvQ/f30pAd3anLtbpdVRcMl+qodWgk= priv=MC4CAQAwBQYDK2VwBCIEIHRcig9pYt' + 'mZZq/jVW/nfTy85QH1mbViwciYy5fCq1qR msg=dFyKD2li2Zlmr+NVb+d9PLzlAfWZtWLByJjLl8KrWpFE5ir3WAxzitYBUmfKE' + 'VFFQrS8Vazb3lE9V3X5aZnXYQ== sig=21WAOMBavwYUk2pkYkW5N4wLK5QNEhspiX9YTpV2eWciPF/nu20U1hgKRWRilqfWNjs4' + '0C1qTc8Bk0GD+EfEBw== e=found last=8 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmM3/Zggp0aOINx+uhCmCIcTsi0k3fmMSgBPTmNrSaYQ= priv=MC4CAQAwBQYDK2VwBCIEICfJ5oMNeY' + 'YIEmcbLP25t7BF78SNRPL/J85/i/uecT49 msg=J8nmgw15hggSZxss/bm3sEXvxI1E8v8nzn+L+55xPj17H0rPKN6Z1KDATr+4N' + 'liCZqqKhQZZbtiqoJOZtQsapQ== sig=2zvO7FUyWl6Owov/MOz5i8AD/Am9fE1na5lj4BJmCQiWkcPIi26RXQG7rkZ+pPWMz61g' + '3NdwRABx4E7gASzkDQ== e=found last=8 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADE6T1shUGBsIc3CImli1AnfE2K0u4+OGbUZjPMGgQsY= priv=MC4CAQAwBQYDK2VwBCIEIMWzWhvXzz' + 'CvC3O42bY9uM8LCEPxpQbCXxdHb160h6AX msg=WhvXzzCvC3O42bY9uM8LCEPxpQbCXxdHb160h6AXa4QHMXbIx1KTqyhmmTzTC' + 'hmMIpKgj7H1Yna3dqNYJAMqcA== sig=mKKQZof5Y9VGkqFEsxwDHk7B8VEN3us8I04xqqUDYC92wGnnanHlKAwYJbgxa0n7oFqz' + 'duJk4tto+xOsnVv1AA== e=found last=8 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAzpSqMVjUK8gtPguKb5kMa8efjbfnIKsDFIHjrN7qBmg= priv=MC4CAQAwBQYDK2VwBCIEIKIlq7DD50' + '2/di/TdOJUV8vmyhS006JckoF2gVwpUwOk msg=w+dNv3Yv03TiVFfL5soUtNOiXJKBdoFcKVMDpPnqXJMPC5yetvVu42FzW3t4N' + 'OADQA8Wivsldxdui28//itMxg== sig=PhZ2Ijp8mQbM8+wHdq50wbLCxErrXPj/1HaPQ0deWK/JPMM1QAAbbvjTf+zUFUEGCPqv' + 'Sj9IijwwTVPaO/5mAw== e=found last=8 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3rrp5Lk2ewftAO3z5nG36OhfbjpB7XKpr9kgzVRYROM= priv=MC4CAQAwBQYDK2VwBCIEIDxxFhXb9j' + 'xcvIFcS1TLTN4bohHnXqVajuY8TODG5dMT msg=PHEWFdv2PFy8gVxLVMtM3huiEedepVqO5jxM4Mbl0xNcqFt1yQvS22NFttzVX' + 'hiHfe4caoFf+ZQWGh3WY9SbUg== sig=/+Sgwa1h5dueYC+7h5byNCLiah0kGXxtmni6RQV9Bwc2hzurbl/QcAINduZ9WEqZNwds' + '5EcUeRsWAGidwZN/CQ== e=found last=8 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAVnMG6RGk0i5P3WqJ2aG9UK+M2ca/55Aea6g/+l7EUww= priv=MC4CAQAwBQYDK2VwBCIEIDW2QadQ+q' + 'ZPFQAX1IuQEn7B6qSL9S+YNr39YcrUqXpu msg=tkGnUPqmTxUAF9SLkBJ+weqki/UvmDa9/WHK1Kl6bt9UABaiEWsrQtfYQXfSP' + 'siQd9yBDR5pak47uCj15RAEsQ== sig=da8aZTRvOpgUsPborKnMR64rUxpfzK0rpe+bQHStE19ycwN64UqZ6ZwTpSd61wVXf7UO' + 'msnduyiBGxDyH/KrDw== e=found last=8 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhzR1lBSAxLgzh+GOtDL0SmEROPHyf830DoknO3rZSCg= priv=MC4CAQAwBQYDK2VwBCIEIOLG5d/aLc' + 'hi6RU49063TRpIzFe0GEcGBojNcUQz0YQm msg=S7fc3vhT3HVYeueii0Kx3BCjnIkRHcf4aoMI3JkYSqBZRcTAQNtnXuzOBVbQ8' + 'BYNFEFVzk1OVlRiUoUR6P8z0Q== sig=bGDjgYraskpAMLfFreimXEEpLz3k6Y6raYj6CMe0g2PMTnXjTdlZZiAkZCxVWt2aYgR9' + 'Gi0K6ZbxP1Nqt9brBA== e=found last=8 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvrWfI9fDJcar/1uHZc1ano51EwLz0IWUgfiq0MX3/M8= priv=MC4CAQAwBQYDK2VwBCIEIPiGUJusC4' + 'PuuuVHim7ESYTKCA+m+S0C9sPILIBphIRi msg=rAuD7rrlR4puxEmEyggPpvktAvbDyCyAaYSEYmkv5YsPb1jOtoWaSBe0SOxur' + '/dSCZpc2JyPi4k7j6bdFdc7Xg== sig=rim4EnMXhZ+TOBWZAJqFnNiVC7PZvMSG21NHfILXtmmrUVtwGjE49RYKgXKQdS2nOtCU' + 'ri3cIYlKpDx/q4mjAQ== e=found last=8 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA5aNMKVfRETU4dms585gbWhEaAZqd0vi0Ej8Ps9zmCB8= priv=MC4CAQAwBQYDK2VwBCIEIIstCfgUrc' + 'c4sLn1ZtzmathKJalmBl/IiYD7mwEALK20 msg=rcc4sLn1ZtzmathKJalmBl/IiYD7mwEALK20iBOFU0n3ttIytnsb5T/48qnXm' + 'Et8K3Imk5/5sHTV+QrtKt3Kmw== sig=JIfvFOG417/+2nB2E6wBvhEygUX0M20x+Mb/4iCFwWk7nqgx/PdBOtW2BEWNpQ4rL7pI' + '4GDYoeyajiKH0gy3BA== e=found last=8 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAYYrBoQgHnuS3levk9v+0dHzjjgwrqbzr1md2BYet3SI= priv=MC4CAQAwBQYDK2VwBCIEIM82wQ8CAN' + 'jO1CG/b1OTQaYbZ3YsHTYm+XsYep1W8GSF msg=+XjLwCOvHBXSd35Ir5r6HwxX1I572Q6fqS8Ox9m9Lr3GTYMWFmP8VBqRlB//w' + 'zVL5Hu7iILUcnUtSluICXJO8Q== sig=OTD+joRNVjBhAAkd/uWYPncrS/2W0VvMO/FYJfeHDDKkYt3lrf3N2vkeS8qz9Z/zQU1+' + 'KdtqRfvFzl3LgOhPDw== e=found last=8 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIKBZnfaaVcEBa+FTJpmmHBcf4vcKcO4+5v/iXFHTpDA= priv=MC4CAQAwBQYDK2VwBCIEIGlMcS18gS' + 'EMcGEO0pMWxVuDjZVxdEcvojU+kcm+uKz3 msg=gSEMcGEO0pMWxVuDjZVxdEcvojU+kcm+uKz3DwyO/EHrm4tedZuam0lavgl5H' + '9ofO8YSXRb5C2CmcNEU9clpaw== sig=RHIkpNTnWwMw6heqe4RWysE56S3KWuJ+ysaqS/ox33F8Q1BwSzdI8Ibw50hktTQh4cjJ' + '4zo8R8M6jsz2eULaAg== e=found last=8 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAst0qEVaT9cx5EsTjMMxhbVioLL2SKylkinapAlQDZLQ= priv=MC4CAQAwBQYDK2VwBCIEIJS8U83Du3' + 'KYhZFU1epgqTPtXhg8IeZzTcPsbO2hiSe4 msg=C92G6vybK0/OB9IVLBiqs5edD3hzE59d2jKUvFPNw7tymIWRVNXqYKkz7V4YP' + 'CHmc03D7GztoYknuKwL6nT2Lw== sig=to6o3wB3LzyrSDLMlx0xtiD/n3xFvWDFhd+RcPtIWAhN0etBXzQ2/I9hMGPRIH8kiZR/' + 'EXX25iySlLjFCAe+Cw== e=found last=8 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAF9BYIgRPjgjjGcepOMo/AiqnqiVGqMSHpyHuONz3bR4= priv=MC4CAQAwBQYDK2VwBCIEIC6nATsPKa' + 'LuyByUlYebKymCbWfW68VERpxTrGuBCwlQ msg=LqcBOw8pou7IHJSVh5srKYJtZ9brxURGnFOsa4ELCVBtOlDCn7WU/PMKvzvaR' + 'XlYuePfKlexOuzBhjxWxQ4AAw== sig=ahGLVRQkrSRM9ZrBqAVqRZoBYedjDEIsvpzTbqa8KrSZsMAwt5q8OzkiyhKCyYxBcAc4' + 'XHSszkqw5inLN/pQDA== e=found last=9 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA2/2e6MYTlS/fclD5T/kdSX9oWCRGPmYsquX09bu+j4c= priv=MC4CAQAwBQYDK2VwBCIEIL+kLt0ceF' + 'xI48cdPWlA4W0TydbErsV+b4MILG+ybLc2 msg=v6Qu3Rx4XEjjxx09aUDhbRPJ1sSuxX5vgwgsb7JstzY/4lJOQ99xBJw/s/wFZ' + 'EEV89wb7yzMH0qLfm/CY1k1AQ== sig=GlN+LGpJelxKsro0x4t7fXUrDmh7kmZywIo8Fts9y9+dIAHdOTnA2PA3z61VfbEEJYUe' + 'j3cZa80Z+VDeNzrACA== e=found last=9 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA5LrjnzRFio/PIEWVRa/l2N9/r3k3lffCpvPId8IlBHU= priv=MC4CAQAwBQYDK2VwBCIEIFr9mVmLBH' + 'lMFusTtVzWhBG8xMK5zQmGvqiB/j1pFZHL msg=Wv2ZWYsEeUwW6xO1XNaEEbzEwrnNCYa+qIH+PWkVkctr8cmdBbMc2NuHMi9/T' + 'FAy9B/5MtpMmeQuI3phoLZn2Q== sig=9IudH4UABWyKIDvuf+Q3akxRoAvSoSs1YAcmTEysGygKIvuQeF4XPLCKVFoOwL4/znR/' + 'hFJ0AnaLdaw9xbQpBA== e=found last=9 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEALDhuzQrSuz5AEUvn/9FYng2aq00nrlvSxqyZJZs9tBI= priv=MC4CAQAwBQYDK2VwBCIEIAP0Zrcs2x' + 'icBhloCCdwgv0eP+kVkF3iW2ZyXEHgmISb msg=A/RmtyzbGJwGGWgIJ3CC/R4/6RWQXeJbZnJcQeCYhJuDhaaS5OBZrjdbJdzHq' + 'Gd3LVOagaNSxkbsjz43n+mdBA== sig=3qXKA/IggPNDtIlHvjKSQl4eUwKd5f9aoqeTJ9Si9zzq/r7UGaFKCIlP7mBYcqZv7Xf3' + '3LXyaqxc3o4OBFBmDA== e=found last=9 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/4uf/6NIOriyqDAMmAlVFMXvwfTgjMOoBYjs+a5P0oc= priv=MC4CAQAwBQYDK2VwBCIEIMuA+RdrWI' + '5yIPOBFRfO8Lst9vBakrBC9DflgiMvujKg msg=y4D5F2tYjnIg84EVF87wuy328FqSsEL0N+WCIy+6MqAhTKXQovvWKFoYCZGQl' + '+oG9ORLylitK82LNPBNhmX/Cw== sig=LnDenkVBWLSds2Dz90TRDBnSFuYoJQXSMj4ptCMfBeynlbJUstLTYpZA9m9uZZCPHl6n' + 'fm0J0p9sGYJp/zVkAQ== e=found last=9 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAiezuTEFbeHb4ImjB9avUZ/nA8mgsXkE+jy4MZ5oJ8ME= priv=MC4CAQAwBQYDK2VwBCIEIGR2rV16B/' + 'gWo2blA20GD3M20YwIwa+CcXB6o2qLy3Rn msg=ZHatXXoH+BajZuUDbQYPczbRjAjBr4JxcHqjaovLdGf/dXxC+gbaYgEuWlaoc' + 'lAOBjtRBYRWeqVdsVuewV9baQ== sig=3DQSYaBxLr+a/L2B568XGFIaXS/QM9KTEwXmKEDeD8+3zUJ4IXCJdU7yyeG1727PX8ll' + 'lDKgcpUrJtEA/jYFDg== e=found last=9 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcapOHuRQJfvaPnaOn0sxRRTW4Qmwze27fX3VYrSbu5o= priv=MC4CAQAwBQYDK2VwBCIEINRL1nbSNh' + 'RX6cAQ3jOuhd5k8G/nloedR9226gmLgUUn msg=S9Z20jYUV+nAEN4zroXeZPBv55aHnUfdtuoJi4FFJy8Lfc72pNo6cyU3j3a54' + 'NhLFW7os1REBEgiHSZeu5Xnrw== sig=6vamBUAb7DRAbYNpDhnoKYbXrX73juRu9DKEbFu9AJvsrlWH1NiXaQ/EoRjE9qt3vAAZ' + 'WhO1h+InAFfP170UBw== e=found last=9 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvlgouF9o+BIa0+bSqyjxVHv8DYz7EXiuf/Mo6IuhaBY= priv=MC4CAQAwBQYDK2VwBCIEIApbBTashD' + 'tYAboqQbj8//vRgEE3l4JLCUKNouY7qzik msg=ClsFNqyEO1gBuipBuPz/+9GAQTeXgksJQo2i5jurOKQY+su/SXwQUwt5eZWhb' + 'OuhSatG7FR6hUAbNQC1EUvjgw== sig=i5/8rX8bQlxbOZOFa2Wg3HXg4ygclmXDnZ/3H9DwBLCgrCHqCp8nO+0vgqnbFG3thCGQ' + 'ie2z4P1mdUGwvg9XAA== e=found last=9 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZuTZg2F7egDErwm9ru3QUUZnr+0LAhcp4LHbZSptgts= priv=MC4CAQAwBQYDK2VwBCIEIDsPm477mN' + 'XnfkMvE96DPJBm2NmmazyBGYinLp1E8IyI msg=Ow+bjvuY1ed+Qy8T3oM8kGbY2aZrPIEZiKcunUTwjIjkO89kMLWLpt0XDPV6p' + 'DX2ZPBgTAVS/uAA1uB8j/j+JA== sig=DBfVPPdm+KzlgtxddC0L4HzVvmCk9shkVem6fBKxfQVuSCobqS5b6nVGJU9iHwy1smcW' + 'cv3bN6/4EGILmd9LBg== e=found last=9 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgQC2vVXNQTuxDzy9YGFD0MpmlTuV2ppV/h0tH9idkN0= priv=MC4CAQAwBQYDK2VwBCIEIJtoxPFBO2' + 'sScb71Hr2DbfzEkq5qTTzaWwI/g040oW43 msg=EnG+9R69g238xJKuak082lsCP4NONKFuN13bl69BcZNHGgPpPLvyXt3okmAIs' + 'uBIDdbLZKDLCVf+PK4Swpq7ug== sig=mwttA//XS/Wdm7uiw9hIceA2Wt1thjfP55u2d34QhP9abyQvrF9cEMBWpKo7IePZlYjY' + 'URHwSUoiA1bQ1nAHAA== e=found last=9 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAq16R7SY4zHqSbN1YqUCwTJGTceUfPgEw9XbGMXjZL2M= priv=MC4CAQAwBQYDK2VwBCIEIM0h61oL6U' + '+2x1Zxp6IWztJbSnHcoVsGuLyXWwHBEIgs msg=IetaC+lPtsdWcaeiFs7SW0px3KFbBri8l1sBwRCILN7xT7qepRnWuE5triy6k' + 'jjMh2whg9oxZw+bwiembws1IA== sig=6tz5M1lAtk5H1NqEIM/Dpw6lG/Jtcf9HzDT1+LeY3fOoCIb6gVBHy25qY0SPRzQWX2Hb' + 'nVYfPQq/nXmxTXrKAQ== e=found last=9 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQB8bc9JfcTpXsHfspyQNHuVP7nYX84QNvGQMQepnXQE= priv=MC4CAQAwBQYDK2VwBCIEIHImrYbvFi' + 'fg0hyWyaDVqLo2P3eRcBFhHL4t0d3ATOcu msg=UZ2K1Jg4CpmegQ7JTwzGhx5EwNBqsrNP6z1WXniKp1m3E8W7C63BG8WZ73aRV' + 'fBoSYPg9dOlG6mxcJ5cle6xCg== sig=aRepJNngISeBdgXQwp0XDK8/qPuQsIzT472Cv3lmMQOm1/flXFOObTx4ti1ypvdcjzqV' + 'td+sUBVcxPzsSrmRCA== e=found last=9 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAl9AaTm7z4+4DiWdaAPFud+Hv6Aa5Jxs2jaOuDvF4t30= priv=MC4CAQAwBQYDK2VwBCIEIHbZctga5S' + '0B42NKIyQqsGBOC40GI1NGB7tr3lAffJga msg=GuUtAeNjSiMkKrBgTguNBiNTRge7a95QH3yYGoUTh1cF791CXmJbyIol5NcRu' + 'zxIyDueFn5OYK3Ze7mS/mYqTg== sig=VXGhE3o6mO/Zh78K3Z3Lcs8/7fMMBCPU+CzRnteGPcXeJ2qpO6L35KIf0XDx5nY9Tkah' + '8N3EOdcWr4d7gA57CA== e=found last=9 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAYNtC7mIFJzbH5BscQpBMRHpfBG6lawnVvH94GgMY0Qk= priv=MC4CAQAwBQYDK2VwBCIEIOLVcpGzik' + 'OrIi+ei+JlrJ/I8PkcbZ6ag2awevTNgJzz msg=yPD5HG2emoNmsHr0zYCc80k4Ie2c20n1wiX/Ki0KuBeDnxf2CkdQYzqxYh6Lc' + 'ZUYlk74t04VUwReiVjE2rTI1g== sig=HCrJZDl+4qRxut1p1JohrVxOiynq4c36GNEeKdMHJox3nmHbtj7i7opVwZWPS0cG3Qfg' + 'u303FiF/rEVBwY2nDQ== e=found last=9 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArIx5QuNi8blTY8Y8nHKr3KkPyQE36qBOjFPuQpT8rVk= priv=MC4CAQAwBQYDK2VwBCIEIJ7WPauRIJ' + 'mLPGEtDrBV8iXvjCsEaHenWO7QsivxwGoA msg=1j2rkSCZizxhLQ6wVfIl74wrBGh3p1ju0LIr8cBqACp5bgS/XV9ENJdisO05y' + 'EDGePDAj666zUyKyxnswwVYxA== sig=K6Xq5/z8Mg+tE8cB2hLCV8avYSzY28cfMti70nP9IYET9s5qKTDsNZ9OhobR4e5TN5EW' + 'At3c86D8N8O3Dit8AA== e=found last=9 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAXqLF5YCe/8P3L3oDlinVgMoRXY7t22se79RPOxFWoNo= priv=MC4CAQAwBQYDK2VwBCIEIHD+hcwKq4' + 'bP2K3VjZL8BfXNNRJ+nuN5+8LRZ2s9Nr0f msg=Pal43Sb4LavCS7gzX3Ux7lkj0mscShmK2ia9qylM3AxWxwuvoH6fx1rVirBlU' + 'Nxb0blT1u4Q0cGyGQimntC6MQ== sig=P/UjtY1ZuGH5fqlmyfq6XAhd2l4Og22vLf4bQ9ykQLf09LdF+o/AGA39ijjT5g+SOocf' + 'fQQuNmPfBCUmmWxGCw== e=found last=9 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOEAxBV3yl8WWPEb9pHVApWWayBfYLb5IqdYf26uWiu0= priv=MC4CAQAwBQYDK2VwBCIEIGmx55Ykg0' + 'bNw9GGMWflsjY7wjajw6giKITEpqNaHpKO msg=I9tk0/EC9Rkc1eJz2DiR5Am4Q/QgX3Gg1mOqfZ6SiQ+mkKDjhBDBIzKjk2o0h' + 'ejD8zvBT0OUT+KCtF2wF0f2Bw== sig=wzqcrj2Ji+oIMZONjxK+T4PNG2e1Y7UYnjbgu2wJiI/5KLYQXR1MU9v2VLq0hB9nzSGN' + 'egbcxezdWeH4DiXPCw== e=found last=9 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFQaUhfymR3LFT/Z9bKqO7WCbd50QQgst0lJKq9/0JeM= priv=MC4CAQAwBQYDK2VwBCIEILW+D5MYor' + 'zzwXsKfrVSV9S7ptVNwydnOku7PYBjjwjM msg=Oku7PYBjjwjMI5GMuqKjGkwOU+HWde0dC6e2dYR/yhGDIGffIWLULoGEUHAjK' + 'LNV5RsB26D6JRsg7lLiwz0Rng== sig=f5+BuLBHJIwSfKKuX6c2XrYeRCkbAp2lbpBziEXX+dRv8wT+Q2511YzpZS4dkzovW1Dv' + 'FibhsnTtrQP80OebDg== e=found last=9 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAE/Z4qCZf6oeIHPVVWG+AMN/7hfF84KomkN0DPtjcu5U= priv=MC4CAQAwBQYDK2VwBCIEICpEqkRkem' + '6SBSBDYSkw84xk3Q48gWiBi11aNw8C8P4Q msg=aIGLXVo3DwLw/hCfctR6nmBIqEo8LURISYsQm3YG2UH+CoE48HuqAJ7I+RW6B' + 'Q1PJyM9rmB/HqnpOHV755lZdQ== sig=niWBPhruKdRYBojP2RO/3idMKWzcNg8SsFvlxpnjxAF7yMtGoCqG8RGnsPQGmUtQXyCX' + 'XyG4IsXpUVxdz/XkCA== e=found last=9 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAp2itvPl+z8LZEbur+hJ0qthBmtbb0SABFfXYGei9Mt8= priv=MC4CAQAwBQYDK2VwBCIEIDtBd1vceb' + 'TMWI5jKpP4CSMbE4CMKDlN7frmxsPIsY5+ msg=t/ICSwiQdTB89r7Ybjt2TR0Vz0OLwORTUg7HsRs8WCNuj3tHuhIdb8Sl/XBue' + 'i3KRv8E+eRcyUDnyM/YFMkvFA== sig=ekG51XRwbjU+AGVBshsXoPtCuWX2RZ0OOeZ/J5yKCUwo7Px0VM9UN8j0P1/kVd1Tnf3a' + 'vRzPepRkRgrKGrTxCQ== e=found last=9 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgRp52AFYgvlP1JbkHz7p9N2qgcnlwZxEnPWZ/KaI9eI= priv=MC4CAQAwBQYDK2VwBCIEICvx6H2vp3' + 'hPWxGqnyIkXh8zsAJc8Joo4na+HNL6P8ex msg=JDVF4bKKKwb98m2gTJXDRKamziYwXX0PUZOuzjitk2zqQvzGrL9b9Wf1nZ/+g' + '5vbSy9CQtSy9nuJ7AWLILI8NQ== sig=Et5DMmrTGzxU5STwmmnVNBT3fBIsngzwnrh5QU+KChbQf2HdaVKEsgd4EvoNcBGhDfrY' + 'EwV5ycpMZ+PxE3YjCQ== e=found last=9 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAGr4yocDhLIrOL6Fih/BfAUU+KklJrIMM3TpCnVzzgWE= priv=MC4CAQAwBQYDK2VwBCIEILPGgkNbQR' + '0X9wWDolosXqSmu/jd8bH+fPDfoDPGaLo6 msg=3jrxs8aCQ1tBHRf3BYOiWixepKa7+N3xsf588N+gM8ZoujrbvUebmYrEleAtd' + 'lOr43swy/8MYLCkNz5GQ00axg== sig=jcwfGCuTTMn98NhLnEo0lmC9tfdp1mZpn/qa+ZgESuiEcKd/W+sWMoTnBssWFPpl5cK2' + 'zzhXa42Mo+6XqQyDDw== e=found last=9 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA5f2OsBUMpgJSBiBCud6CrDgOb8fnb377tHPMUAhpku8= priv=MC4CAQAwBQYDK2VwBCIEIPutBae7XS' + 'WWEAdKXgStcba2lAxKuj3EkZHfx1/8SDgq msg=seQGx5IulYVW6f6hBKu17sh+zWZB4QPl/yrUNOT7X7hDo6luCD9L7Oy4E6Mcg' + 'QgxG1jGrcNW61OwUrJCZ4ZRCQ== sig=ahmRLcvhyH0cJm9pMIYk8qGyjXLYDAH/KCQ4ab/K7+/CuuIP0ToudxGrS1JZ7/XDP6sQ' + 'mwZTKDAr8X1Nf1oEDA== e=found last=9 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAfxAUfihFrxF+OoD7MdELWILMrfb/AvXVQRV4/WpZpy4= priv=MC4CAQAwBQYDK2VwBCIEIGRdw1PBTN' + 'r4L0Y/ggMNyJNnzpO7S3N3jBzVE0eauyun msg=HNUTR5q7K6eXuv6GnsgsOtlH4Jpd8I6JO0Uy+gGI59l7TZFkJbFseqoU9+sUT' + '2w6TLZD2uKoIwC70VRKHhV+Ug== sig=Hj3XVCdcgrPql96WQz1pWC9+6/zZDMguskKjnatNbbe+SRhybK4jlH9Nrt1ZhcdgTvH9' + 'lKY4TQkkoTaAf7PhDQ== e=found last=9 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAzDtAtFRvYELDx1foLwQCUkNtmnUgJoejAlAntzrtpg8= priv=MC4CAQAwBQYDK2VwBCIEIGJ2eiKZBH' + 'CxD3BDtnqhjvtKmwyD11GUlDHa5zIUCLjj msg=LPUJGWzXpoaBYnZ6IpkEcLEPcEO2eqGO+0qbDIPXUZSUMdrnMhQIuOP0sNgKv' + 'E5pPd8fIdb136sseQCTxGcqqg== sig=m41sd5J7phr0zo8sA2JwvjTXvFeqKWmkEv3iGjA7jG1doexlb8tsaybfA87q304r/MbW' + 'mhnba9x9M8SmWSwYBQ== e=found last=9 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0qsVQTGTq74sXPS5OLIUecO1pxPwfL1ajdjUqZGai1I= priv=MC4CAQAwBQYDK2VwBCIEIH7sYVrj8O' + 'vzYSWFpgEWtDDblIQ0QsI+SamGDyV+4keL msg=i4JPUhxAxLpbIlHkDRQJW1aXhZPiSciUQHk07NMeiClz1GCxXTlcoNTrHDnLp' + 'zNRVgXgbKCmDycFc3Jrwx5NZA== sig=wmo7yOCWzACbwNcs4rZHP5EO1br77Qlj6FuYxa0yINgVbkzjSUrQHsXm3w4PmIfmIKfK' + 'UHn51d5o0tvdWcmRCA== e=found last=9 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnPVRZZBvdMr/6Ljg7698FsUe/AKz0S2jOwnTxRcSrY8= priv=MC4CAQAwBQYDK2VwBCIEIBG0ghMCkg' + '8xEtqJvZ3Ep6326QHMjR98csLWqfSJ5tsN msg=U7wqAnTkfLP53Xt7eMEefyXAK5ajGzaS2oqOCdhDt++kEbSCEwKSDzES2om9n' + 'cSnrfbpAcyNH3xywtap9Inm2w== sig=/pPkRkGLs5RAM9bxB58TGeYKixXg3AnPFzmrMTbecK3PmGrSMmybD8Juc3/SOMlbndGd' + 'k+NoFBWrr4ZXwxQnCg== e=found last=9 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZcVHB0GNr1ZlO/ytpOnSDIo/Cr6Mi6wg81NlOaPnzFI= priv=MC4CAQAwBQYDK2VwBCIEIAJLzZvYPn' + 'nDp4DmQ4ZNfun+5c7VdXfOT3gBKz6/LYKP msg=IFAoxlib8/GnBwJLzZvYPnnDp4DmQ4ZNfun+5c7VdXfOT3gBKz6/LYKPIzhIH' + 'D+OnsiKHjru01CnS60kqsca6Q== sig=Rfq7a2CeEmVskDOImTW22O37171rT73zgIQuOkjmfQvGmHSF0fnspAG8K5/9+rHc/HWi' + 'nOl+3UfCDrRzEm/3AA== e=found last=9 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAziXMQbqrSktGT7LW6taCzNdW7XNbuuEqNAK40Rd/NJU= priv=MC4CAQAwBQYDK2VwBCIEILKtyuK9Uy' + '3jVcMsK6/2ImFMn/6uDa5ebKPLnFdAMfbb msg=Arm1CatqrqQKhSGQiQ+4E6u/Sx2lQmzXSkcE+9zB51+EgLmognmpO0WC+7zF6' + '5FoSPeguNQJJj1g2KGZtNKyrQ== sig=5YMzgOk5WGGx5tkVNsuy8qBm0TP/X0su5eJ649NRrASrmtakL2XsyX94xzF9HY+nCLIU' + '19P8mx+w2pf3x8urCw== e=found last=9 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQ1kddGvQTMAgOjWas4On5RGX6CHYKq1Fv0Wea5cymh4= priv=MC4CAQAwBQYDK2VwBCIEICgWHAFL6s' + 'ul67ikjzCPUKXyIs2UbLBxenNYVIie4fmz msg=ajyHSaNuFPZhSm9YEfKe8ceURcsv2CgWHAFL6sul67ikjzCPUKXyIs2UbLBxe' + 'nNYVIie4fmzFyBB5/SkK02rWA== sig=RcTjC/OLHdV2Ibo0MHIpi7zsWrX4Fm3kibDwqLi0s7DZXeIQZKCJNRC9uMs8mSJVknS2' + 'ByYMnXR9VU3OKg7VCQ== e=found last=9 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPdyeZEgaGZBTsMHVZ/iuF2dm7YddC2G0M6aI9Xr1hyY= priv=MC4CAQAwBQYDK2VwBCIEICiSKpY+iV' + '1iRsSI1GNfJ9qsv/R50wCvd9qmVYA0BGt+ msg=ACdgOWUd8/aF09Eoe973ptmFo/YBU0LAaVKLj3jp2qLGh3egrIdPuH06xZY4N' + 'WmGXRqIPfdo63hiARet8hbnSQ== sig=7AV50j4LsmeSTR7fu4dyVE8DQZG/o0vIJFtfxECq42twOCkBkEe33tDdA/rflGk4P5KV' + 'gSn+Ft4acSV5rjnyBw== e=found last=9 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFwl779AGyZOuTckZiLjkFjopLrDu3RqGGGFzCwl6QoE= priv=MC4CAQAwBQYDK2VwBCIEIECssVGO8t' + '+3rbYsVzgeRAEfoyG6pOE5qrKe5KH5Ht/P msg=PCJz+NqJFFtOtAdj/3ke50Jny9/n/4IwE9/MbzaKIbnB2aNfeeK2+vHSZdTKt' + 'LnLIODU42R2ACradiIXSHmesQ== sig=8barku2yA5fI65ciRLnY123X6bLzQ5pfjYOv4r+fNjI+PNSF8CIHGT4t60c4Sn8kzxMK' + 'qPvr8q7jHTDoO9UZDQ== e=found last=9 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAux0QdGpHw7g5xdXeEP3c5F81QNgJ5lg0sGpvRl7su6w= priv=MC4CAQAwBQYDK2VwBCIEIMBlU7/jsf' + 'YSHUZczt37mf8VplawWGvjRGRoSizYNFTC msg=wGVTv+Ox9hIdRlzO3fuZ/xWmVrBYa+NEZGhKLNg0VMIdOvqggtBkBI8FHQ8IY' + 'mWRltIjayXMiLBNUIzUyTv5pQ== sig=1EhkdxeNI+UIRnuOxjMUqWaE2e21JCTG3nMKOaHOio4MFmuEaRAUzX+Izb+SxlGhGBot' + 'Ssnynt7UcUfnzzKxAQ== e=found last=10 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWgNXkDjSowfnL60s56uX4FbZVDlgCDOSFyk9iYTKvOo= priv=MC4CAQAwBQYDK2VwBCIEIEwifddis+' + 'k/GKVBNqU2wVvZOtdupq0IJ/mc6oue+wgc msg=TCJ912Kz6T8YpUE2pTbBW9k6126mrQgn+Zzqi577CBwnBPJIIjOThqnf5Ouor' + 'ZJk2BtZESWT9ERTUMwjDYTF2w== sig=2ROjbB3L3zVI/DJ919UtL2OYVRrn7S/tNv10Wx47j9n2sIfoDpasMfiR0DWaJucpD+3G' + 'NBUa7GydUlfvtlUiDg== e=found last=10 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEApIBh/FC3g4vIbMbcQWqYfj51K59JqWeofLR5b46fFpo= priv=MC4CAQAwBQYDK2VwBCIEIPWksiz5hq' + 'G6d8fYPc5rB9rcJb1pPhesvP59xFGjiix/ msg=9aSyLPmGobp3x9g9zmsH2twlvWk+F6y8/n3EUaOKLH9cyMeGoO3Z6r8URiSc5' + 'D8XpH75535z58yz9yd3d4p8gQ== sig=d2+ayYh6Y+P0gpNMac4eoAozdOucvUue4xM/8uthI+wmcF2fIIHl2j6T8xxqGaXC8T/S' + 'Jtv2wcUHKSnemIKBDA== e=found last=10 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADMWR/8jaXfLeDy9DPGZZ8nA1PkER6gZ3sdsIWs2PYO0= priv=MC4CAQAwBQYDK2VwBCIEIKsXIjNDeE' + 'upOj0wfbhVBSqjr4/gvBwK2D9lifr7+Kit msg=qxciM0N4S6k6PTB9uFUFKqOvj+C8HArYP2WJ+vv4qK1SwPdOkMcEzeuUzexl7' + 'ToCFjmJ3In2OoFgVX3kBmmgUQ== sig=RtFX/iwyi2Qi5qy3oYJflVKnYfYo7CSvfuoU7B7rkAQV74mpwRKnlt00QZQY7pfPRYSe' + 'WO6xnjVnhx1CkIOeDA== e=found last=10 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmltWbwWUy9NMvrc5ToATVFcansSKjM9zhwA0L2cXbs0= priv=MC4CAQAwBQYDK2VwBCIEICDsiD0J2R' + '2DSV4zWuruN4ShoebsIyOuCKk9a/TE9kns msg=IOyIPQnZHYNJXjNa6u43hKGh5uwjI64IqT1r9MT2Sewgw85DQNrKurEPBy/s6' + 'NKyvhyYqm/tZMeEqlkwrEFGHA== sig=YtS2X6KU/8g7T5JolSFimvm+ZfrikPci0ZpQ7n1Pmf2TJRyq8apLns3l83K6JuEYy9j5' + 'iwd1V1O3wWFRr/whDw== e=found last=10 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAxFjzJFwpBCi4vyiCldIe/wqLsdqUETPxG12bqgmFkBM= priv=MC4CAQAwBQYDK2VwBCIEIJP/WubHI4' + 'vay4+WNTEsCyQL4dfuc04ol8OrCeWALIyb msg=k/9a5scji9rLj5Y1MSwLJAvh1+5zTiiXw6sJ5YAsjJsooNj5n9Pk2Z5A1ONu6' + 'WAFSoacmqH38NQaLmrqE4+Q+w== sig=8noKM41S3mUrarvqUkJZqMEEgdD2TOy30AxT2H3Cuu8ajZI+RGZ2uLNkY0iU2uoFI9zW' + 'dB9fD4YyhCLlPOTtDg== e=found last=10 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJNZiqeKDdEN/60h8/h5VNp5MKDiaV7SpLgWqJaVY9ZI= priv=MC4CAQAwBQYDK2VwBCIEIFZG+2ZDxT' + 'Q3ep3sjprWdi7+Zktw8wM9onUWsK82W5Dp msg=Vkb7ZkPFNDd6neyOmtZ2Lv5mS3DzAz2idRawrzZbkOn2titaNOGZoQ/DHJkx9' + 'xZymr2Iu6d8mrqyl//blHgyBw== sig=qomdS3eH8RXoTU7QdwBSve3eiPMFUyHYHDl/OH0rld8MPjwc2OR6rEZBkSWe0kJwsSgK' + 'EoiXllrLVXF0iihWCA== e=found last=10 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAY4loFosEnwKOt6nByzs7UToyZaVp95nnx/ypCsaLC7A= priv=MC4CAQAwBQYDK2VwBCIEICa6sOopZX' + 'Czd6RY8Boc2lsMljiMOCY1JXa92LXjEgh5 msg=urDqKWVws3ekWPAaHNpbDJY4jDgmNSV2vdi14xIIeWMKJzpqMngVxWu7+19eW' + 'N7hVPGup8gKFHOaMCTR2j4Fjg== sig=OBBtVEIGHkDZjJ9LcN2Vv8L1CnFAS0tcgz9MP3DqAFfrACxuk5AbBwzmEr+K7P0wxu6F' + '45XqKEnxUCI6LOrWDg== e=found last=10 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAeK9TopfnLXAKfWAeucHPLjwuaOXBWTOrZpXne6RnlYI= priv=MC4CAQAwBQYDK2VwBCIEIClHNDhsdx' + 'EN3UXY6nGeEvhqWOzVLnrusNSs3HUKLixH msg=KUc0OGx3EQ3dRdjqcZ4S+GpY7NUueu6w1KzcdQouLEf6gSlD1mW/d2ukwkAZy' + 's2QwHGWGHWJBowJgs0zFsYUeA== sig=3YjGEsFc5P/Ml0cVptAQars21uZBZiDw4/dAiB3AMb7iagW3oWTIwfTsYMkdOmpupe84' + 'UzZiwMHRhfUMZKWrAA== e=found last=10 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAVJ0/i9GDUrDLGZ6k01UkPRG+MIGBGfgtPPqWNWHSJsQ= priv=MC4CAQAwBQYDK2VwBCIEIN+4iA4p/D' + '8M0s4s1PNQc3bK0ld+TI+EFKOdIBmE7ajw msg=37iIDin8PwzSzizU81BzdsrSV35Mj4QUo50gGYTtqPAu+smYjGjUz9bvxAlSZ' + 'H834FsmGJ8VKulF77YzwcqDSw== sig=EueCyMZ3Dyjmk34mzABhS5aLzfxMX0prekL8hHJo85AjAYyC6v+7VYIB8TnBWq0I8g38' + '7QlvOFC9Z2vjjph4CA== e=found last=10 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA5Ap0u1ciQAJyWF2Nq5AIgppaoh2tikn11CGXXov+pkI= priv=MC4CAQAwBQYDK2VwBCIEIHiE7at54N' + 'HRgiPom20p+8bRmwIj93XLHg7EDENNyTTJ msg=eITtq3ng0dGCI+ibbSn7xtGbAiP3dcseDsQMQ03JNMkhAl5a8B5Tzfm0R07U0' + 'VQDjD+4K+ZH6mAPpeVwxYffkQ== sig=abXqCrjr2zczXQMJI3X5aRnSfqNd2P8I/j1x60aoRHJ3ke1JAwkunAtuor3Pv1n2Bacg' + 'udSIH5CgoPedAPNYCg== e=found last=10 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmU+M8wIAbBzseJH6AocQ5ouvmZm+N5JJFH3mVEOWSYs= priv=MC4CAQAwBQYDK2VwBCIEINO0UKcc0p' + 'YvRneIxRVIO1gucLzB8ZVrJj53YD4v3TcV msg=wfGVayY+d2A+L903FRbUQjjFUyTuTxNJZatqoNdm68ojADcXOexkmSMcNwddx' + '5uv7ZghLUH/rs2GKR0E7+b0rw== sig=NXtNaKqzTcGRCJLtK5TlcDm5yN1NQ0eT/3xd2jLB9ihDtHZqyjDlkZAeBVH1VTmliV+c' + 'tsXU2k0mf6hZsLVYCw== e=found last=10 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATvalBvKSZF2CLacTUV2oqZ/tQawWM6mOoX0Qt6jobiY= priv=MC4CAQAwBQYDK2VwBCIEII8QkH7RnQ' + 'Eur4b8vWAdQjfr4ZCtJoERHA+EKwoHKWYK msg=jxCQftGdAS6vhvy9YB1CN+vhkK0mgREcD4QrCgcpZgqho/TgUxvni1x6eIjif' + 'owfmNZIeIfmJ478nY5O4h/c3A== sig=QqXC62L/1T4H7WA1xguUVOTpZ4Z14HbMZlP0cm/hpnT4ipRUr0/gwOupDWXbFSYvRVBz' + 'SUOABs9IpLK6eyALBQ== e=found last=10 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQuOdKX7NCjyAr2WfI6glAjTJkm6YFcQgOBwOe8Zfh14= priv=MC4CAQAwBQYDK2VwBCIEIAADNaVQ6z' + 'c6sPtTswdQ920MO+sQEMpWDqqVBUn+/J5t msg=mVwVzMHeeZIdvFIG4AAV0f3UQs3uFBVBRLv/Nz/TLHxrFJg4TClE5m27/xUx7' + '9U3dusnivZj1qw2/CG2aI6W5Q== sig=t7pulOHLxrwo2rN9/Xs7kpbPSxJ7ldIfK04/tTMbI21n8ilbl9CNihqfLSEB1fQMOYoV' + 'IrQRbkS7UXOBO62hBg== e=found last=10 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIGB9q0TI0EjvYJE0xmnfjLMBbNvkmZc48YvfSyD5t1M= priv=MC4CAQAwBQYDK2VwBCIEID+xjwfzzA' + 'zQgy2ZMj/dohIkP91iYaPsrY8nJQ1JVPVy msg=mXeb6WDx/ffkYl+k8ZEa3OO8EC4BU1ttg5Ffzhnd9gPBnZe0nqzcZ/frnb2ow' + 'S5HKGaPe2KtpPDGUyrwMyUiCA== sig=5Szy+T0AVwP3OReBLswQkRd7FZeZS9DirCuYusJAVQ/J5ST62EzslmZLGqNRC3TRWiNW' + 'nf1ZTegwoADqys4DCg== e=found last=10 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+5SpHKz060IU7R2fKBvb/0OSSAy+B2zcfGHF3wX+pso= priv=MC4CAQAwBQYDK2VwBCIEICa70pUdmd' + 'AeYJ377Yr4QPeQ4eq15J/TYDx7FavXkoZH msg=UKabTZtnA3+pEnpKFDFhLCKsqsU29DdyRDV9nxnDdtGOA43KIWjbrnw0GVpBb' + 'Gq5+LBf149BGO/FVmk3pmg1nQ== sig=1KkibqBXoDD7yPsPBIoo9OYAfehIxGSQeGJCHJN/BkaWwg8fvbssFV5Wvym/yhGiwzP5' + '1cW/mRPEHyWN3YzeAQ== e=found last=10 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEASWAUAIKMRli73hlFdS+SfYVaY2O2mvFjlP3QZyFFfU8= priv=MC4CAQAwBQYDK2VwBCIEIGL2Zq9uE6' + 'wbeU3mni4G9N/Jtdf5dllhHWxqGLKHNTVi msg=Yq15SxXMxPgFbL9Tp4BJ0g0ixG/iDYmuM428jb/inM9xkf9U3u89UTUAepDPz' + '7hhUCsoV4PslFuFNgm8wvvdYw== sig=vPp99xy9rXvppPm53Lzwdb9a5I/dnXWCc28Amc/+2HQ8q6LSVaGaeGyoRKu3oXRkdOeL' + 'uU8Vuo11ysF0VI3WBg== e=found last=10 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAm7GTBTu59TE3ME2yYAsuizLT8wiNzbDDhq5SSQNtceQ= priv=MC4CAQAwBQYDK2VwBCIEIM+vuHEBQv' + '1bXpNvBwKopdPRwKHtUPla1SLitwxAcoJs msg=RsmOPmrNmidRL2lxILsqaZ+D+NvVsZSDBGmDxIgKoc6mi0lPyu1jLxImnXc1X' + 'hTl4D0QQs3680MqDfA+xn/5Aw== sig=Vm4aDOpe9aeMkSzuOO1iBEA1twTVlcVG3mdnxqM75ZGTmX7ugvyhsXXZkPLEssMMR3/x' + '/q0nX/YVZ3g1lJjaCw== e=found last=10 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAILsX8HvDmkpEa+zCRZGJb/6Z3mufU1T0kq/T6rvvL44= priv=MC4CAQAwBQYDK2VwBCIEICTGgD/dVF' + '9jkigtqmX93KCnKC/bZ+yF0iu/KJXxetXg msg=7MtH1b6741JithAnkIOSn/Cr+kGWle0y8WSrrwFE7Kd7aaBK5e0tP/mCou8IW' + '5lRzoXlmZScF45r18PwRybPUg== sig=C6iHWrg7vF5CsKf39n3Y62HEkDfwhBkCmU2PF7LXETNfG2rC2sQP08R1/IxMhvcP5RXF' + '4P+j5NL6FV9zQNmnBQ== e=found last=10 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAYj8rMcj9OIWposfLgYxo2ASZ+Xeva2HCr5eVj1VexQ= priv=MC4CAQAwBQYDK2VwBCIEIJmNwAI0GH' + 'nyxlhtJ88peaatDsI0cuF4sOjvMlAL9HnH msg=SwGcJaxLsD3Xz7IZJMeY4qDGeYRNuAXiPHuz+yvLtpzyZTz9jVKM/5nmsqA5m' + 'Y3AAjQYefLGWG0nzyl5pq0Owg== sig=xVouRLawmkwNdCEe0cb1Zq1iRXe3rOaCzTt77lBjtef1ydLsBdYiSsn2qLc7YQ0P/q/n' + 'VNeQdyTfI+PEU34QDA== e=found last=10 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+y9C++IQH6G4gsmnknCaPuW7bvE2HiYeFvgxUqPjMIQ= priv=MC4CAQAwBQYDK2VwBCIEIBAyylmXg5' + 'OeHyjvCt8VhNSRuO6++hbQznxZi0cmPf/r msg=YUSSvW7TXl8W8CGSduvvuLiHi+9un6K/RqFx/FZV9B6Fyj692+k0ZgdcY5u2x' + 'RkfEvIWDXIyIaKRm5OCygPusg== sig=oTfnazs3nxm3gp9wDnDLJFTqqoSYd5OYy4MAwEz/CRauX4E/IpRdeRgjVnDowefqwR++' + 'TSXDSh9xtzficNHLDg== e=found last=10 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArSi3AXaNkRPHypxuLMR7jQHLyPVjFkqU41e42TTdLpY= priv=MC4CAQAwBQYDK2VwBCIEIJx7/cPhFQ' + '29P5Qhpt9aynj25MYwztuFbcLGaRCOfPtm msg=yjbhnHv9w+EVDb0/lCGm31rKePbkxjDO24VtwsZpEI58+2amiI5O2YYh2//rJ' + 'O2JaSNFcoLEq/K/d3jlxZWY2Q== sig=ucl+6aWvUtau019zFEx3g6yyJ8xnt81wx0QggiWgXZ/KIlzxDZfCmKSuBXWs2z+JMYAG' + 'AHXPmJs5010T6a1CCw== e=found last=10 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAafJfuFf3UIAdiv2wGIemUGa1RgbHghD4Coaxha7J/0o= priv=MC4CAQAwBQYDK2VwBCIEIOnFAzAMwl' + 'jD1XG3VNovAsm9W32DMiT5hKjtiGPkwzxV msg=1Ya3+AE9yAe28a9BL/lnP0LUEZPHJv8Bvw8TTcLduki58wCObPpiJATUvOqeB' + 'n7hZbuvg6dADLrMLY37k5bBTg== sig=1xVefKMGve0tUbqogRtn2aNoOST84SMfHUOxVyeYWGkXoWma4jnYehum6ivhpsgtHHgW' + 'KoYed3vHnyb4rFVpCA== e=found last=10 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+Az8lWI0foVFrMvOn405qBfHiTP4GgQY4MvcJIdFxE8= priv=MC4CAQAwBQYDK2VwBCIEIP07z8xGJC' + 'qh4O8ytzNgyWeMebo/EWAhAL/TuAKIeLXD msg=YMlnjHm6PxFgIQC/07gCiHi1w/o76AqYclCbNI2amK1gfkixbG3MdoCXkvrI6' + 'KrldQ/2L2M+2z67D4rgMCm/nw== sig=eqbczU5T5QJGm0en0NCwe8Ud4XbWAAcGr9tfrriZBDvwJANNnqH+QzXf5LijwIvr5Y3y' + 'sEh2jC7WMUSII17LCQ== e=found last=10 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArDuubupd4tl9bmE8sQNpZgnpMeCgFoIX0J+ejVslioM= priv=MC4CAQAwBQYDK2VwBCIEIMWWMegoyq' + 'uM3Aujl9kSBDwEqkNk8hR2Qf7zKFaOfsRW msg=Qf7zKFaOfsRWFFuAVm+mRQmvwmdXcehfRqE9DMrymyuvwjscTUFurqW7DeHQF' + 'U9ibxGXD0/99+EOOlG9xnfNPA== sig=dkcMZ8VCLTgqG0tcNlg20tp26BVq1trCnYlDaZ7szisl8Gb+7GeTxjim4B0h2mKo+HV0' + 'MzFmmogZjpOV7NmwAQ== e=found last=10 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATPZMWENxy4bN3j0V5GBhe5o3vErlzODfH1DeAuDlG9g= priv=MC4CAQAwBQYDK2VwBCIEIOO992AnIt' + '0zR6cPY0uronFjK1K6eUpX3c1COwJjnteN msg=QjXLZlFa4733YCci3TNHpw9jS6uicWMrUrp5SlfdzUI7AmOe143nUDDc0fU+n' + '19vojba2FvpOLgQhcxvt36Icg== sig=ACitAaoDGtqPrHb3HuU4ykO/rh4IPpXenkt6SqKDd0S5Iq+Vb6d59+4/HxWnLYtbznQt' + 'REfFanrNWqn7590gCQ== e=found last=10 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQPUhLTnXEAhkC9hKHNaJfv/Wv9nAmw24lQIjjQ5rOHE= priv=MC4CAQAwBQYDK2VwBCIEIMugafCUiN' + 'bLejpUJAImaRjpG+co6sNnRWhd4PqF1sSr msg=iNbLejpUJAImaRjpG+co6sNnRWhd4PqF1sSrj6zgs7li74WP55krBJlaGzlue' + 'RHeYMPK2yP/yiybAfCg36FCAw== sig=zhBZSogafjtmyLqWolxZzbWxp7/oeNbwNnAXRtXfn2c+c7rMhEYvLlVQIUHhgY4huRn7' + 'kGweMhYlIVYbFCahAw== e=found last=10 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAUFW09uQiOrka+tW+ryZ0aua+LXTEq6/S+sxHaMFag/g= priv=MC4CAQAwBQYDK2VwBCIEIJYiCRquNy' + 'pGktBXipg/okv8tnQwyT0FjVZkonl7BiTA msg=TZeIGnsnbt1vdKGeJ9yal2ZzHdouvV9cjXeN0oXieks2LnYJ4CrzyRfigRQbW' + 'vmDtQmNMI1cKVAltQgJHPo8lg== sig=Pr97Ne8m1jBD3c7yzqT8L2v5nBXsl7wIciMd2jqhQT1errMAMrNDq/dwY7R0iSwo8m7R' + 'xt0b8xcKg4N/XzdcCQ== e=found last=10 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAROg+MgPJHSzgoveOSestls49vCR2r/3saBkpgEn9VO8= priv=MC4CAQAwBQYDK2VwBCIEIMuo75YlxZ' + 'YOKFpLY3jfu/59Tv/ARKRsa+Xfhk8hP5vA msg=hdhZxzuZSDMQRMuo75YlxZYOKFpLY3jfu/59Tv/ARKRsa+Xfhk8hP5vAAsmsi' + 'GUiQ8LC4fPJNtg/vZaGLV1Iow== sig=nQrKIMq2UnXvp2Z4lR3HdaI9qhKC9bkHKMHfjtIryv+hyh6mEhEOSaqe0KisaBJFqEYD' + 'iQ93e55WwM/kKjE8Bg== e=found last=10 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEARoNeIdkOkA9PgM54OZF3zoSQsBjotQ6V6ZOrp0VhQI4= priv=MC4CAQAwBQYDK2VwBCIEIDn/sXCnlL' + '4K2AURqXGwLifOJwJEIj1V150UrmER3GCN msg=93Ej5uHxBKjSQ6/jf3r55vymFfKMElaEHE4M0F2kC7Lh1za1T7A7hkklQ0X9i' + 'AFLQhFu+M5Yb2Yk4biqXqI1UA== sig=RLiX4rIYT2L7LYDV4B+FvVoFZo1Tmsut9Ixk9NBgtG0AnxKThiGujxlKQTpJrZOLimR5' + 'IJgnAJIK9ZwdlBMKAg== e=found last=10 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAb7cP38jSmHuse9y2qKAN3M1jmrkt/pY5SuGY69YgHxg= priv=MC4CAQAwBQYDK2VwBCIEILyiaUbSHL' + 'A8pgo5r3K/AQtKg5ZiNkyDhfmiJnpuSp/5 msg=Ob64XUxkjpSXq/D9HiBOMkdcJKBlnp85jc5SoyI7dCrQvKJpRtIcsDymCjmvc' + 'r8BC0qDlmI2TIOF+aImem5Knw== sig=LLq9k5Mibc//xXErCIJEyIqv6yuTmjHQpU7CH140bkFgJ9azakRo6MPMmW7mamwJu8sq' + 'Nso/f0+PXQjtnwLtDg== e=found last=10 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbiDs2BlW89BCO8Rw+R8KsGUOZfbgieEgUFkx6BMnZkk= priv=MC4CAQAwBQYDK2VwBCIEIGcvApOm22' + '5JZail57JWb/ANSdEqpuX0h1vzkZpqrYI1 msg=kZpqrYI1nFYMc1viGHXR3uWZYLzsW2ZoiwcFB7wzMVV1IsSSzvAnt6BIVUlG9' + 'rrkqExGHhav6sZjzXmL1suc1w== sig=9PSCThVrW9FeZIv29OFUIbYWuGiYqBaplYHYCg3tDvaJKxlYxtHyeFt2u5RjpdfgU091' + 'nrCJIiGNgULD3QX4Cw== e=found last=10 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACPCRdUS7vBIKCcEZFG+lyHsf0oZUzVRLmYDjnDPWxCY= priv=MC4CAQAwBQYDK2VwBCIEIFKCfS19Wv' + 'mB/x1/bB0O03Ry3a4IdT7tRNtNuZ1xZMNo msg=81KCfS19WvmB/x1/bB0O03Ry3a4IdT7tRNtNuZ1xZMNo+8M/8qLjqCMAJ/tLL' + 'l3ISCjXdbov+ngnyhYJLROAsw== sig=V23UC+oUz1xFiTztfGu9tXacSe+oNnkuLOJRD9IBi9jVogBge8lNCKYZXbWfyDQpa00E' + 'a85gkB+W9CmLd7AqCQ== e=found last=10 s=32 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAse/oyjWhBgVL+c1yfW2tgy6Mze4Od0/aj55BYZdHUN0= priv=MC4CAQAwBQYDK2VwBCIEIAMduO8bTP' + 'zENp/2pnZCkr3G9ZgK5GZtCfc6BGiQ4/+V msg=Np/2pnZCkr3G9ZgK5GZtCfc6BGiQ4/+VXFQMMsczc3iVqIe/sMlvWlDoue0vs' + 'k7Ls4wVUa42pQmEV9Hpb/8F2w== sig=6jw80bqyRFMoYbowyc0arSLGsu/8gXHUd7ULY9yATnw/R1Ezc51dcfz21OvADewl04y5' + '7MDoURAXZMzBoIIeAQ== e=found last=10 s=33 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkwZaHK2OmEg9nDS2fEhH0jySZp4ym2ImSwA5Du59Q+w= priv=MC4CAQAwBQYDK2VwBCIEIOzUSvfCCu' + '2NwFtpyQ+o8oDewcv3HiPS2FxYFFd4HTxq msg=FK9ibFT1TlrXNr7PMuzUSvfCCu2NwFtpyQ+o8oDewcv3HiPS2FxYFFd4HTxq6' + 'sJ1qfhfQOsyPjpVVdvCadKxcw== sig=Kyx4EdP1dAB6dcLbwasd6TF0XBKhxZ1kbVfDsRlKmnvH0T/gI+4vgF3a73kTWRuM+Qb6' + '3PANpdCzWT/P9md9AA== e=found last=10 s=34 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAwoh+TTmZ0W/vI39R4Qu5ucgQeOol40imzxxmS0dsBvg= priv=MC4CAQAwBQYDK2VwBCIEIEESo2Qmvd' + '1bmkqbGOdmcci4XMBBAE+98K2/ej/IalT3 msg=QA5LdHgBTzAdzPotQrVWQZauvWhSY8G/qSITYAXm1UD+XdoHWEszcknMilcAc' + '1BzSW47IEiE5Xp3u/Tigao2Fg== sig=0tD4Ik8Eeed8LKqHMyNT3wmrjNzSmraou7CcGv1B+ApSTW31j9mmY7xWcEXNBKOkwqoI' + 'ajv3ikULOTr9VGjZAQ== e=found last=10 s=35 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0MRsfPjTQ9/Qjt5bUaW1AelU8ar9S3DLhtTdb/QgFW4= priv=MC4CAQAwBQYDK2VwBCIEIKtgQUtH+w' + '5Bmh9/mgr1FcEtS19Ln4tM2FJU0zRUwAGc msg=YS+yuwowpP/csN/nPrbVSnoqNvy5iZ/lJjkQO2pGYQ7DBh2ZPKZSOZNLn9fMo' + 'FYieHdATLoRq2BBS0f7DkGaHw== sig=h7V8/IhSHHrk2P4nsbCHdZmOUpHaRzbinVJveAlAts7sjOfXpBolKAfJW5DYaLiG3/HK' + 'pj3gWMB3XbTkxvidBQ== e=found last=10 s=36 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdltc1m9op7NtBhD8DiUDsdCo8RGgCV4RVmcsitC46U8= priv=MC4CAQAwBQYDK2VwBCIEIKT6CD15wZ' + 'vMO1muFju2iN3WSZOkyQT0D087PNtQt+BC msg=e9E2vQd22CEEukrUKlC4LKsp9oalwqjDSmCi6hnQ4Rp/sseR53uqC9Xss6T6C' + 'D15wZvMO1muFju2iN3WSZOkyQ== sig=D8pu6y/fMXMYz6+i/ZYGPrWAs40DnpqdYyDujGsfSWuG7TP8vlF8nf6GUBkL4nDO6nGF' + '74L0hZBaQA/vyPgYDw== e=found last=10 s=37 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAdeI8N23lQz1JHFWuHlMu2GH5A+nsi1pfC4BzcoOKthE= priv=MC4CAQAwBQYDK2VwBCIEIMeqNXRbTa' + '4jZu4sPrm62eyaOn5y5GJJqoCWEDZ9Y06E msg=NKwyR4W+NyOf/kYKN6Ki2qOyTPGZJoFsk84W0d9EFXrtKcPVlEFwB8eqNXRbT' + 'a4jZu4sPrm62eyaOn5y5GJJqg== sig=uhYo0QnNZE+cComfoBlD1WYku+2nl3GiK+OyzVinqTi4r2gXhf4QZXv6ZIROnui421Lb' + 'vvC9vfK9FZeFGSlCCw== e=found last=10 s=39 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAoSq5eyTr3kNT10mvJ8S8UjQENSz6znEUUuxKhFYIwhg= priv=MC4CAQAwBQYDK2VwBCIEINsTYnADtH' + 'minjp0FIROWN3+DRDFsSwqy0R0bAYn4WSV msg=2xNicAO0eaKeOnQUhE5Y3f4NEMWxLCrLRHRsBifhZJWa+3DvRrE2LxlGeH4zJ' + 'z6aBoUrM8YpuBQjmwmfIwHcng== sig=ew5TDV1D0vOTHBQ6nqzFKx5HpfS2ae5KTBShicFOpvBmJ+s1EoKPfCx/mqna5oJ2NkPI' + 'Io6O9eUuL9orKZOjAA== e=found last=11 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAG8ouSZ/7LXBd477vksld8WNz7O34o8LMfmHs6YCGlWY= priv=MC4CAQAwBQYDK2VwBCIEIAUHG39Aah' + 'FE6/B2O66aj6GN+AdvQyOX0OQLuGuBjIYT msg=BQcbf0BqEUTr8HY7rpqPoY34B29DI5fQ5Au4a4GMhhNl8Jku0MC4gKtMDShA9' + 'xezAP0nYMh5ZND+BzBbNAYLaQ== sig=U01DDCVp/O+KykUarWq/AF7H7yX1vD9eE2J3Cz7t/JbY6N6qlo8qpsA30XruKsNG0jtJ' + 'mPYwoO67Cx9VoN6VCw== e=found last=11 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATVN/R772H5+b5RCqt92zoia7L8LdurZWfibBqYr8EGQ= priv=MC4CAQAwBQYDK2VwBCIEIFFudG0a4m' + 'jFJEcuam66BYt0sFfuTW+SZrQs5zxffjfK msg=UW50bRriaMUkRy5qbroFi3SwV+5Nb5JmtCznPF9+N8qLCnVwnv1SltFGMMrBm' + 'VjKyGnjdd9HlwPdgqZpF6Bn3Q== sig=l4UAUFVDlhgaEMc17gjBB0fMQyBFd4ugn4EdnJU+GgdTLx5NpczzfEElp0aCwf7EUkOu' + 'vsZIp0DyixDEISBsCg== e=found last=11 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAkXdJvwjG9+/ouQK0IPda5Hq3nyEEzOjv02ze29YslRk= priv=MC4CAQAwBQYDK2VwBCIEIPkpRkgG/W' + '55sMwGhgwbxNsQvKv2Of4eC1bMDDKhnCrQ msg=+SlGSAb9bnmwzAaGDBvE2xC8q/Y5/h4LVswMMqGcKtA/v4CE5QK5GyPT/WSgF' + 'k7M7GZlB2kLC+jXb8VsFvJaeg== sig=zUT0b6oc3zJ7IWmLQAcZ9LpAQB2fJbu0NKrvRp1DrRKOIAi1VylDMGewRiPeROsVxb2E' + 'WP7VvoAz9aROrtiADg== e=found last=11 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAybXDhjS9ylJE4HEuNYFKNEd+7FTGiKBiPCWQV05RfFc= priv=MC4CAQAwBQYDK2VwBCIEIPAXRyRhyU' + '9iV98v9Q428MhmJNHo81ltiSYE7/t7QHIP msg=8BdHJGHJT2JX3y/1DjbwyGYk0ejzWW2JJgTv+3tAcg9sKl0iu43U6oPFR1o3B' + 'LKSiY8ERc3dPKI6R4X195f1mQ== sig=0HFf2XBrhN8h3Ad4IVLcMa4fvAV/G/yh8fOk/b+Ut/4r2Kf5yoNMO3Yq54wcZhCHwMFn' + '1F45g0OKgP6WvT6gBQ== e=found last=11 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtlgoIJTiEHXEFqsCbv+4Pq7mW3dBQ5O8rGm0aLl1K5w= priv=MC4CAQAwBQYDK2VwBCIEIFwzt/Xw0h' + 'tkuU5LDU3zMe0Ktdgae/YFVUn2QN+COZZt msg=XDO39fDSG2S5TksNTfMx7Qq12Bp79gVVSfZA34I5lm0OV8PPWge4GRkJxVe28' + 'psMgzylwVFdrTrwCbPUh6KGhg== sig=63o6rO0IC6ZZHk6YGuVxRNHbbBIi+NJlmFwF92EmuBVNBD2fLqgg1XiiMJNH1NIiIroz' + 'jGxEtFFKGqYWVEZXCw== e=found last=11 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArpLBMZr27tq6N2iuzMmbwo8p6ZiyKVBmwNMkSjG6UKE= priv=MC4CAQAwBQYDK2VwBCIEICAsKvlbR6' + 'xdXkRbJpyLIc2C8QV0V+NrmbAU/GIdGD47 msg=ICwq+VtHrF1eRFsmnIshzYLxBXRX42uZsBT8Yh0YPjsYOBX5cEfHrDqxCH0q6' + 'x4Zj8+y9m3HsrIYv3k1bq7ufA== sig=y4L6Gxi5pYCHP00NPzrHzQHq1kuJ/BfBpU/Eo6wGUlYtu3HAEsRm6+UnBvpfmX5Le5dp' + 'P6uoG0j+TUhJRtQmCg== e=found last=11 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEyNgScytZXWE3yAm1SKkQFT6oMNgu/E0XVOcQc00Ius= priv=MC4CAQAwBQYDK2VwBCIEIGaTwqRXSZ' + 'eUQ/qLVdVe16CeQm54z1Df1ABcUkjewGj1 msg=ZpPCpFdJl5RD+otV1V7XoJ5CbnjPUN/UAFxSSN7AaPWh02lTBbsz+90sYhgjj' + 'MZrxRSRJ/8NmFqQddRoEx+5OA== sig=M+KIPUx+EjpECrnDU2OKdW1AQ4yDlB9qBW9ALkT7OKy3lPR2+sBbMs9zfrflYTxrsN9Q' + 'rjus2eB/awP2NSRlAA== e=found last=11 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAUiyyLDOCa6aUArMAy6TKqdJdzDYlggws+LnnlsBNrT8= priv=MC4CAQAwBQYDK2VwBCIEICz8N7IJRl' + 'VnMxTgr699zMN9Ks31VBZYUl5WcR/xyd2i msg=LPw3sglGVWczFOCvr33Mw30qzfVUFlhSXlZxH/HJ3aLnmwcUFAoWnG2X/7BNs' + '9z21WlAItGymU3nBwXppkfj5A== sig=iGY+nwLPTugNSmXZ8V90lYpk5G0XmwIIoXPUx/JV4QzKAEBqPAd6uuKkfOC18m0uZhr3' + '9DtGKe9P7QFSaJruDA== e=found last=11 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9h3cR6GgOeBHPwO6GhNlNt3oU4waGPj9Ozn5cBbuTos= priv=MC4CAQAwBQYDK2VwBCIEIE9mJqmbek' + 'qUYYCnej3iN3+a7W55FNVHusnUj5J5V8SK msg=SpRhgKd6PeI3f5rtbnkU1Ue6ydSPknlXxIoM8mAbtmlRSaKRSk4+ISWVnd3sc' + 'r+ogvgOWczoO0cDsTqU/JX5lQ== sig=+VNdt6OVsHTK5D30g43x0THTxdGu8jRhDkV7BDcduiIWAG++OSEZHZqcrj3J3rccXxaG' + 'evgRxurrnACu8gsdDg== e=found last=11 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAekDfJ151h101IOHeVIIUsyp1nkvOiMeETLeDvjnpZGQ= priv=MC4CAQAwBQYDK2VwBCIEIMXrLC7CAq' + 'ujkB+DOKI5R2J75PgYMoiBnhDd+0RtHsOg msg=6ywuwgKro5AfgziiOUdie+T4GDKIgZ4Q3ftEbR7DoAIgAN367PQG8/AANNj/z' + 'bcnMi3+o1iOggV1m4WoslFOiw== sig=GFaUx4NVaoFMcSJeq8lA7O62sej6mt17IvFeJFFu+rkHYSJiu1uIFUb8ZvUVNI9VVMwK' + 'afHN/fCPqkEuii/SBw== e=found last=11 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAh9eF8gqEt4dJhSp8C+ne2HUem0ByZ1WtNZnPhgQgHYI= priv=MC4CAQAwBQYDK2VwBCIEIAqIB+LxnW' + 'uRud3/yKYu73FccOfitzXGD424UUQcMJX9 msg=iAfi8Z1rkbnd/8imLu9xXHDn4rc1xg+NuFFEHDCV/STnirQt8nC3Zho+rzSXT' + 'PYSuuwiOHcThJJC5iHGPlwZ2w== sig=djvx16+IdOSICTW+Nhd706C/4uPQh/5RxqzRznIfQasmJgT6FrNqEpCU80g+hgi2XBve' + 'cKRV9m0IYVGA8n71BQ== e=found last=11 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPwoBU9rvqnFRD3bketRJkhV4Rc/UGL6D1Jm4Uxubp0I= priv=MC4CAQAwBQYDK2VwBCIEIM0k4HL0tS' + 'KZvOMYAIPjvEbB8hmTGkuo83P43LLFDisM msg=9LUimbzjGACD47xGwfIZkxpLqPNz+NyyxQ4rDIx2ntyWwTzisexjYT2IaZ13M' + 'dToCEeVASM9CnJWOkvtmKxg2w== sig=ho9rVh8N2K+fwzTZT5BWWBldIWiPy4Fyd4KHSCgIzwwhd58znOcfR4bcFLBpeuEEZyYf' + '7HiUKBjtqsKTZR9dBQ== e=found last=11 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnUmMTktlHnLOtCHmBBAYBVQYAQJECvh/s4qZbamEMZo= priv=MC4CAQAwBQYDK2VwBCIEIDdtgt5jo+' + 'RBro+kMfnLamZNAazOdITGnCL8mC0FuLZC msg=amZNAazOdITGnCL8mC0FuLZCuFWUwQIGkWtCkUvEN+5PNqTSkEwxfNKZZr3B5' + 'h9GBYjc6nCKsNug0ceFU+UnLQ== sig=DlnNapUlYuoP2ySm566/RwLLYH6rH29ClxEpbwPrAdvpQsBhIm5Q0HKSqFf9zp6sYk7E' + 'DswvTElFf+qKtqdsBg== e=found last=11 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAzZ0wrpc1Rh/wn+bG37ljxfzOylYxVfb+mNwGvIuee0A= priv=MC4CAQAwBQYDK2VwBCIEIFoaA2LX23' + '6KL3Ab1egfNwzyRqZoEb62BjuY5evuczgh msg=1aKLUwPV4jL/EZgNumZWIj8ey7bLJksH06wR5tmyVZ6FDeO8Vguy9T3+Najr0' + 'I2fQ9OjbYrvm2bHJ//FcdkfnQ== sig=iIa1t15nICpNfljsAP43K+ATS+BLB4Nrnf2mWGeHp5dyogQHEQvVRY2G/vkoT8ci5aL/' + 'ldMey/HwmdV4HshVCg== e=found last=11 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAjVD0t5J7h05f7qpmuUtzUcRb+1ZHZkqg5NSmBJOp9es= priv=MC4CAQAwBQYDK2VwBCIEIHdPLmH/Om' + 'XzuoJKNGzQ0qoc5AsDzeUzx2ZFOLCdSfx8 msg=zcGrRrFcKhv5p/PEnl9n5RURELmch3kiPt0qRG890RhBMwJA0lj7ctd/+npyc' + 'rCtNwVQBaekZIVff7gh1i37Yw== sig=z6py/Ekwei4Szwy4X2Pr4g6xeO1GFQcqWaWBCtabpCiLdex61bsGKvcRMqDEmd2axhXE' + 'BKeUSzP7VYmfl3MBBg== e=found last=11 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+UnkRLiO6mCYkOg29FC8Y+fstbGixc1z/DEiORk1iPo= priv=MC4CAQAwBQYDK2VwBCIEIPpB7mgU5K' + 'W/g4WhYxwgRBis55SPlLzaQtr4hawkYeEn msg=dgsErb/pkob0I858BB4+u/9nKcxkYZLBv35zuewmcb+dgM5mV4JRPfYuR8Dwg' + 'w/Ju/unJXHeTaTcApuQeZs3jw== sig=TTSlRKM9GkvLKCd7vP2aISg14qpWwp1lLInkdGou8SlMsOZ5fHK5s5mjz2KKjrbp6hOq' + 'xOgv+tJNAckoTF3cBA== e=found last=11 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3O751fpTvUdJiuGzgJnHv5HbxXOzTezoNt2Zf1QaLXE= priv=MC4CAQAwBQYDK2VwBCIEIDSThXFq/T' + '+8SRIRLXHvwTm6CFxbbw2cCLFp72/jcRkB msg=EkYObxsmAE21sR9FcUvWbbiSzLSDY2CX4Edgv1IHQR6TkRTdJbNp917t7U9u9' + 'yrOu2iVJ2gYvbRmbeOHGYqDRA== sig=1F57+WnGPg8bn/Nwdi/Aqg8yz63KprZANXNnQE/nLllq8r8ZGur5le4U2dqitTXlh8Be' + 'RSZmmGfS1AmKekKXCg== e=found last=11 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZgPxEH2OFraGzJHQSRqrB+Z2B4DDH49WZWIvKgN1xIc= priv=MC4CAQAwBQYDK2VwBCIEIHu6hSeLgd' + 'xcOUybeWYSGP0sN6r6pNbMahEDIiwmdsQK msg=z/IVdKxi/OKt0AKnYHnutvQY3D7GPbvwEkA8qa4qxcD15AtyJCDDoJJuBOp6B' + 'WQxBIMJ9bXaJw+uJ37NQvYKYw== sig=MmIWIkV2bCaGWhziu7PAG8916RTwJZ5R56JbKs0FcOKVcdifBSpqPzLa9E2T6fGwiMVV' + 'NUtcbU/FpQVD2cdNAA== e=found last=11 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA4dAi5LjLYRviuHV/ilGciPpgDl4/farIkRc8XfOXUqU= priv=MC4CAQAwBQYDK2VwBCIEIP4F8J8OqW' + 'YQONbwAu182uM1Uv7flCDeCGihZmK4vqOA msg=/t+UIN4IaKFmYri+o4CjZm7aL3ZEMb2GN5+rw/a+bfOFA+RoObwTYpKJc0qFa' + 'ax+pKs6kds36W3kO0Q+EuOrcg== sig=ScpLcq/EPOlWlxTRg8uwP6m9qjilJ+UVT8NUgGntkfwf8HuQf3h75eW8O/DBAZB3oklY' + 'QPwTEQDcY3HmrNajDA== e=found last=11 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAtnc7NRxJV6cS875kTBFdu4AVfevq+HknCH/EoyFKR8A= priv=MC4CAQAwBQYDK2VwBCIEINbjDYqnOo' + 'Gt+iSJ+9vGUK0NkUJnlnO9T6HGuMZsFHm8 msg=iqc6ga36JIn728ZQrQ2RQmeWc71Poca4xmwUebzSpsWCmWOaerIoj4mpabxDu' + 'I6CLRU6gvlh8KSphkOrZ9+clA== sig=omn925A+YRgJxKTXPie5/UjOmg577a0P58+RvHF+NesBoJMNlQPf8MykYsbvOxEkS5SJ' + 'P80LNi8kAiBwJAgnBQ== e=found last=11 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/bCnD2Tqy9Z3HwubsdZg0H/JtQW9w9j3nzLPIKnUDTw= priv=MC4CAQAwBQYDK2VwBCIEINlYQ5b7yY' + 'kV0eirvZGwrmnuWRwItm7SDrRTvRrGKwh6 msg=3iWqTdaOjX2Emxt7M+OCdvAUaNA+0fv+bCfqHz7Thx9oKz55FR7ZWEOW+8mJF' + 'dHoq72RsK5p7lkcCLZu0g60Uw== sig=cvEmBdhhhIAyScYJPCqqSj2kYlb24wkNsZ6pIdRdno2ip0W9L+Yy8sClU3YJ5yk19VHO' + 'Lpxdqbo1yOKNw4MXCg== e=found last=11 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWFGYwbHXRSznEe7vN16FleGLCHJbjvTlk2nRbUWnc/w= priv=MC4CAQAwBQYDK2VwBCIEIKmvzQrLIs' + 'qONgH5uDEQ4DXDSYHeB56HJCEkFBvo4yyq msg=jjYB+bgxEOA1w0mB3geehyQhJBQb6OMsqh7LQx8u69S9fCb84qsuIGxLqsFYF' + 'wA2nTDIZ2Rz5op+KOFxW7+kHQ== sig=FyiQBjc2GY9nfs7+gtG4zDQJ/hSAEO3Xnx4HUeXL8aEYCxLk2nrniv4jVbHpFEqRLTkD' + 'xBXyR1lS1xlE1EcyDw== e=found last=11 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAyNWW08XJQMJGTef4U1M2+zx2JMQdhq+xZW2C66x+IjE= priv=MC4CAQAwBQYDK2VwBCIEIHtvlg87C4' + 'BX14EeAk1qfzHo9v3a/tfN2YIrX2+aG+ah msg=XEa1ENZ6cJhCk5xgKDtQu6TEjWq/mLx9PE1pzO3IFS919CUYykR7b5YPOwuAV' + '9eBHgJNan8x6Pb92v7XzdmCKw== sig=2p5VoCmw6ZmBudLjk0/Nw6+l1fZVby1iAYA29VADydzUIU2HLGJ5SVM7HRh2MtHPqgsP' + '13PB2M3zEg2levddDg== e=found last=11 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhNOHVVOwBqIVamb7kpzXdegsl87Lbul5RkLE0VTDdxc= priv=MC4CAQAwBQYDK2VwBCIEIOPwNqbdQR' + 'n9DUpdePXAOW/vBuvww6t720kHiR4TG+KL msg=O8O5pYstV/sm/v9LuIeLjmhcifx2OVgplpa2JCOibPrR/CEC7F7FS3Fjr2Asg' + 'xC8iGFCrKYY6+nU1SldbwkaNg== sig=rJgoIz/UAkCya1UmmAjxdishO3wXLK5UouETTPeBJCPfkzJKDF9ie8F0mfE1EO59wZnc' + 'cyV58nLDlzI90J3yBA== e=found last=11 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmSTudAe6IzmxoKH1xXihjHBowtSwV9HC6+uyHBo9MRk= priv=MC4CAQAwBQYDK2VwBCIEINCL+VZRPh' + 'DCxyJTGugiiDGmvKGD9PVS3m48kzWAJe+k msg=XqYc2NelX0+SioPpz15yQqG9n+BCFH8HVaaO3Qer9NYHNKhGC+IMDUNxOWDpB' + 'bQYMII7FKWpzaADSDF6EuowQg== sig=6oZds8eNc5hvJcygOBwedkTTExxAQyfowdCX6x1HU3saFtiz7TVQdAOZEudZtJZ/tzrC' + 'W4LV2Tles75EvWXGBA== e=found last=11 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0amF9189i17uQrNevhFwqfefjMnHfVmC0x2WiD8QW8I= priv=MC4CAQAwBQYDK2VwBCIEIAOm+WPRCQ' + 'g39hauQFciuq84e16q4R8zRqQLI2JNUL6C msg=N/YWrkBXIrqvOHtequEfM0akCyNiTVC+glrgWVGgAnaTuNruB4qmkD4aBtrJ1' + 'nq3qlX0oRTmwe7PTHHkFHhv7A== sig=YxbpDE/siX3BVJDXDHhxsHB/ndVfsDpr0dXFS8FiJXG0B+7gl8cgoQIBncRhFpQzDWLQ' + 'heUnljOoCv8+uiHsAA== e=found last=11 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAaoBumcp0+MUKaNa69BT7YfHJxpc+VFl7zbnkBG3glfg= priv=MC4CAQAwBQYDK2VwBCIEIF7UKbwTT2' + '1uGsjKQzrqbCNTkBZoQggLESvu8jfQgxQH msg=0yvgsQGuzmNH+pAhubmZ5AO/nTifjRuM1YAQ7L3jG8VphI9aLiEgAwA1s2Amo' + 'RSAiS6vfqgOk53sgbt2j/g6wA== sig=FAYCAJ5XPwNvfs0UIIAfcrpkCTj9pOPVVfymtdrUnV0iwnPOAtKyogDKwBOAaHdH/a1B' + 'Aw0GRBxZmKuXCEb9DQ== e=found last=11 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEANXVau7nKQI4+48qecYoOq9RWgZOA7JLhHGpQEUAbzX8= priv=MC4CAQAwBQYDK2VwBCIEIEZ6q3O+ZD' + 'n+tC0twl5RGaCPsMgsbnSMp07qwsCp1aTy msg=Bief/lQVCRNRKoB0QVgtRnqrc75kOf60LS3CXlEZoI+wyCxudIynTurCwKnVp' + 'PIcKPVSPxZhOu9NDV3H6Xc/1w== sig=+WJlMSlsHmo+i815rJh279DnNbfBX0Bj5ToCnX6mRHut+aN1+7ZLeluTnz0wzUSmlsHT' + 'RMu4Ioj0Fbov39pBCg== e=found last=11 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6Pc8LJjYWd4oDgeDSiolugltO/sycCPKuYe39lDZYFA= priv=MC4CAQAwBQYDK2VwBCIEIC1CxoLtSx' + 'tiDed5Ex4MOkhYt27AB8Wlwdh/R3ZQaGrq msg=Gcehmvuagq6skF4CWY5fxCFIXvZy3S1cGB5Y+C4681pFVMo435FpZmAA2uh6L' + 'ULGgu1LG2IN53kTHgw6SFi3bg== sig=xgBcaisQf6y6u3RUqV+GCMsvynKJjlD4NXQ71Hl+L1/pPbo5glAZPFVfpRf/RxoCBMb2' + 'mB9lPvIBtEfQaWTOAw== e=found last=11 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbWlMb1kKZlhWEzW8Rp+7h5a2w9qZM8JJ1pozkYlM2lc= priv=MC4CAQAwBQYDK2VwBCIEIA3yeiFQ0h' + 'fcl1ucAmRW7nNP871skASyaAAw2+hp46cc msg=5Wa8dKWfwLacthSEoM3q9ypM5KcYDnNR5aVy0JM7HGu6ULsdSaH7PmXKnvAT4' + 'kRifvdFY9Etl4ROBaY3yHyo+g== sig=IrJVF+m3Swu8uSOaXBwkTU49WpQl9MdLw1krsyqntb5t+DFOCzmK7gWRz0uKcn2SB1Ga' + 'oGghpGltKzSbM5tlDg== e=found last=11 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAQ6og6ibUfeDsHoCfnyxQL9VNmnwU4S/Thze+etLtW+4= priv=MC4CAQAwBQYDK2VwBCIEIBI0ZcChMz' + 'wKN8f+S/ORLCS8yePgYBNERpmtTzCXRk1u msg=4IxkZhI0ZcChMzwKN8f+S/ORLCS8yePgYBNERpmtTzCXRk1uBDhdUwk+9/xPV' + 'J6s6wkEU+c5aA5NJa3tCC6VGw== sig=m9uJT6+TnsEBXLSmYNWl6NzpFJCeuXCfjnctEOxGCI6Tg6XzQ3Z2Ve9TL5sJ6gtMev3j' + 'ecsgqbSEDw3iKy3KDg== e=found last=11 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWgKwgnXq1RaYHW78WVP01ONNZkpt1G1hR1Wkwqh6v7w= priv=MC4CAQAwBQYDK2VwBCIEIFOOa5s72W' + 'xs5uBYlf0y4BaK0e2bn+Ijvr6ac9YwwJtE msg=Wle5cMJ8+QFXDr5vGfzggY7QHCz+Wy7HjSF4DT27QV1tkQ8va3jJxG3Ms90l/' + 'q6RgVvLJRcTRyxp5Cdhkj+qpw== sig=OBAJNPuoo68Z4/YXoweoLBFDtOcjU0KCoFBUW9xRpNzzNmzrWWRGDJCrMOEPyeQamzvH' + 'T0oFcpq3YQFtVbvDDA== e=found last=11 s=32 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAfV0Am0LdqRUd3ElwIvybUcZdN968wTr79eE81BDq/w= priv=MC4CAQAwBQYDK2VwBCIEIHD/DbwqxS' + 'xlGf/eP+7ivHADN9jpdMLXiIFrX5zkVDxk msg=AzfY6XTC14iBa1+c5FQ8ZByKNy+brskAXWhm1pJrIOQfHVASrO3m570fYvE0W' + 'p2OmUCaHZ6iw0MzUc6YdLx7Rw== sig=ijvUKhNPTdWrFIGN3LV6hj/IYPSZdWJhVrMDooZ9vKzzWoex5jkChfz1OA6VdDR6mzIc' + 'clGbk0ftjIpQVZkMDA== e=found last=11 s=33 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABJZMiHwb4kWvdvMxhIKCaz9BenCp9fvQRnQ1qc9z73M= priv=MC4CAQAwBQYDK2VwBCIEIOmk4W4hft' + 'N0z4rgPDeDq6H1MUN6l2Guv3bf5+mg+o4c msg=v3bf5+mg+o4cLWzwbOgAyrXhDGDqF7m08jxNbeR/xSHQIlkegWybgJRDY/xpi' + 'QnyBAfoOW05IFBAY3tld06cmw== sig=KMHedglAtLxRfScpqaxdSaHWECytr2gidxqK7QufI8AthDt6t3TLZylTgcPWKa9fmsXQ' + 'iItiX96OtK26rXUdBw== e=found last=11 s=34 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA60FdkcuwML+kAkLJr+BaJZxK76kAkcOm4oh/hWR3RsA= priv=MC4CAQAwBQYDK2VwBCIEICwXNnW/q/' + 'bDixbXVpYWWKg+Fbs0KucdNNq6tTqP7XHk msg=K1fn5zuC3cFP2AKCE2UG2jHMAhT1FWeW/yK7VSwXNnW/q/bDixbXVpYWWKg+F' + 'bs0KucdNNq6tTqP7XHk6sK6PA== sig=2NJj+OnHsAmsLZzhPA5UZkGMlzsxgYz6ij/5pCtnGHWKCJGEEBnYXcOI26eJT9xBnc8g' + 'ddvzcGy0AxPo2VvXDw== e=found last=11 s=35 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEALLAr1oDBMARd+cii5ZLJgijoCdsXWJHVFBsv/ymgDgw= priv=MC4CAQAwBQYDK2VwBCIEIGBasUJNh8' + 'Th7XmbHyvfYD0QJvuOYtkmRpngq+FFzhPH msg=Rpngq+FFzhPHcXbGnZvFuJXxryp6h3cOl1+KRcoxDSu+84Zk537f+V7h8yG2b' + 'lLjBX2t45ErAX7Bq5MKIr2+Cg== sig=dJGvqvqcxNCoGBsGQRIbxUn/dJfx8IMqSr70U7/mi549YlTWZ9YYdtxHQnZCLac877oY' + 'TWjcWi59Vnp4Rlm9Bw== e=found last=11 s=36 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOkdW1aB9tgks54LksoKsyHAuwlVXT1GLwRS0HnyzWbc= priv=MC4CAQAwBQYDK2VwBCIEIEaTAyMV8J' + 'dL/Zks+mL7lDGeP/wlRxVlQYLcRJvhph4f msg=X+Ior7wfvZQ+RLh/StMsASaDCBPrJDeYKwtCc9sAESKGEqgrSnCHLkHYPB+qP' + 'HNnmoXQe62ZrBZXkdRSRzUG4g== sig=kFB+cBqjj/5H9BO9pc09ObKxJZdI/mnI3JgoRZtjxxIxy1Q80D5l/+mfyr+usg2AfFKi' + 'R3MCnKABW4B4+b9BCg== e=found last=11 s=37 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhBchleYYWoAyyhGIm0FKB/q9M436EBJ6BzhJrNcPM9o= priv=MC4CAQAwBQYDK2VwBCIEIIwYLRv6JM' + 'AxZV3nzenDVpvm1iOkvdYkgS/N6bpj88In msg=jBgtG/okwDFlXefN6cNWm+bWI6S91iSBL83pumPzwiei6305MYmem8cef11wB' + 'Rr1V4wLlsdix7A4ohr94oILUw== sig=O78Hq5sTrpnPx8c4H0MkI1OURPHdxYJrcgt4n9ZVHXqJVq3wCet6jGvAjpIrl5TvcQvh' + 'b/NnKviLJj7yZaxmAw== e=found last=12 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEcQrUuN0I1WbgDMUBRIBnZEoNJnYj5U4UqdwkliQtG8= priv=MC4CAQAwBQYDK2VwBCIEIHrlVodxJe' + 'c3pdyUjd48lFBC5+WsK8DaBaOn+UhAR16/ msg=euVWh3El5zel3JSN3jyUUELn5awrwNoFo6f5SEBHXr9iHtb1Uz3gdfhIUXw4r' + 'vY1w9c40IbwwkFB5HIIdRVfdA== sig=kIEQN/VqhvCkty51hBsKf67PeQ+NZw0khDs22tPxQ1jd/m/KAbXyxbgK/41klKHfwgsx' + '81szOTY+V4je8WSsBQ== e=found last=12 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAk7DIk4PsGRyTxWrPGGv7yD7ok7qKfu/WoSWo1x2WfG0= priv=MC4CAQAwBQYDK2VwBCIEIC3j4SFR1l' + 'tPozDesptNdjsEmbWKu1BE9+vTuR/MHDEK msg=LePhIVHWW0+jMN6ym012OwSZtYq7UET369O5H8wcMQpeID2KVDpeQqwT9WF1Y' + '3me4Ok8PtoYQ3b+jMVTz426Kg== sig=wz5zdFuwGSHdOBpV26UYeiLPdiJ2wDvgb1yuU3j9JaPOb1O1kh0SRAcjME6YFHG0143J' + 'sPs3ZEphn/ItCJ05DQ== e=found last=12 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWSYvJgbmgB/nkjElEWnl+CAOw8AyznweOjkJLTfAswc= priv=MC4CAQAwBQYDK2VwBCIEIFWcQDBPKU' + 'IWHlR+aocfPNyLuPOzIz1zNXhr+8Wp6ebi msg=VZxAME8pQhYeVH5qhx883Iu487MjPXM1eGv7xanp5uKYLd5V4IK1ClKHtGlsl' + '5eBYClqVipzpJ5aZ6HnrJ7f3w== sig=+ekAGj3xtq5AroXAWs3mhKQqW5bML0n4AyXdEoTgPM2cuVpGp8gnqUNmZbvulqDwpl+e' + 'kAroSEfvR6M338hWCg== e=found last=12 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOu8etn6e9uZVbSxD2EKFh0eso7NCIINBRogpm35w3DM= priv=MC4CAQAwBQYDK2VwBCIEIEbdXsWpw7' + 'wj2TA5YiG0WUJYKWf6pCO/gZBxwsw/9d8D msg=Rt1exanDvCPZMDliIbRZQlgpZ/qkI7+BkHHCzD/13wNOkJNvKTft0O/xnVVw0' + 'kxtkioATwozhKp/y7z/woNtIw== sig=9UgQ51bTPAmbKscCNLOllvQczuzQaHZp5apoDDmfx2oMbQfaGDLOktLVS984K00M1L6g' + 'XY8eZO+IS8Us89yOBg== e=found last=12 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcqGT6+Wv/6hE+bmJC+70T3WPFqrKnE4xnvZRNUIinOw= priv=MC4CAQAwBQYDK2VwBCIEIFwVfGiBSc' + 'ul9fYIEzhE884aCu8tpqXKFyd8utYpg7Wc msg=XBV8aIFJy6X19ggTOETzzhoK7y2mpcoXJ3y61imDtZxxjVluNk1RO29tIagJv' + '9xwlNBBFZwczIq08djSLaEDGg== sig=yY1OmgRf5o4wmPZ48bZz9OolfYQLGHGjzuHTa7vuD5jcWVeN1e7TP1GZqhNioCpn63zK' + 'NOamNEObg8QFnj8VBg== e=found last=12 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAy9wza62eZ4zfXZNz4vYULsHN7c9wGehzFkKFCuz/TeQ= priv=MC4CAQAwBQYDK2VwBCIEIGLHenWlkV' + 'rD/qwHU6Gfdiw351c9cYyqa/dn2htG0hS+ msg=Ysd6daWRWsP+rAdToZ92LDfnVz1xjKpr92faG0bSFL4erEkle1wOtx69icvCy' + 'h6Rpj+/kEKJ4Fq4HZ2OJrbcZQ== sig=VPBf+rC1j1B5CVysOjKaANAwbDuniG1jDpq6ySks5iiR7wg0QdltqxCAo8HVK6zwzyPe' + '5znbXl5BcLKDTawrDA== e=found last=12 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOwNIvU7CivMxXyYHVC7r2Gb7u/3CUwwh26GZfLGxoyY= priv=MC4CAQAwBQYDK2VwBCIEIATBJKtBM5' + 'Zuof3m/Ji52wdaEkIcH66cVjxpLeHgjgyh msg=BMEkq0Ezlm6h/eb8mLnbB1oSQhwfrpxWPGkt4eCODKFWFdJBCo6K5ac+9nKqM' + 'TCYxb7Eth30eqQn5YbYQ9hF4w== sig=8QWFQNg8/hlJS0Dw5eYYWieg7dc8EExU/6Y4N9O/7BYM5pF0IoFnN4Pl9vftvf7f+FnJ' + 'a2AECqUFqPaya/NxBQ== e=found last=12 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9TxXg58hrFBW0okBk6SM/AOSat2NVdEaCbNT4u99C2I= priv=MC4CAQAwBQYDK2VwBCIEIHUhNormCt' + 'AgBIotjC4DSIIj6A1YACzx/6aPCdthlKOT msg=dSE2iuYK0CAEii2MLgNIgiPoDVgALPH/po8J22GUo5PRP8V5sMBu6eY4NWiO6' + 'k8yhIML1BStoEPiyMF3/3wOTg== sig=+D0saXPzNR+fNhZyvp9QHK6PvGKEhMWJG1SmjyS5+s37qbyTREL0IvCz/jSYXmteMlje' + 'nKOjYHGED6aAJkjSBw== e=found last=12 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAe28d69FxILp8b6KzWlBqLnFSNoSh+4+tJWS9G1gJdqk= priv=MC4CAQAwBQYDK2VwBCIEIMPYlhtun+' + 'xbK6IQKrksHm5MgBAx+diJ+Tmp+rklFt12 msg=2JYbbp/sWyuiECq5LB5uTIAQMfnYifk5qfq5JRbddtQRD1dxVRtXSKvHIOpfd' + '4PVcubEZXIqPkIqVJ4yJ3oHew== sig=z5GqZR1OT+MqjOV5NMIKp/QJCJEJOjd5tiiO5OxyrOlTvG5vjo0wFgZRHWEnHplPXrUJ' + 'v+SyVwXX6XXHqYM+DQ== e=found last=12 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAfrpt+SIgmM1Z5H5K67km6CV1dFABDmXM3msBbebGwOA= priv=MC4CAQAwBQYDK2VwBCIEIHeMBAnhle' + 'g/ZBCtC0n3cPhyA/BD3xqz7iDUoEP3C2kU msg=jAQJ4ZXoP2QQrQtJ93D4cgPwQ98as+4g1KBD9wtpFNomkINHDXGx1iKvOZqRH' + 's/l2/ukm8OYhUl7D/d4ItXPsw== sig=nUVH2VgQsxXM74tnN3lFeT8Wo21IU8GjrvbWuKHP/0UTspeOVyojrJ7nL3xSn+Vmx35r' + 'VC3NjYnjkRGO3dVHDg== e=found last=12 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAq59eFtAit5utMnnIchLO4vkRkG9I1V+jts0cZlkftTo= priv=MC4CAQAwBQYDK2VwBCIEIIKkXym0Us' + 'hKYcdg3it3GF8yw7vYSRD2ogg7xWWlbLfE msg=tFLISmHHYN4rdxhfMsO72EkQ9qIIO8VlpWy3xE/w4+DeY9jUZbcvCwRxSrZyS' + 'bxHpc+PHBwJz5Zs/wwwGRzscQ== sig=XQ5kNnmC7EMpKVreNqCJUSSbmVU7zaylPt0mAzmvNb/Gh/gpOdlpp2sp6tGEJdqsUPJv' + 'aDEQWHpF1woPe7GSCw== e=found last=12 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEgBNZg+/F7YqUiOosIiMTPbwgbmwx+VZhA2usZJpDhM= priv=MC4CAQAwBQYDK2VwBCIEIHFwkaUhkf' + 'Syj1m139gQmHQGky8GV7APk/q82yFTkwJ/ msg=72Bx3sS+7Ih7pDxZR3GuuzuOAI6O0TwmhNDuYxVPhfWgmETQaNb+h4xCoDp4p' + 'YrS9qmldO9XG8bcOe/QvwD0Sw== sig=7Tc5PNHwNu6VClY/WWIFih69Vw70I+ey2zG2LMcMkdcDW2cI/3L2RwF8pNxZ8xId9ipc' + 'oc7rMOzJKRPKCnm0Dg== e=found last=12 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAzSEhHVTBSJXVL6ndSB9FDAG1tBG+56ytwjtn/0p+vf0= priv=MC4CAQAwBQYDK2VwBCIEILro+JmIsg' + 'F6+zQYepj/EoMndRWRqIsz5boGpz3pSVBT msg=qIsz5boGpz3pSVBTeNtvJsnx5XKpoDobajj6MWCY4ryH7Miq8EpPS1IhyPQKD' + '4S83cuMElty2S4kVQ5Oaq7ErA== sig=SpjrZbbZ3583S7CdW12BSzaeKB6hYW7ZawGoyFOevCkZuvkWwKMXt2rY2z2alk0eATZp' + 'cTfclSvnRucnokhQAg== e=found last=12 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAByp3P6JYmDM8RwYZUUkBsMPZNoWNoLx/GA2s9dY2Orw= priv=MC4CAQAwBQYDK2VwBCIEIFTkSi75F6' + 'WmBWSlhyO0gkq4WOvK8fnHtb3QdQHfQX3T msg=SE7Fz4LaIbLBRS2NaMQS88teCgS3wYhRmETMw6c44pbX0g/nQkD7BhzR0PESw' + '5oykWLfagXEBaRIA7ZIzWb0og== sig=/s9AddtqoBd/qPBNovzYGvJzSQEFKUoW0wMRylh8Zpj/yEGHQn+0l2f/D/7BQwd1NiTZ' + 'BASOhFBxS0rxkw90Bg== e=found last=12 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgzT5ODy0HNJgl8tnJ9JGy5erXVFUdZm5eEFz3TCTIDI= priv=MC4CAQAwBQYDK2VwBCIEIEeMaQ/iAk' + 'rUNVdPr9M4z2vVmySgeD+EH1zlYnsY7rLH msg=1ZskoHg/hB9c5WJ7GO6yx4R1XRbKIJnq1vN/Ag7aRw5lp47q3gjiF3PE6SmI/' + 'BUrVX5fzwwEbx3oGdER/V5+7Q== sig=D+SjvzUwbvT0TrIcFQ48rF+zJi9PBu4wh99+Y1YWiys2R6PtkO7lUsONSjKoYc0KQ2AZ' + 'OEq9nvfnhNOVLcIiAg== e=found last=12 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAADR3nXG4lYkmrSL69CfCLqknoVa+1nE7UBIHsDL4Bjc= priv=MC4CAQAwBQYDK2VwBCIEILR88F4HFp' + 'v+0XmsaI6VuHCjLIoQbXE62j32hkKZz8sv msg=vdTOyGSvc+fRE/TiBtOU1jp+YqbMTZLa23hovL7dQZ/NZ7AjaxbSSgKIPhn5G' + 'aFt/r/7Xh7GwwT+g2EPEnkBSA== sig=fNXGVjY2tsTrUKDVF2CDtTyoCGyQsBv56EZEm1ygMdhZsZVvtUO5/Xs0uLJteqsRtnnj' + 'o8iMyHjFKEMPppHICg== e=found last=12 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABEk+afzT53ubmjwwVkh6L7zfJNAJ00cdEkgQWYq2TOo= priv=MC4CAQAwBQYDK2VwBCIEIOINSYJgPp' + 'vqxiekED0J/kUhKKB7XWI0rpSccp68GjXV msg=7gtKEeOXNEalky8z2p6BqleHI5mXm7HqfDQzVqS+oOIOM1BRwodGJ7C5QMn8J' + 'eG62JZ+2JzzNlDeqbD4XIlyyw== sig=9dyEmYvZaT+iUR5AieKOlA/6186sIjIngZnkKcKoavyaWijXmx2y/ehnXUDb1ZgUIirP' + 'YQb3yfMDyLGOYAD8DA== e=found last=12 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgHPLClp52r1Cg27nDr2/nl4lIGN4YDgCQbjy8ZwjJRo= priv=MC4CAQAwBQYDK2VwBCIEIJvV4h88lZ' + 'r5bAprZE9BGLw1dFJsYlSl7gX5d0eapkNv msg=pe4F+XdHmqZDb+S/2KAR37aF2Z1E4+EGGdc7S4qDrWnWsML2Vbw470uitfR5J' + 'oHvSW11ALHBjV9friJ3rR3skA== sig=VEayAgZ74Uqkb4chpPgizbwk9KmUh8HscUy32XOKR9mhwbiKROU0Wg/MbV5MhEa/f849' + 'ScA6Pz60NcHcYP6ICQ== e=found last=12 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbcwTJkNVVVw1MqMH82GTPtdjufJimYY71qzht+5TRcs= priv=MC4CAQAwBQYDK2VwBCIEIAJTfkzWgC' + 'fLLhrL2a60QCD/jCVP42s4XlfqucSiFg/c msg=0Vav0mFrxllRRNacMq0rd6j0RMD0O0fbaGzCJHJq/h+/98zwCRV/fToJV98GR' + 'buB3MMM0fI2YMXt9wDzaqETYg== sig=Z93qLppoai0wFBSweocO/4zrv2aqXkSp6V88pNYY/gIiYdl5BUWFdf+baH9MGARviGHz' + 'NP4uAFRpIUGLzOMMAw== e=found last=12 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcsi5sXtYBZhgel6/z5+VBZBneP/uMl+t5oe3jNLnk/I= priv=MC4CAQAwBQYDK2VwBCIEIGTd0dyyKV' + 'XQ3OhQPVFCw3Idv9JGDvFvJWO0TAbTmo5B msg=Hiej/sMgdd0AQxiMHLP0+z85Tn9/Z6x2xMbZ1DyUR0VwvXN6gohA+YUwf5db2' + 'WMiI5mv/570yebqevVj7S24VA== sig=dTsEYo1DZCpb2I8ZhkDJR2vBqGY+2mM2WfDQkfKGhSoceyX8N4G5XcpuTJVQUCXBqJmW' + '84onFs3VgN/z6NybDA== e=found last=12 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPGf+KbYAETS5fKfUFQhnVqJBAq9sv0HfsGWtaaYGXTs= priv=MC4CAQAwBQYDK2VwBCIEIDFbfJVLt7' + 'WpMXf2NahwhJ7hSyMoNKQAsRC4BJ6Zbgna msg=Iyg0pACxELgEnpluCdqcT/ZqWmOJFl5L5eUV+HbSTuoRD+zMDIgH8YmmA0pT4' + 'leSQexiDHJzKM7L/jBLwL9ioA== sig=zHJjczaQAe859BkgsQ34tGtolc549PtFPxAcNyDrPczcYqw/xI+AubKDuEEWVL7fA3ut' + '7WH2z5TEovnzDRwjBA== e=found last=12 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1dNOEG9khJd9OZK4e3AtGdYDIRSm4p9ORxyyDQspyPM= priv=MC4CAQAwBQYDK2VwBCIEIKq8nuLOKG' + 'u1iSmnhvigTXDitUKKwCC4JGpTD7gt4RE+ msg=H9sTgaPIRmZyZgmyzIFEeyahDyAJ6soRv/ya+Gd/8gHkLNqFgH68d+qFxFS/K' + 'OKUVrcrrBax8oZeyJaIqrye4g== sig=vbRFaF/F3cjxpBK9UOoxU7CfW8myT9pOwpmowzrSW6Z4/jksLOgOhu8y3eS0wLI2sdiC' + 'cxNsRc+72wbRUNI8Bw== e=found last=12 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvkhg/nHmcZV7j6d5d9eBb0McxMS0tyRo/LC5Br8bwas= priv=MC4CAQAwBQYDK2VwBCIEICnSKL5JeR' + 'IT51vv9BqlyFm5rvXZDrZ8BTDs2QiZ89JY msg=7+O3b2w2hQ+B7+RbhXRd9mxZ1yZ1cnu2Qs2wQ6StWdEVZIti+5wQOBItHELsT' + 'ZjK4tfU+RlUzrV72wYWMYxStg== sig=fLLoIMZdM+ajRQM+8qliGs0GtLxeaEkMlGDUIHmIWJErTL16tSuVsuopKwFftI/7w4Mb' + '5G0ArQvgqO76rN5+AA== e=found last=12 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAaTU5RBHx3Z/+eUOiDMMFSaJVJREPtEVXEUA7Ha7h4gM= priv=MC4CAQAwBQYDK2VwBCIEIGPMtAfM8K' + 'K03jWcf59KL585gAwAaXOLT1IDqNTf5tHE msg=YFVZg7grYJIa5mdYMwhjzLQHzPCitN41nH+fSi+fOYAMAGlzi09SA6jU3+bRx' + 'PVjqSzDMFFYCmrfva+/YACA7Q== sig=x6xuhCabQsn9At8pYNPfcw+dA0wxuvwgni8HtAIQ/OQhs1IFHEKd9bSMWvId9gJi5zCL' + 'ae6hGAOGi1n0DcGqBg== e=found last=12 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAhVCxVymvqjro7LfrreMrbogkrO7/+6tfLY2rKv0KV8= priv=MC4CAQAwBQYDK2VwBCIEIBmbi1tULI' + 'QsRBcN8qXOck/LiDIZ+Q9jpQtUorKQgdmL msg=V5BzvApphT+KQ11t3mBaLMhK89ycvaNO6261twxc2Tq1KgmedEFJlRZZ0iN4G' + 'ZuLW1QshCxEFw3ypc5yT8uIMg== sig=plluH5rcyFIVKTmLA9fWRt9VN2Q67z5hJZM3SFM6vFTyPVmSLFYTmO4Dr7wrboB72mNj' + '0tKSUOSWkk4xqFyWBw== e=found last=12 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsEjQ1z4zhKB2vk7jQWqf7DG9s+hWBewTeVR9N1Xl6NY= priv=MC4CAQAwBQYDK2VwBCIEIAAGmJ/Ut4' + 'OPNydMp2yjuxG33fJV1ExBr1m8duKHrWJr msg=Qa9ZvHbih61ia8dE+tiVDZyJ12rRWB/LRfTOySyPzxFCAB7Kx2zxgMS50YPTW' + 'mwvFk/rb+NLWrsnfEsuEkGx5g== sig=XZMc00dL6taSzqUTf5yCUMaHJOCWz6VExja7fZ+ffYs/wZZSdgRuKxVNy7U67O6EkWr+' + 'yK3Zhb6ptRn0dJNfAg== e=found last=12 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAuTxaAr/GqBZSw1mb3fBm7RWgmmRWNeHo5CkVLe6HmA8= priv=MC4CAQAwBQYDK2VwBCIEIPMyou8Bz7' + 'SWN1ZUwBfomBnawXZYqyaKDlLK3eoEFg9e msg=VMAX6JgZ2sF2WKsmig5Syt3qBBYPXrvvZpYlPBb+z8anmVnnknZsC7FG6t+Do' + 'GYyorqjW0VshVnEDdAyAuadHA== sig=IbbHuYvaEyfBv3nbq7BbmdcrZsWR2L52o/FQlPymJXgus8/o38Q33oeaOPfI4diHuaxc' + 'pTRMnccDApBUFHm3Bg== e=found last=12 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA72Y4i9imNsFpihtsnEtcJZypaAfLl6FApiIE40bTRk8= priv=MC4CAQAwBQYDK2VwBCIEIGOvz9s/dT' + 'PYFrJx700S50NRx8MvyRCi8GMCQX7JBXmA msg=iM0VJrb/8SmnEQN3fo1nFq50XGmwM+bFXdSTuLmtdoDFJummQnLNNkNE+mOvz' + '9s/dTPYFrJx700S50NRx8MvyQ== sig=id/6/3Be5l+IY7xhtv+SEt94GraKV2Aq9T5piursLVlZn8HGPYQO8s2DwTJavvJefF1h' + '55UxMt5/8zOop4mFBw== e=found last=12 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAqum/xy7XEnUragS2+q0QcNUnvsc/UbmMTM13DIU2dKY= priv=MC4CAQAwBQYDK2VwBCIEIKnSOR47Lw' + '/cOdYYzU7a69iM8LrxLt9L5+iQpPpLNjFl msg=yOlCeB87KbgQ3sQFMez8ee9cg/gptu1ZGGE73WH3Ud8ZfNErHqnSOR47Lw/cO' + 'dYYzU7a69iM8LrxLt9L5+iQpA== sig=NlIdnyNCuorPuz4/BOfpBOdPzOL4xGmaVm0v1UrtU1A5+7MAp1qEx6/J8tpIr1RO+ggb' + 'EfrHAGDLleyOURgzBA== e=found last=12 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAABJBurNCsFqvffm5w7toj6kQqCz0kEdkQ6cNSPNstak= priv=MC4CAQAwBQYDK2VwBCIEIFXIeIj4Le' + 'OGufbqVLTYD9X0e1Qc/QBZDGJEr0JmOKqf msg=WRgdqBcJ/VhszmTJhtct1H9VyHiI+C3jhrn26lS02A/V9HtUHP0AWQxiRK9CZ' + 'jiqn7Njg/YLcb8qRJ4aswB+qA== sig=adfBri6DRHYJYq0D+kNrtfQksNO1gIqVSHu41BMOS5H+WtIux9Kiwmi06ug+QU2vUqYL' + 'iKUiU3tv7I5NMZdzAQ== e=found last=12 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAer+R+/MhPx+529LI7DMEwXtP0kBYZybawVuwzHHKABo= priv=MC4CAQAwBQYDK2VwBCIEIC9eTNAcJ+' + 'lfOq5WtpDxdnlqU5Ld6/nqi8QATR6dm5zC msg=b3KNI7MbQiuzGPG3iroM6FGlgsge+3iz1O3lkW5KT1JLjI+2i19UB7ugFxx6U' + 'o0RRsKIhVJXur2Ela0vXkzQHA== sig=b/8yTU8nrM+/1IQZda/oYP+0ALEn3Fv/63aoyy4mgqSyPyn28s9P9nOipM+ZlCTQG0ws' + 'FzQPR3prLLo4/ocvBQ== e=found last=12 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAxmKXakHc6laMdWGM2d5Wlpf7DwXAv6eT8oW+8XyHyTE= priv=MC4CAQAwBQYDK2VwBCIEIKMe92+O1E' + '6pgWqXWO67m51SCZiZWAmTkDvZQ4ZvXKqY msg=abjZIvKggedebpgwH6Me92+O1E6pgWqXWO67m51SCZiZWAmTkDvZQ4ZvXKqY4' + 'PtjP62H7QCCSa7W0ausMwAQFw== sig=x1Sa2Kzj5j9YFzy+kkOemFj4jjBjquzzgucvd91Am6AOrdSEHjbTEvqTfCCiBdLOQmcN' + 's7QAEIcwCqJ33odABw== e=found last=12 s=32 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOm/f4GgAU6v4HGFyuJ6utzgHd5ndu7Sj8hV09YQCZBw= priv=MC4CAQAwBQYDK2VwBCIEIIWo910mHM' + 'z5SZvJ3Pf6Ur3pDwZW6FYGWNjC41A3U1mm msg=GHOT9Z8iL2rYqWmGVH/lFvGBkMptl8o29UQDoDrdvRsL7kHXWHtRBEKXuSqJo' + 'sbXJvUTAt6VprQ1/6lpUhnMrQ== sig=/93D6vOBC2zLzpbl0qZXlU4D0/6TquAQbvWn5ev49qOSlG4Bt36Tvy2QyO2e2ykHmcuk' + 'EUm1VZdERj195SEnAw== e=found last=12 s=33 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcb5sXPPlASBpW/ktOeflrTrIXEraMSnhj/rDt+2Ef2M= priv=MC4CAQAwBQYDK2VwBCIEIDinb5Hkln' + 'HvKWaz3Bn7znaP6jCih+5oY3fSCft0Auxc msg=5y+9fCJerPKmMBOkGC8SpQQ4p2+R5JZx7ylms9wZ+852j+owoofuaGN30gn7d' + 'ALsXE8hlKhE7FeFp5RP4IIFIg== sig=1nUjYLf0yJFkL44JBF8k8vE8tKnxG8oU2JH+Caz+6jA0+dKpPYU9PAJDLjLJ1G+79K+m' + 'fWxShWDHwz5nz8AkDw== e=found last=12 s=34 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhzpqCQ7zeaVjYXCa+NfFveiVQj7REzfGfibsdxctt2M= priv=MC4CAQAwBQYDK2VwBCIEIFSI6qdw+6' + 'a0MJtnC94FDVfNhj+APexWWT6XCvuiVONL msg=hjUOxmkZLVW9EBuyqnlHgC/mTQpUiOqncPumtDCbZwveBQ1XzYY/gD3sVlk+l' + 'wr7olTjS8Yo3Ajm3xiS9D6VTQ== sig=ZguJwNwYXA3KIRvwPDZScF3tZJYpTQj6wzzdNREdR332AdUHDKfafix6WTg/OG7Hl0x8' + '/gNeiLcv4M30yXABBw== e=found last=12 s=35 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAH3h6LU59C2qd8Y/F0zM9AQvrZp1cqbh8VM5+Jo1/UTs= priv=MC4CAQAwBQYDK2VwBCIEIONC7cA0fJ' + 'PIsl479OKUBN9aLu0LNLvikx3LSMLt2eD+ msg=amhkiCvizzw7viO4dVlJj1HjQu3ANHyTyLJeO/TilATfWi7tCzS74pMdy0jC7' + 'dng/tnhFS0/HUFRc2gjdokR1Q== sig=+aYHktxTZz54KiU/6ctr+vRFKWVZb5yZWfXy7WYEgv1Lu/0nnPgyqLK3b5lQZfkHBoOl' + 'WbI6qIsqRTMCeNSTDw== e=found last=12 s=36 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAxEYCYCrM2BT1lZnfebc/HFV9Tw6Cz7zhX7ClbZ8/lYM= priv=MC4CAQAwBQYDK2VwBCIEIECinzCjAN' + 'riRACYcU6DZg5m/Qhy3Ul03mhf9umVwVyH msg=QKKfMKMA2uJEAJhxToNmDmb9CHLdSXTeaF/26ZXBXIeyy3POthp4GRu+HPoxV' + 'H9y8rghurND78l1JHdaZjEetQ== sig=xzuJQ5Uww8J934wMxDUKSs9TWCiufj0wAAXOWo9av6TQ71g5uAesto/6iYIeXZ0mogqF' + 'tu1tKDQT80ICcSwkCg== e=found last=13 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/xZ7RWNWIiCRfE8Oir/evregfQW8or6kla1hB8VM+rI= priv=MC4CAQAwBQYDK2VwBCIEIOWCNx1ah7' + 'MAPQ45lrOx6Gmj7KbTc/zbDVoDO2ARtSxI msg=5YI3HVqHswA9DjmWs7HoaaPsptNz/NsNWgM7YBG1LEiVSFizqSJd5Oy6pHWhB' + 'eDePs4JEnp2voRa1yMZKCMkiA== sig=i4f3bCYSVsrtECdShp0KjXihDT8Z4wQ3Lyo5hp571qmiumOGKb+nOpeB82DUMz355o03' + '/t4vyF6qwS/Gv9dzCw== e=found last=13 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlMQAiNvmyR4t7hSV/8Yk1hzGLKGe1SFlcPlZ0XGwP/4= priv=MC4CAQAwBQYDK2VwBCIEIL2o3zZaz7' + 'DYtCaK84BfsZTj/5YdXuuPoGyzjeZkfJcq msg=vajfNlrPsNi0JorzgF+xlOP/lh1e64+gbLON5mR8lypPaSnTsaBpTtGA4CY2S' + 'xtLPvA2Sfd2xyRPt2SMWSmYGg== sig=SZ3kgmTPczaBtp0pmX11PNGl7MMFjuFxpYN4NnVlrDKoGc0WtUsztLGBgsLWdHImzYFc' + '+g5VdUgQLXbzTUA/Dw== e=found last=13 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEVbkM3cSv4A+0GNHX6g/puvU9z3BjZ+eNxAlKb5PAGE= priv=MC4CAQAwBQYDK2VwBCIEILm1eTKsLq' + '4tbThPDxGevWkQlzSMuCrd6sgp+bkjEY6E msg=ubV5Mqwuri1tOE8PEZ69aRCXNIy4Kt3qyCn5uSMRjoQmi1YmRwyXuWPKFwe11' + 'vndjf2L4kdpxi0do3TytOGgAw== sig=1DQlx3l4ZBFa6X+ns5Pw4cp8VDpyf2m+uSPuOTjjWac2I/PWMAbI5qdnzbyd/UTakMKA' + 'cYXnrSN63PZWHGd/CA== e=found last=13 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAOwTzFOxpKywgwQ2va+9gr44x5KbQGw3Jz2KyhiWRR/U= priv=MC4CAQAwBQYDK2VwBCIEINY+999DbI' + 'dnYvL+JTJpctuWm0kxLwJ1+TeS50Z2aHk/ msg=1j7330Nsh2di8v4lMmly25abSTEvAnX5N5LnRnZoeT9UCWDbMQG8dflMfvS4p' + 'yStSi2vzTgOMqwtmVN8H9IcTw== sig=cWVDnqag+qvpzgMzNaZnO0F4nSADwN3hKyk5RxlNZ/lamejBvvrR2sH95ICvI/+RnvyM' + 'BKGYpvfV/tdipkACDQ== e=found last=13 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA4gd5Yszd4KDokGPYfYuFukOh+nv9FgpQR7jIqx1qQ14= priv=MC4CAQAwBQYDK2VwBCIEIHSw6zDMaL' + 'hsdfW0pSVqewdhi4rJm2NDDH99yEdkDtFK msg=dLDrMMxouGx19bSlJWp7B2GLismbY0MMf33IR2QO0Urv2bMpGrDsI1m6c5wyl' + 'BaxGTFomCDYKt6NzD6GTTn+gQ== sig=Y+fHprdODp1CyF2dVnB/F/xW3QKuGaG6d9fMoj88FB6eQMR2HloxQzda85324il3qqH4' + 'q423HSxpS31DhCi3BQ== e=found last=13 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvPpM0Dhs1biJjQbZASXQ0wB0sMRkdl/RfVodbo6COfA= priv=MC4CAQAwBQYDK2VwBCIEIEm46Zf7/W' + 'sIvGTTopV+gujPW1DqwWYu6D1sGZA/UzBb msg=Sbjpl/v9awi8ZNOilX6C6M9bUOrBZi7oPWwZkD9TMFsql5lhoQox4RA6m3PhF' + 'Q8VHzDnFhR8z+N+vYY9muyppA== sig=vr0YFOf3UwN3Dwuppzdi5DAf/TaV6gpM/enB8OtBQEF8yxn0SC7rqrBl2aGrXC/Y9B5O' + 'RnXWFnIPj53+I0nJAA== e=found last=13 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvnKYzsWm2JK1I153Zea8iGVslGihL9wz6xKdRnnrw0s= priv=MC4CAQAwBQYDK2VwBCIEIF5SNvBsB1' + 'DMLW44UjgvbbkKhtOfQLowxnv8RQbaqDOY msg=XlI28GwHUMwtbjhSOC9tuQqG059AujDGe/xFBtqoM5gf2/pvWMpIFa7Pa1nDo' + '7D88tI9WQg0O56Bj+5KOn7whA== sig=zakYde4sm5Ax9EUwW9Av6TfUudlinKTZdPHNpAq3S5RJh0SfJeHFgIftuL9mQyMbx6Jh' + 'm6hVzWp1wO4BVHenCg== e=found last=13 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9UvqVL90rABRd9so/FWqheyo10kOavrS5jrIl+Ua6jA= priv=MC4CAQAwBQYDK2VwBCIEIMP5+SXCoB' + '6WnQlNMyPY4o/NrVFz1PzEbPfJSElWaG9k msg=w/n5JcKgHpadCU0zI9jij82tUXPU/MRs98lISVZob2TLa8GMyE5NYoAAb+x78' + 'jRGn5HbMF42s6bCG2ZzOwdMaw== sig=0KGFd9jfHNDaphagtFlG53gg0GChlSCbv7PDEXcG8kTBlmiWbfpWlkIX9gRxh04BW3tX' + 'YJpm3c0gfF0DI/6cAA== e=found last=13 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA2UquPENIT1af5odjWP8st7YTfH8daYf5dvYmi4lECx8= priv=MC4CAQAwBQYDK2VwBCIEIIlyMwoOAr' + 'lA3lMYgHU8lkjQmSIBgz2gvu+RRMitO8cO msg=iXIzCg4CuUDeUxiAdTyWSNCZIgGDPaC+75FEyK07xw6eWXDB4OMCoMTkP3wIH' + 'j3r+81jmpX16PuIMcLwZzuzKg== sig=GPA2fdkckF+PguSYq3IjN8LSiIDSNVOl9Na3cCmhYEUzfV+4Z17O7cMzCik9NODdbf4e' + '+jnXp/ND8yvrtuFQDw== e=found last=13 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAe8AjcDAjmDSgyYZ5rGSuq0WfNtvQtS0fuy/rU6dPEig= priv=MC4CAQAwBQYDK2VwBCIEIEpeczlUbN' + 'dpwkrCnuvSuAqzjCTBqImGjH5gxXBy5cYZ msg=Sl5zOVRs12nCSsKe69K4CrOMJMGoiYaMfmDFcHLlxhnlUJE+VBRNou81BkxMm' + 'lqpm7rq/h/lHgZN4Nc/cC6k2g== sig=bFUh8WU8v38wQGGY7x0t5QLKJax2vsJwUNP/EQd6sT8MkOofg++KUFVAlT7eedfD+JTx' + 'HvtbY6RMgqlh2kn0DQ== e=found last=13 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAAn8A4IVkDUj6vltuJ4zbzyse5ZyWhwFR4fEk50bWp6c= priv=MC4CAQAwBQYDK2VwBCIEIGQwCM7NO1' + 'hoeCCU6G8nmlmNDWeE7zBIHRatCw/2lRDv msg=zs07WGh4IJTobyeaWY0NZ4TvMEgdFq0LD/aVEO9HPacc9CrPejVhzFTRmZmSY' + 'D/Dv1q3SCfyYy+rP9CE1w/CwQ== sig=XkLQwEQMQGk96CExdexXRZOiXMkS/wq5JFyOV1iB97lK+wOXvCSs0GnFebuDq3sMrjDq' + '+Kgdi+8mGuWwA0OkBw== e=found last=13 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhM12kMba1FLqBNxPSIN13nCtLrzoXJIX2eLy0U9BOLk= priv=MC4CAQAwBQYDK2VwBCIEIEl+8fCKbf' + 'RsUem7XT0BBzr2mcEs7pVyrU6pSaPLDTYP msg=9GxR6btdPQEHOvaZwSzulXKtTqlJo8sNNg/JnphvQaH9rS5n+PQiuB7l1NRfo' + 'MomDKQk+rtDC980jyadcTnPfQ== sig=/873e+8ILSEkOPI7YRBT6XvXnSjl5Dec7otrN4L6Nq324kmpwwMMOXQ9Sf+j1/oKNtC5' + 'H/oIdCS0eE5ARilcAw== e=found last=13 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAU7SxiLqEeSPKJUMsp/9f/EDv9TkCgDgCLzUE2+fvIZA= priv=MC4CAQAwBQYDK2VwBCIEIDZjlQuulF' + 'xjkiFwwrg75Y2AIRXj5QBSqN1CJqcXctA0 msg=Fk4nHHZdu+gxNCb4WRs78ld488tLMMVrkiN3Hi/eDOXypooVIxC6DLIohzz4H' + 'SYOz0cexAByHjsmwiIlpLGf4w== sig=6rta5oSjlXvl6DvIDTxLwBs4pyilz6Y64hIpsuYBVEjK3pjy3J41mxPh3nxhjaD4b7Gx' + 'ZK8g1+C/4hZnBGomDQ== e=found last=13 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlp9AdLnkZewJoVCuNAc8NGpMAHBNnUEHF0Maa67xTqc= priv=MC4CAQAwBQYDK2VwBCIEIAPJbOuybg' + 'dYeCU7CjyhhyEbFm5kaorPI8XnDOLekkdH msg=3PRTyMrpXc43GT4us7xSnyCeLB6lybE45lNukrrOd0+TqgRc7eSi0Mn43RCPr' + 'qVnM0FgpEsfkzKytTUVhSO4sw== sig=FeKSW4Vq+c4ji3GY5BERcfw5NmOgIq6o9rFie8ULUfSqeav39KEieyVVmjcLmzIfJWPy' + 'gjZfu0wzZpiXu4fkCg== e=found last=13 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA2ib11ZBxDSqktjZPs9OflN0xuxGklld7sCNDSpteLIU= priv=MC4CAQAwBQYDK2VwBCIEIOk9mgtZA6' + 'k1PP4qOLS3yiu/x4MJ/UTC55/lt+lFjAZC msg=tLfKK7/Hgwn9RMLnn+W36UWMBkI8Q03YHZLgQL7ICq503FikVx9GNpVb96a8d' + 'fwQ0kPH6aHbI4lrvhPzbHQROg== sig=mzGmwcOrMT2EhDaV00UmX1ZVv9jK8pRwMakfHvLO8qZw1uk33eYJvvgYQ9vdo9f78/ng' + '426EO6aftUHDMiCTAA== e=found last=13 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADDLUi2p8YVzNZfiFyf+wCK9zzpep8yW35qsv73/vxUQ= priv=MC4CAQAwBQYDK2VwBCIEIEYNspdQoy' + 'fk364Ji75OWh91KlmaXuC+EkZZlHVpoxOt msg=5N+uCYu+TlofdSpZml7gvhJGWZR1aaMTrW4Bnpfim8eHy9CPA/5zERJGAf48w' + 'Ol8dJRlE4a7vLfnftxB9FkbeA== sig=k0cDkkQED1wlR9so8/tgxtbkzxd+n2/xM03ah1T/WnTvJ5dD5bWw9GCBtEynEvgo2nom' + 'LQ5PurteuTKhm8mJAg== e=found last=13 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1YFuSTCj7dfWRpipN1mQbKIgoP6CWi3e13iS7YsJzSE= priv=MC4CAQAwBQYDK2VwBCIEIL7DrQ6UWN' + 'HorJ2uAYkN3UDe4swZ4a6ZumT840rLfOAR msg=vsOtDpRY0eisna4BiQ3dQN7izBnhrpm6ZPzjSst84BGQvNr37eBB5ADLLvVZt' + 'UFVLNjVkAn3/gDAFVoe+JPZhw== sig=w8D+ivrF84UBp52qgcziVgBeEroDODgLlrMi260IIMac/8c3b8LQ9mM3G08p/7M1w6V4' + '1zgqDc/xumDrTr2eBw== e=found last=13 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAwxWNN+Hs3t8vgI/FOiuNP3KooTU0trS14Zi9b+J/IG8= priv=MC4CAQAwBQYDK2VwBCIEIHIBXkSoCH' + 'dlA6GEDvmsp39vn3FgqJmSzkaoLgTMf8AZ msg=WO1f9OBLHBkUAf8heQ4K20boQTYUnMJVO3lwvOYs0G6JNSrVKcGxx3cThbgi0' + 'CQYn8vhsiqNH+f8qoZkMuUw6Q== sig=XkxeVYNvYYgb3L4CHXWn1aRoBr6FH1V/lI8P7jlZOm2GcADEg+BC5XJHyWkV8RiFniTv' + 'eCs79iXQGXp7we6kAg== e=found last=13 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAfPYSPfAeWD2rboqdKqjCafP5goRNA955JijOl7fAYMM= priv=MC4CAQAwBQYDK2VwBCIEIOQ13wHvbk' + 'WkfMjOBrcot+qjcCB2oNyByXHZ2ZqCaXHu msg=DAKJx5chFNVi8t9RFw0voIqmqLuDWdqMeI0WtF6UdSrTl8WoAkKjXMTmDHZwp' + 'wWZhB8y5TqzRbRryuYn7+qkqQ== sig=QPmPIcVmZGIuqlLq2z7kbiBWPG/KjqsRBvChELQwckoVthIfuRRDXMr66vhFCDELhXOt' + 'Cyays5BkafVjkogyDw== e=found last=13 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsTqBXfJId2wpuAhA/NzVvOkJev7hgajCWI+qxvdaJNo= priv=MC4CAQAwBQYDK2VwBCIEIAhyU50+k0' + '6WkaMJb9xVgWTrVZy4smSLnN1fUHzqaT0o msg=nT6TTpaRowlv3FWBZOtVnLiyZIuc3V9QfOppPSg+MTu2OcjGxNksoTTYgs/0d' + '+/gFzcbEZpwtYpPB0R6dqaYTA== sig=N43LnuuUj02pAZlJeCaTaTW/iblHKbMcAiJEOCwPGtiGe88R7vA2FvI0RMN+ZXsAVpiL' + 'UxuEKDWaINIehXMZBw== e=found last=13 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1VnYS2z3yWhvUnaEFleBKC63u2zCGKfNhPu/u9FZ6Xg= priv=MC4CAQAwBQYDK2VwBCIEIGe4PIT4c1' + '8zLs3nOzNBu+RTEpp6fqHaELKyTgdK+/bz msg=njQhDUT1ajZ8oU+Sl8QeTK5wganVeI7JLRURFKbTltvfMZsA+qNiyNcPc+6XG' + 'fef82e4PIT4c18zLs3nOzNBuw== sig=J8BZgOmVU/nqJpoL40yggpvrVoqknOGuZC0EjJagyIcXorWFcGHMpGTsN54sSe8c76v/' + 'AccnIwIbh6TiBUgVDw== e=found last=13 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmXY88Wodwhonu9r8USHWyd8fOjgqnrccc10NB5UESnQ= priv=MC4CAQAwBQYDK2VwBCIEIGqut8fuTX' + 'KI+l9hLeMhpA9Xn4Bp69Up6NP8mHvmgVxU msg=ZsNBwyqw87SgSK9t45TknCh2/o9M5MxIaRQA8flEXFQvwIMyHM4ysYUdpXKQy' + 'd6auhqCbRcvAdevMCjKoRrEIw== sig=l2gBVpwfbBB0I3SJ910/ijqPeZaaU2BwftOj23urkv6Pne3W0N3sSkHDUnVbO1UtiAku' + '3gbRns/q/umRvqnSAw== e=found last=13 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0ZubSjEyeBRtcujJDTy2TUvb7gU0Q1uuInKWrjXmigw= priv=MC4CAQAwBQYDK2VwBCIEIBq+pj4BOB' + '1+0tgpImbgDfp7Jv1tx3eXT1v1pLrIEWqO msg=ImbgDfp7Jv1tx3eXT1v1pLrIEWqO98vdqCtPQim/38KizJZtmudvRvTesY/X3' + 'babzGWZAMRX5IY30ESgTcP2Xw== sig=FcCOBsbGloAAWCDoZcsAE/Y6QVGcI+5K37DKbno1Xn534PW/ggKBi5OfUd7xPP985VjP' + 'OGjbVCeygLc+yM3mDw== e=found last=13 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhjhieCvP4ot+CR1xhOQHJmZM4mcUPeZzGGQ8DPKK6ZA= priv=MC4CAQAwBQYDK2VwBCIEICMOOFYAEU' + 'L197ajXapejXex94f+j8lMpDQETE+Jbyzu msg=htgwES0zbzed8pThd4x1WAbgZ+5yYxefvPJcK8XMaxdDTTA/qa9xy/NQV2WMr' + '7KHyss04SqR1xuFSDukPKYfiw== sig=oWmAzuYgJCjwbw2v3PUQ1p6c/g83ngjQBp8ndZpsNr16CGOZWffdIydp0w589Tr4NXbh' + 'rJ990zvmdxDUzimDDw== e=found last=13 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/ww9LW9EPu6ap9JZyTdlfxhlhYI4v0u8qorI7G2UZbs= priv=MC4CAQAwBQYDK2VwBCIEIBm15B9m2V' + 'SK4ZWZQiuF+0WqPdlgJ8oIb3EMbsVzkXn8 msg=c9WoUgAK0iWH3jRxFPnTJVScRQ5hjILt27BbYlRzNYFYRV90QStwlpFd88esr' + 'C5ZVc9uRfAtPM3pjjW69hm15A== sig=J7TtssJltWU2hjaj9GqOpyRNDCX6yJplNP4f8cq3AJRI2Ly8DI1Jii8aBAHDyWAcnRvA' + '+N9MBcD3HTyCWDz0DQ== e=found last=13 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAjoPuogLfEK1bVbvm76Bj9gCfa2ARy4zKWw6WQHf+J7M= priv=MC4CAQAwBQYDK2VwBCIEIGMM4f5U3s' + 'cHStFaJWvoKY4kkUVR5b14L/OEtoioD+gx msg=X81Kw59EwGFq3W/5pxTl/m90H+1V3XnzgINANoaiZDq4t0ziY3Isb2XqBnKrn' + 'WA5NPJlTul6tFwHYExiLg3YJg== sig=tuL3avwptYMrrkyK/NHqya1+WU8lUzMXy4wyYK99QFEiEJ6HYVodsgcK6+FR26dgkmUo' + 'nb9HRIlXTp81spRRAw== e=found last=13 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6NSF4It/S8bNcev8cHaAeP2MSMGrHpbzWpUaIOfwMZQ= priv=MC4CAQAwBQYDK2VwBCIEIJzR54Ymy3' + 'zAYZqyVZpK2pfL3NJ6bl5R9leKSH/Gq9/V msg=a3RxzNAZPy1r3eVW3MXSYIeOB+4PKIohk7cR59Dh5bec0eeGJst8wGGaslWaS' + 'tqXy9zSem5eUfZXikh/xqvf1Q== sig=wNFmm+Yh3sZkon/jFV/zVQP7JS6OxDEFvjUWIPOBejsQrN2iJjJ9fsB2WOQje5E4hYj0' + 'f16wld9saWGCJTvjCQ== e=found last=13 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+stRpRotKBmDBpYDeeJZuNxZzpmNMoTZ6UfAqE2K3V4= priv=MC4CAQAwBQYDK2VwBCIEIP+1JQZtt/' + 'VzfaJ6U6sS9s0U328tueFmPIKMJvQKfJeX msg=bAV8y5Qe6dghH4fo5Z8ZghcpQQcxXoMzhnfkDpyIr53IreitTbOb51sjcqvsw' + '7lyZcIDGbnRvekOt0EED3aLcw== sig=k+Oc2sEfv/UYEkjb1YIdQ341n7E2Spa+1i0jt0i0Y+i3f4h8TtOTCgPgpU9VKXE2+W9z' + 'rR5XRQhlsuvwdCFcCw== e=found last=13 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1kWEIF7NAa571pSYKFP6/FoHC3UsFtDtS+Zn/tYlDas= priv=MC4CAQAwBQYDK2VwBCIEINti1RWeY9' + 'fWHB/JVKEg3lMk48YxHgADqUFa4zMxIT/G msg=IYP+q3L/qMvYj9Ct9PPyWhYTqWPQFR13ueKMITKsN6ShJZgHJM+N7uuaukhNx' + 'KplHlREnppQ22LVFZ5j19YcHw== sig=kCFBEtUEAxs+QXMRb6GmAN5v2QhvWCboWk38IiN0dY8EKWKSSlxfasBrUmLktV1lrZNl' + '4tIvdjo4pl+j73NRCg== e=found last=13 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABHFFkRu1a99IMjSNz0VSCJdT47/67h4td+/GP14//Yw= priv=MC4CAQAwBQYDK2VwBCIEICq2dhRzzn' + 'DvtT2M/qSE5ahXyFzpK6DYCFaSAWEWqMur msg=CiMatKjjySsA1xOgKrZ2FHPOcO+1PYz+pITlqFfIXOkroNgIVpIBYRaoy6vHr' + 'MCp+s3TxKChHI1IJLQCFrJp2g== sig=04gI7/2bWvcgTGfXTisGn2/A2D6op0sddbR/jId9UpD5Z2XBSGsFSMkBcNf1zoPA3/Hb' + '+FpSruHfi57t87MkDQ== e=found last=13 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+Jb6J1+1hyheCbgCioYycSz0k656gIfhu4EfEUBVY2I= priv=MC4CAQAwBQYDK2VwBCIEINCly1IOGx' + 'ydTAL43jRhRT675BL+sHbQzOZMElkwbLXN msg=Bx3Ixq43xi9PMhcOaNYngHHQpctSDhscnUwC+N40YUU+u+QS/rB20MzmTBJZM' + 'Gy1zXe+zZJqpdY7mfJ0YR/G3Q== sig=nvl4c2hHz9ZymE+5jy65ztXduFh4ahdOzjAU7XXXUQozJL9YbAjrT93LFbRDdvqgMagG' + 'D+pottjpFVfu6DFaDw== e=found last=13 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACOHnzv5ruwKgIv0NhYH7n6JMQv1BmDD5MYuJXo9eF5U= priv=MC4CAQAwBQYDK2VwBCIEIDGPwU7MVh' + '2+peJSYgTINr65f0WvSuLZRtjMYh2JyiQU msg=tJOperaG//Z5+JsPTO8+KstuGLGOREOqJyDlYhphh5Wk0lJyWLGQWbuppUZ0m' + 'mfG3obzF7lo5ZP33Gi5JVQp4g== sig=iU6HlvfZFOKUXhPz+phCj1rGbO/8GENrpU1/VPTRdQYffgc/NcF0R9ZlSlD4xbfeb65n' + 'ugZmHg432y5wz37eCA== e=found last=13 s=32 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAm28K7xP/coEXY69+BY5qdlHZbK39j/9xEeVwcLIC74o= priv=MC4CAQAwBQYDK2VwBCIEIG/+kcDtKk' + 'v+V6vCunYJrK2SbIlG+oBFXPXNb9vIRlX/ msg=Kkv+V6vCunYJrK2SbIlG+oBFXPXNb9vIRlX/7EDubge1ILVdZPRjlZz3Qjs75' + 'vb/rzt6M0Jp5PcGIAUiQ1mnfg== sig=U3cY7ZY60rcwfSFBM2Rn3ljR4laf633Dmdng7LgPXUt4e/CNeMUwk8iuyFYVJooiP+q9' + '8dWqxhwv+ucHFhWhDQ== e=found last=13 s=33 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9BGgy7krNn6RpH0yaWPC1CSZBdKiQ9R1uNpHy+HWsMw= priv=MC4CAQAwBQYDK2VwBCIEIHSDZA/usv' + 'lnqN6Dc8v1S26j1nHRBoWeDCZGzYJdutrD msg=YsQ38VyTC6TBQL9CPaHil0xEuWkX1J2DELP+4B7HNiClPEc1oJsEQS/X2cpcH' + 'JYZRLxne8L19o90g2QP7rL5Zw== sig=SGST+Ph2sc0FmYxZRtz8w2bC09I2NqxkQipgIRtK/YNbQBY7/5GXN58Lkb5Rxfo4MRSP' + 'ZpmCANrzUsGTEuAXAQ== e=found last=13 s=34 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAs4IP8oziqUpTza1762bPeIHKICM0uVGWmbqZIC9SXzU= priv=MC4CAQAwBQYDK2VwBCIEIDtlts9zxl' + 'cytnBZqrvVCP4RPwXDJri5cbHjwVq5tAqZ msg=Wrm0CpmXOGB8kBIuUTLjJMeDMCbBJuodnBWXpC8VxTI220CI4ayXKjg15QYig' + '1YwM1E50LORBOunvhNa5CXF2Q== sig=CmWRt/hLECO0wAe1mVLOnL0MbDi+wcAtLcEMhqIcVhl4Uztz+kwGxSTfXghg/HJdjvky' + 'DmsDvxlymLFAGcOvAw== e=found last=13 s=35 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADKD+bv+zegZWgMNKvHoEQ5qsJa1+G7/WNnLNx/an/IY= priv=MC4CAQAwBQYDK2VwBCIEIKGmx/GfGn' + 'BASBsSyrH+9mcA79BKcjvQ9E1CEphb9q1d msg=KAZ+E28F8Vdk11K5L3zsykRP9LIlPzLGUa4Edh32ETMV6uBDrOvOER1XXBSFe' + 'agmtyCPv0oAwoRPoR36h9/LIg== sig=6srlsZwrDwPWS9xW1JDFuN/Fu3VssfSu+RQJe96YnfTM/PAZOaqiXoLYc4/Y11NC2g2B' + '8F9t5rVPFGq9xscBCg== e=found last=13 s=36 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEArSpVjA5w7LCW7rdqW/K6+qHOgd8N2H/Q66eUmKFyOKE= priv=MC4CAQAwBQYDK2VwBCIEINC+UODfOp' + 'EFQuIEyA+fjhLXuoWA3W42JCf0RR8kOrLN msg=0L5Q4N86kQVC4gTID5+OEte6hYDdbjYkJ/RFHyQ6ss1Qfeccz5szjX/4eKg6F' + 'eUR3d/DIHcEV+zaQAOMUStHeg== sig=8+TwnBQzQgX7QA0K8IdOfFrdj14pFkb2TIma1mHGfLnX2Iy71/EeCgMac/Cp7VhTlmEg' + '+fxlVARYmvBdvKamCw== e=found last=14 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAUrmA6SZe1nUZdYSfwll3c5SlP5l+Bx/tSpI036M2dbs= priv=MC4CAQAwBQYDK2VwBCIEIACru9rHDl' + 'UynZztpOj3CbrqzsL7/W3xEELplGv4qTKn msg=AKu72scOVTKdnO2k6PcJuurOwvv9bfEQQumUa/ipMqdxt+Vt7olnPDXKiEOYA' + 'Q07tYFKNIaimasOTU9G+7jg2Q== sig=eYzDo3KJnjopu9JYoxLmX4K4i/E9QOm/xbii1ov334xvMfqUHAxQh86x3texMkFMkjie' + 'JyKyemSkEQyUlV7jAA== e=found last=14 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACCfYE0NMvS27KMTrDcGDXkpCRJgfGja59pvAEV0dMSk= priv=MC4CAQAwBQYDK2VwBCIEIF1CkkwLna' + '1/YvpTsdHVoZxutGEahwNHvJEa69v81ppA msg=XUKSTAudrX9i+lOx0dWhnG60YRqHA0e8kRrr2/zWmkA3kkQTXwSVuiJIvIlb1' + 'KW4/aT+cMYlrhvf+MIMyoEI3w== sig=/9A7ftDF13H9Ud+HqB4UKyJ4iFkx20w+GOn9Px2pcGXBtI2lJ+yMIswHOhudqEw5iQlc' + 'DrkdXOgYVlZaaZKDCQ== e=found last=14 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAox5pJqmwwzwvJ7F25Pfg2pt3jkDiUOOLQxEtfngHVvU= priv=MC4CAQAwBQYDK2VwBCIEIGnCgE5Xgt' + '2DSOpsVqDoFWOAhV7F0+3dA3RJIPu2d8Eq msg=acKATleC3YNI6mxWoOgVY4CFXsXT7d0DdEkg+7Z3wSr6YWcefb4OPhscmi1Ve' + 'tJkCltAV7SFi2KDachL51GarA== sig=r2lPx0IyrcqXmaNt+7IyBV7FYDhFPWR/nNQ2Jrn79/Zak6WxoMM/fZLXrHtRv4axcldI' + 'mF/RQQ7ZkQmxdNXhDA== e=found last=14 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHr7BzFwIlSraonHssOueXzQzl1oI3MdofgwBpAy4LCM= priv=MC4CAQAwBQYDK2VwBCIEIFds9tS6i6' + '6tuvmCKSYlManGPuTvQugih5MWPKRjzoi9 msg=V2z21LqLrq26+YIpJiUxqcY+5O9C6CKHkxY8pGPOiL2cFrEzYgLAW75V4NIIG' + '9DrQMh90M8SIBQ+hy8vzgSUqQ== sig=OTMtvYqHUzmUDFbStGTqV5X7KFD/+JL91kYRLYWBWofMVnAdst2KwZuVxYSFNJNyh0aQ' + 'GAijp8d4kUfFsqEECA== e=found last=14 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAH/3N3Bfdi7Z6wyE9HNzG1nyHsv7WjqKyFl88E4M22G4= priv=MC4CAQAwBQYDK2VwBCIEIPq9umF55W' + 'V3H/K4IFHcNHThlVowwht95Jr7/CydVsKA msg=+r26YXnlZXcf8rggUdw0dOGVWjDCG33kmvv8LJ1WwoCNmpyxkBxVDn1olXnJ0' + 'hPWLESV7RriF8I14Z02x245UQ== sig=h7+Wg1IhpMNxg9PJUIEW1IW/OGdFdBZOjDiDNrr1MbgcETH+i/J8YWV/RPAGRLvi1Qlo' + 'oYxoP5vH3NBaVN6YBw== e=found last=14 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIp/klvM5Hd/ycnhGROLdVlMQUuA0WlH2ynpc09yeYPQ= priv=MC4CAQAwBQYDK2VwBCIEIGpFnW1yrC' + 'LaWhGR56YzDuzYh7/VhFrOte7qhJj4UCm6 msg=akWdbXKsItpaEZHnpjMO7NiHv9WEWs617uqEmPhQKbr7n4obJhO6tWLay3neI' + 'lH5jrH6imjATw721gbdbCdvQA== sig=lNg7ul+IjRHtEegWxbMtMJVjvVzsxtI7PHCyn803sYMtX54FxVQVkG12tHYqreXn+WbN' + '22Gz9dlkCiGHxwSpAA== e=found last=14 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAXI2KPuYPVRaIa4w3QBTZZ/fJuqvnDjTzAi1lqc7NI/U= priv=MC4CAQAwBQYDK2VwBCIEILIN90CJhB' + 'rwHpxvZKt3xrAZ+wUWUk7hvJrqR6S0azSj msg=sg33QImEGvAenG9kq3fGsBn7BRZSTuG8mupHpLRrNKNgT9X3bSqR7V7XUuv6v' + 'a8NZWdWL8SxmmQfk2VzY6S8JQ== sig=PtuqgEr/bYvG1nWBc4ra/vS6JMePDAYQF7ajDJrCMlXDlIDPeKAKtcsfxRH4ofLiXBw4' + 'WuGnDdsIaVker9d8Cg== e=found last=14 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEATS4Mla+2lh+RdQ1Ocu48PmWV/VM3Wr96KQfDMSyRIMA= priv=MC4CAQAwBQYDK2VwBCIEINmZvIojYq' + '/TlvPypWsuBHUZGZH+7WnLEsUCJgzvGGir msg=2Zm8iiNir9OW8/Klay4EdRkZkf7tacsSxQImDO8YaKsGLMFpYdR2NU5cUqrum' + 'BqsbIm0O5EWg82kJrRjvjxHCQ== sig=cEZ9+cTPpPscbkjDq2tw7nknCfYLPiCyC3zV0C/9pkX4cfu9CiMahixL0ga67zHpxQD0' + 'J5PrFGx9mPhMkx0RBg== e=found last=14 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAg44T9uEqGa7QiI7Ju0GPSIIn9Jy2vFHscywQf33drVE= priv=MC4CAQAwBQYDK2VwBCIEIPN1TLnZn7' + 'tqLW64n2XtexGqtSrTcsqpMG2ffSFJQjBu msg=dUy52Z+7ai1uuJ9l7XsRqrUq03LKqTBtn30hSUIwbjZuc5ruFeV6hXCX4mWIU' + 'BEIY6tjlcWsbFyUOiuVYbbf2w== sig=4gnO3iXjpCv4a/u1UliaGcfvQDhjNc41I58iXt5YwYVUEPDZeLgmPxi44hkFRH3V2DED' + 'Ny353E2oOSRtDWA7AQ== e=found last=14 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJO2TgZl45QJLSjUam4mWVPQ0h22q4uSlgrYOHbvv1cg= priv=MC4CAQAwBQYDK2VwBCIEICGOCk25WC' + 'ik0HhVJ0fX/TKLeVBSam20TYwie/xbsRaf msg=uVgopNB4VSdH1/0yi3lQUmpttE2MInv8W7EWn2TUN8W8+zjC3YB0Sm7l5MCk1' + 'cjSm5y+jTbEA4f+7+PKYN9X5w== sig=Tvf77WmfrwdWSE5AfJsv0KileFIQsnCou4Crl3xor6Us3RG0IzUbFkLtZjot9ad5+3zc' + 'p3xN6lEHNCyulKaQBA== e=found last=14 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAcuKZD9MkL8m24IgvUHUqNy4m65ieSR+nWFESCPj0wNY= priv=MC4CAQAwBQYDK2VwBCIEIJYQxyjA93' + 'dZ6Y2BTsWQKODDYqT5veJQ7Et+8BNIPyh3 msg=lhDHKMD3d1npjYFOxZAo4MNipPm94lDsS37wE0g/KHcsNTFHXhbv6T/dB5aK3' + 'cBCYLjGpIKDbDFm9YWgQIIB6w== sig=slqwfNi5DJvcdz6LXGNABQFtVYeAznlruDNIwSqVKQulRqy+PdKTWNvsyMZb/32LrIej' + 'PzySYiBes0MvLXm2Bg== e=found last=14 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgPw478gkjq/g+IidYjWQTpMFu9DdFu8wRQ1JUiAkBi4= priv=MC4CAQAwBQYDK2VwBCIEILkXuYOCJl' + 'zQKJ8Fwmu05DtiXJwmDrG3Nca8bPU+V5PT msg=uRe5g4ImXNAonwXCa7TkO2JcnCYOsbc1xrxs9T5Xk9NXRVPYtH+eTCEmspRHe' + 'I6B7C4wIFOZpBhq/OTQ5+9SuQ== sig=DohKFdYeN3vhyY6NJWOUzBYYsMVSIU6psNc8b5b9EreIYX2kDdlNPV0WhrEEr3/n4MLH' + 'sYcTZnNQp+42SPuWDA== e=found last=14 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnHfXEmJ2wVuWTbT98vAhNTK1sD2prZQ2xaxlNhN6NDM= priv=MC4CAQAwBQYDK2VwBCIEINokiK7fOO' + 'Zlcv5khot6gTzsnB4y9eEb71fWNHuzmvBe msg=/mSGi3qBPOycHjL14RvvV9Y0e7Oa8F6aRJ6FwNqfe1p1Q+sGhy0IKlOngJcqm' + 'rs+QHzOk5/ISSCJCHoS2p4gwQ== sig=Wg8mMPHAONYEKBtbX43K+TsvRbIr+E6EWUV8hutmxeSBbeuXYUX/4y4EqofqCS6cHvuS' + 'GmLUBYQUuTujDBOVDw== e=found last=14 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsmQw4VC+O5aySltPDZpuyLJnIJOT9Jk2ycKrrGiUwGg= priv=MC4CAQAwBQYDK2VwBCIEIIc0vyKV9J' + 'O0RUZplWIFWRtgmtwBHgzVprlofSjnRAYh msg=K/RN+IQGEycN5IklrFYJx2aQNXDo3YF+rfhJ6z3MHTw8I8X3bSAJnP+amuWfu' + 'CE/EKHdOfeIVx+l7Ew22a9ZXQ== sig=CW0fgUaArksW3RYCgKl33glJ9lpNgVXGDDZs86cqwuzUEGCMBow+0Tz3EAUJgwJOYllI' + 'KYSVpNmh46SbwjfmDg== e=found last=14 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAikZTSHt8+kzMZfj8a02ytJlLnNqTt+rf99oFA/hKybY= priv=MC4CAQAwBQYDK2VwBCIEIFROjMUdRd' + 'KV6+fMX6smLk+1ao4mIvN1wUzQxN+jD502 msg=Lk+1ao4mIvN1wUzQxN+jD502fkSboYgOVesHz5fC3H8mMT8zHmQ6zJZeVxTbH' + 'LxWAMtMZI7GUXsYY05dU0Bjgg== sig=5f9GEI7zRHrHe2uPlg5OrvNORNp6lOe3FA2olhj9r9y6TjqGTQ312XyTFfRyECJ77phB' + '0nqeG4oszG7uiXFcAQ== e=found last=14 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAv5BhJX9NY8XwGtTOcf4hQOGBCjoCGRdlj+k78pgt+9w= priv=MC4CAQAwBQYDK2VwBCIEIA86c/pn02' + 'koBdJUXMJexT0rDTbpUxDJpTGmHISws3vU msg=Nq0KyaFCnkylokAEirAUcgKt/v631+CU1LMNzoiGmMiAZwewq2kz3+n7+fuq3' + '8nTrco3zMagfvSmz4FIZsf9tw== sig=h1OcUwWK8Frv8X1AuCgoZlOJmsAdOfvASg+Vq4E1W9u2q0hokHEaGwN+sewjmLALieVf' + 'DOlfMN3QKxYfowMNAA== e=found last=14 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0PXwb760cHNZCVG5o3KfzU8pITFcFSXDbi+qQDYk74Y= priv=MC4CAQAwBQYDK2VwBCIEIOnjvFAiRi' + 'wj26H9LYPDElxOxjFu9AcBLlgzkiLafQ8Y msg=5b/cNTSfKQSInXyW8Ys3E2oJ8GS3LND/Z61grfV2aHaYMOHunCnsStY3fHwEd' + 'eycBe8nVC9+sCksRxQ3udHf0A== sig=8NFnGKdMair7CqzSsLuFOVCUEvSHDjUVH4m5Bz3qr9mOcsl8xgeRs4Ro/KgbU2GJRugH' + 'nttocRWvsqIH4frLAA== e=found last=14 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEACZ7rrcDbw7MkE1xYZvOwrovPyCj1sgcKcXw5U/nqnHg= priv=MC4CAQAwBQYDK2VwBCIEIP9iHYQeTe' + 'C6clgwx2kpAP4LwUpPEjguhU8Oi2R2Tr8R msg=gTuUz+Sg7aG4SabALhqX52GK+p+zGyxufWtoLqLq62sUifbrtgj8F4czJIKb+' + 'FkIM/ORkDTFeB5AR/NhD4F5LA== sig=T0G7iltrMGbrbavuCtfFDBo+4pVhIdT+5qyZ8zn7YQeJJYT3lrtYJDKny9QYRxknOada' + 'yhrwjDc+fMT0zlxcDA== e=found last=14 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/F8kUfM2pJRmMJRSV9Mir7XOJfQfQUZVQkB0oLnY/II= priv=MC4CAQAwBQYDK2VwBCIEIOyv9DdWii' + '0/m6+Jzy4XoCeqdV3QeYJUsD3ZTzfVLw97 msg=LLyErFZqCsIemoY08F4ZBYx6SddkzGkjGmcBq15mlLzkkXe506LUnCZoNyxmS' + 'ceompB+QrdOkYAOit0/Tqo8JA== sig=Ft3QMD16hHHV8//MHOyUmHD+WBgbdY5WPB402MjAMhEzY3RCqHIsm8eRt+K/rAx19tNM' + 'TfT3geRTeTcUTNN8AA== e=found last=14 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAfeKoj445Doqbk5QZNmd2K9QP9UaAAjsqx5XknzCJiNo= priv=MC4CAQAwBQYDK2VwBCIEIBN3kDoG/s' + 'N9i1GeoKxj7sQq1tjFadHLUVYN/sqC2qbA msg=Zn/K4fF+4QbrLyhdw0yi8FMO7oCdgJMD/M/5RrCnYNIPLsdiTmGnFRN3kDoG/' + 'sN9i1GeoKxj7sQq1tjFadHLUQ== sig=qeQYhXNfUoLjWzseUEJswO0qQcxmZdJkLYR39Uhf0CepSj6uP125rbyrNtqtEcqxrB88' + 'Cv459wBQ1qPzd4C0Bw== e=found last=14 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHaCKjp8TZKIKE3RiV0D3xzfT5+pMRytajmm8WotxMwc= priv=MC4CAQAwBQYDK2VwBCIEIE0HVehlVL' + 'FBqmUlBmMrQeW7OyPtf6R2crpoPgIjp7/x msg=6R2sCH5OdA+fOPVfObSrKmrE+cTTcaJx+gNtj333/ZUgrGHkxZU+/hbV/fWVB' + '6yLq4ZzW4QwfWX9v0by94bV2Q== sig=O0co8fmHsPmfEIBiQlw0vx7v5CopGE/1rWceOTgPiIZIvwCNRpj9S1VQRx2kxRv1LE/a' + 'Ih9RBtfHmVWaFDR8Dg== e=found last=14 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAG85BbWZTVSSWWduYvGIulQp5XLQFgs+u7Wh//kaQHy4= priv=MC4CAQAwBQYDK2VwBCIEINsxUuFwQS' + 'd93SLgK0f1mZ/9sQjxjThULtgYf7xnI8Wy msg=GH+8ZyPFsgSo3ZJiEDC1JMGJ0v+Wml0arKsfZ9OcqDD+4u4fMDyx0QkyIkXuf' + 'oUfsih0s8HN4iGJifLgNzzCBg== sig=ztVuYKKeKg2+J02hWuqlS+VGPE8l90V01DhwOfbQ3ag6pL8I0HPLofxDXIA/wo78U5p2' + 'I0GYWPvSfTeSBLz3Dw== e=found last=14 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA8QSGVDyHFgS9FCMWJl8TcRm6Uplx4ashpQBSt9maDIM= priv=MC4CAQAwBQYDK2VwBCIEILTSHyHMZT' + 'x/0ChAaBLAZAPnqha8dqxCi5tnFT0ElOYk msg=5nOKsEhXrErNncGBFlUitNIfIcxlPH/QKEBoEsBkA+eqFrx2rEKLm2cVPQSU5' + 'iSdrKYrJWG4Ozy7zCjo1zIMYw== sig=lsu1Lp++hvOu/fYf08XByAX6aMCk+M5rPE4xDbAhTYJPxIvOk4jLEiWiuIHZsb244bys' + 'hoX/ZHAvQeDN1jD8Cw== e=found last=14 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAnNUwb2W/n2Dljqxg3ePBHWP+j/7KaJOY99Cv8XGwgeM= priv=MC4CAQAwBQYDK2VwBCIEICfItpQZvP' + 'V3pNXSzUlS7GCwfzuUhvRGv0kRWK3AX+YY msg=uN4608qRJ8i2lBm89Xek1dLNSVLsYLB/O5SG9Ea/SRFYrcBf5hjnOuFZbFDrW' + 'PiGYq9ofTr0bAJBCtkk7kfyjg== sig=HnS/m9WOhBLgrPV8W+is3zTZmI/0ruX4R+6Bu+YFXs/gEheFOdTjq34XZP1vqLc7I1eq' + 'jdRG/bAShWsWReUcCA== e=found last=14 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAS5AR1I0Dm0UENSWNm3EL/W+6Ey92G3XKC9qO/as3oGw= priv=MC4CAQAwBQYDK2VwBCIEIGqbGSBspJ' + 'uPKs8wayqnx6fD19Y6OpP68H4z57FwgB9x msg=x6fD19Y6OpP68H4z57FwgB9xSl/G4z3COsFtZFB1KY2viBSWG5yN47kHfi6sJ' + '+yvpZujPsbY+50fSMHf+DFULA== sig=eD27n4x+5PFxZNVK+Xvg09MPlcUCDhwFclFnzkWoi/+Fh7LQGLik0qHs9O+HZptU6E6l' + 'QiCvD8h0B84ByHzUAA== e=found last=14 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAg1/SoFTJGn9tzkYXB1sOieMwi3PaT2JJMizJQdFixds= priv=MC4CAQAwBQYDK2VwBCIEIDjAoxJoHS' + 'cHL6KSSJVIDAjCgl4E8UgDtJn57YAx6hNH msg=rs86drHHBXUssV9pqGwycBLHHgYJl2YaYbnUTkqiOwndiN89cxsqGF/gfllou' + '8DplgL9TAnAF0ph3vNh3yJtyw== sig=A4MaSxSQzw8de8p7kH2ENB6dWoDCPnTrgvk7WQQ1RLbQ3wVWqmPUbckTBrOlw0WODVXr' + '2+EPrei3t93bhWd/Dg== e=found last=14 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHx9xHm31qQbBuK/rIHdAI2i9Tc+DNCxWPFd6gjJ6MC8= priv=MC4CAQAwBQYDK2VwBCIEIKAnnzu7YX' + 'kU/5XV3PUICqh5iXUea8G2wkvfZrgHf0/p msg=h9bV141APtBjH6X2yRGoApRBzzQ7gmDZ7toxiNcATGAiRB+8a2uOco+yc6lxo' + 'ST9DA7bazISV2IPIKw0flf28g== sig=5Emp63BKMxaoidDd1D+Z4eJ0ra97GL1/YVHaGwZp25wRuXg0TYKh03ZZdv79Qo7SSMyw' + 'DX/2GB6jrXq/7+FXDQ== e=found last=14 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAC41msvvc8BsyUrFr1ei9dq1MeqoXyxkbK76OIPFyR+I= priv=MC4CAQAwBQYDK2VwBCIEINkCeYdXwD' + '72aTZU/1GMQ647Gon6OG4wN/Ahd/pq92wH msg=igJZv+3ZAnmHV8A+9mk2VP9RjEOuOxqJ+jhuMDfwIXf6avdsB+xxcruKS3IbR' + 'PSltU4XB7DBsPF3B3JsGaym4A== sig=NtQlubz6vG1DooJxHT6ffkWqNsJGMWH4OznyQX3fHJvmKU9Ih9bX+ZrSmuqY2HT0YTFn' + 'SM/18l2TrBmH+qpqAQ== e=found last=14 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFUEjNOcwiyht7WS7K1CYUg4qo/q1nrJsdNrx7RJ2Wdg= priv=MC4CAQAwBQYDK2VwBCIEIE4qJx1zsL' + '5y7T35Ra2v/AFXrB3IVmyjipp7xCsF07yx msg=xUyrQgk8TMfvh65q4wCsrAJr3/MhRguGTJWWHHPpJr7Jce0VCmA58n8kg83/F' + 'oROKicdc7C+cu09+UWtr/wBVw== sig=etmmnB2cknmfBTbRvUEy2tF1RJ3sQxb2pM4nJaOs6FoC1l7+sDvOpOBY0g6AKgKxo4p3' + 'IEqvc8XyD5A73UxOAA== e=found last=14 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA0PMdNjMNCpOf3obup6fWiXn112pRaPhsNJZg0OPzIZU= priv=MC4CAQAwBQYDK2VwBCIEIGld0udu7p' + 'jSyOw2U7sWX7p304rhGsj3T7fING7sxv79 msg=Avw7hLn7OshU0ps54aztYKD98ixXxhxVoofx+1RfG7mbiGe3dWVgqts9Dj2Yh' + '6wQfK3441lC/Dd1y21P4G2Ayg== sig=Rh7UYU7AzUWQ1G78MWaW8WeVsaWscRZ3XMAL1C0fBKTs1bHjuckpo5X5oBC54q/O1B8O' + 'tzPSwrf3W4gCwAjSAg== e=found last=14 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAFRpiqT6VYuLbdrrdiWnpYYw74zq68UhIJ1HhmuS8620= priv=MC4CAQAwBQYDK2VwBCIEIJyvVSzvwQ' + 'u1vZzWWAlij84HmKMkzyXepfMlDrJD/Wiy msg=Yxdh7WvZhDL9533KBxdcg9rRlVPX2kOcr1Us78ELtb2c1lgJYo/OB5ijJM8l3' + 'qXzJQ6yQ/1osqKY7E4ESk/Q4g== sig=xq4GCxPoOYStspP15K/8B6gD9iES56nmVDKEk9y8WPzVYyC5YBSPszQUMMtFHZjMF4Ro' + 'kJei9L6CNw3EoIT/Bg== e=found last=14 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA9FKRQ6OVM95NU4P/Q5940GASqnOAfSzD5CuVJc6aZxM= priv=MC4CAQAwBQYDK2VwBCIEIDLK+c4+cM' + 'K/+sJKi9EB8QHNBKNmGLs0S9Bop6/hkB6S msg=0Ginr+GQHpJCGrkF/b6GgkO7jPyb7JDnjTm0YpIlawS6Pp3SrREWv5ThCpUd2' + 'trm5ySVlQp5gGGtmjRpAOkAdA== sig=1kpG+hNW865unFQUdnVdHL0F6H3jIFC4CCo0CYKml+wOJe0gSZ4nDI9ol8Rfmq/sALoh' + 'ss79h35b/rd+PQDdDQ== e=found last=14 s=32 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAWreZ+PD6f7dxNGNtoZOPY2Rt0IsBIJnzZSpoFgPkH1g= priv=MC4CAQAwBQYDK2VwBCIEIEW9pQDt2s' + 'w3513ox9rby15tT/kZjptFyCckJvkAlKRS msg=bdM5PP16ujRQdJXkBIgX/Zbm8pm/7W9FvaUA7drMN+dd6Mfa28tebU/5GY6bR' + 'cgnJCb5AJSkUnKbMJPB2oXxuQ== sig=55E5lhF+7fpIlYDYVinChpbnBHQqaq3ctLjdVpTlt7lU/jo7oMGXC67YEM3cp4H5Tcwo' + 'Y1iwkIsQTvnrb3qXCA== e=found last=14 s=33 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAeWKpkhqvJGaBNUHcGJERJ7jCKeJLPkgf3fFTr4taBl0= priv=MC4CAQAwBQYDK2VwBCIEIGdrR0LQGG' + 'bOgaw6UUnF3W1APi9qAeIxiC3Hlp5ne0B4 msg=WxwsPFNjTU5xP/bFOyBj475sdmxmvDhs9jx8R9m++3f7zj3gBsgKv6QDR5zwf' + 'AtwK5Zalkp76OIAwDGaqu2nRw== sig=CDPyyj9WRMQMC3M7ZV4iu9mjDNa03X5Yob/rICEZTN7/8LAbRuDzaUaB0uxJ6DzSBjmm' + 'QKAZc+iUjOA9+kKrCw== e=found last=14 s=34 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAafrjyw9TmjNAtcYY73p/PgSz0pD2vXNX84Yp7qPvF2I= priv=MC4CAQAwBQYDK2VwBCIEIJA+B7Wcg8' + 'xWHPmpEO6/DdGAkUZL2eTXI3BFTRgCO8VZ msg=HPmpEO6/DdGAkUZL2eTXI3BFTRgCO8VZ+b05LT8H2NDG38cvxSimvCE+4Uibc' + 'fSRvwpq568qd/np2HYRF36eFw== sig=22FROfguVCamKxJIjuTblkoae9nkTRcQ7FN3gd+z3+GC6bTzBje3ZGsAbFlz/xUlMXd7' + 'T7j/jom7TzpMbx/QDw== e=found last=14 s=36 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAUC1rrJqYnJUlSjdtw/h7AiRrV35U2JgQZ2y64pkrw3A= priv=MC4CAQAwBQYDK2VwBCIEICIQjYVEZ7' + 'sX2zO0WIIt4vq6cJChxbyLRJXT7ZgZrH7X msg=IhCNhURnuxfbM7RYgi3i+rpwkKHFvItEldPtmBmsfteebevNrDJnaxeHi9b+e' + 'G1FzrNhLxkb2Qu+i24dz55q7Q== sig=/5siLluNHP7Zne7N6VKXd6MqzHx1n1rBF8hIdAHu/W9F5JCqv2u2OZrt9uVJGPNXuJwt' + 'YjCw2MDYtYDfkBAJBg== e=found last=15 s=0 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAK7mCAXGd7DY+OaKT8f4xkBeRzQQ6P7ghcHmCxKg4jQw= priv=MC4CAQAwBQYDK2VwBCIEIGCxM2IVsL' + 'PH0NS0iGdDRow0RDA8yore0g8L2GYGr0pk msg=YLEzYhWws8fQ1LSIZ0NGjDREMDzKit7SDwvYZgavSmQUTmsmi9z+bMdIo054T' + 'xoZBuniJLX1l0GztsVP8RALsw== sig=58iKbQtzv61RvW1Ksao3euioHPm769UQihSMgopALBaTQG69nbQpEyL2zsYoq35m562Y' + 'pnx9/mFq/uV0bj49Dg== e=found last=15 s=1 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAlB/IGlnaOpKHz3qpR/f7i83pbmxsvjt6RC8KLYIcEps= priv=MC4CAQAwBQYDK2VwBCIEIMajxYZbI8' + '91LtZscvF1rr5yUe6HZfGNjmTvR9vpQb0t msg=xqPFhlsjz3Uu1mxy8XWuvnJR7odl8Y2OZO9H2+lBvS1y2IjN+pAjgo7J9T56n' + 'TUdw6sDZOM0kf2NEM+297ibHw== sig=+LBpQtXaQabx8Be9or19wjlQITyiGMYBTAOOytsgw1MpGGMdq9/f+62kh8F9xjDRLBaX' + 'vE75v/V3CJLNNhbBDA== e=found last=15 s=2 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA+iDTbPH8T2ZcDU3mrEibgB7EuWuR3FQh9io3A2YUt8U= priv=MC4CAQAwBQYDK2VwBCIEIOPKqzzSFa' + 'Ul2i5P5Qb7tKbwLp+7c7e7eeYwexzlWZx7 msg=48qrPNIVpSXaLk/lBvu0pvAun7tzt7t55jB7HOVZnHsUk1b+tisk/cUVzCAVF' + 'HKcgpE4yxjy8Jg49zG2o+0jIQ== sig=2LPcnKJ22GfGapX83qmZHGtGmbr/z/Q9VzooWWPvAmnFKg6fkL6+i6mOKCSYB5jGBbtY' + 'RcUMP54Ou62OhdccAw== e=found last=15 s=3 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAZsxt8mPXNweru97xumepOhY5AbbMEezJDaTEPMywgQw= priv=MC4CAQAwBQYDK2VwBCIEIF7GRVvIr5' + 'AL4KmMDJiO2VZ6M7rqmEkCgXPELMh1Qfrp msg=XsZFW8ivkAvgqYwMmI7ZVnozuuqYSQKBc8QsyHVB+unqEMArYvgAmmtDjuwh5' + 'n7n3EoypTj/CWsfXEDCbE+DtA== sig=S1XOmC3InxDBIaxu0XvokHhX2dnDDYgKBWfPS6QhHpBYxeoPHCIg7ZO+ouUzq8FXg8ly' + 'g5ZgY8wbiEH9GhimAw== e=found last=15 s=4 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAbK7yF2NavTh6lO6tyNbx55/sGchWhj9ecGPTnruOVig= priv=MC4CAQAwBQYDK2VwBCIEICG9OGZZdu' + 'e1U3/4/GJ3gICwLnYF/6revXmqkzgtGtf3 msg=Ib04Zll257VTf/j8YneAgLAudgX/qt69eaqTOC0a1/dR4EAofxWxFlrs6k5Zq' + 'gwbQdm4huliGWK5ANXdCNvy0Q== sig=/1yj/DisQgb0r1+Sneiu7gmtdNb9a2JnVcOW4J8y88pLJUKSxHZFTqQF9W8hYXoUVoHY' + 'SyWUL3FBS8eM6u1hBA== e=found last=15 s=5 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADMRod3pzq1twUtm+FmvR6kxgZ6Q24kQ83g5kf/5UICQ= priv=MC4CAQAwBQYDK2VwBCIEIBEgR5F50T' + 'rSj33KnNi+ApH+SuY+TZCmGBqU7rpU2rN2 msg=ESBHkXnROtKPfcqc2L4Ckf5K5j5NkKYYGpTuulTas3b8+AplIcjUFNBxSKDGe' + 'nE7wLEu0RlQ8Y99F80jQwp2Mw== sig=en3wCT6xW5B8PC7RywJB5UcNLblIAY7qSe1K/QxqVcn8ozsipa+f3nr3jY+INJreOHUB' + 'fP8b8rESOKb8gSlvCg== e=found last=15 s=6 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAScwAAocf4+eGsN2fUEItodZP5Q6Lsd+X26DPLkLqe+Q= priv=MC4CAQAwBQYDK2VwBCIEIBk/m6QC9J' + 'IJIX2vDtGfnfn01zZgPJ1aCW366dYgfJUj msg=GT+bpAL0kgkhfa8O0Z+d+fTXNmA8nVoJbfrp1iB8lSOzSO5i9016mC4WHoiFr' + '+5hGOEmSef45Pw2wwNaUVqOWw== sig=YduMLTPNPrkV5bh1ZJKft9/MnUQNLqseKnBib+FrfCCKdoEp76lsTNfRb2+0doyYMvtV' + 'Ij7qTjrq3WBomLxMDQ== e=found last=15 s=7 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAj7UBug1B7Ut6/UAiZ0Bqbx79V+SeS/TObzAmma5ztLc= priv=MC4CAQAwBQYDK2VwBCIEIN0IMN/PYS' + 'PJWBN3hoWVMkICkPY6N8PtR3vcSBs5DtSN msg=3Qgw389hI8lYE3eGhZUyQgKQ9jo3w+1He9xIGzkO1I1G6JqWYplQJNH0pigQV' + 'jpHyy9kgBqd6MGsnMgW4HSWAw== sig=C7ckE5H1vLurQFqIkMPVRbTYIdV3th5iAIZHw5cdFdUbVTx0n+WE9NRZDzCwFKAfLd/J' + 'xevR9RBjlAcU46PVBQ== e=found last=15 s=8 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA1oNlJXlk2E48SmzxjRyuBYGwA1iJOA4hkurfmtSmKls= priv=MC4CAQAwBQYDK2VwBCIEIIYiRBXxij' + 'KkkKfrc/vTdSzLwboBTistMjAeAifnI2b1 msg=hiJEFfGKMqSQp+tz+9N1LMvBugFOKy0yMB4CJ+cjZvUe59xAFclfXuh9CUSR1' + 'THLHu4giYzvI9uzLuys1GlwiQ== sig=yIOvn7LBvnkiNzAtI3/GQln/qIbp0QROREHqxAUFQcxovWCiJkDIE4OlYpRPbzwG6+Cw' + 'zF/zTSAZwvKcnxzhCw== e=found last=15 s=9 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAMyFRGOT27U4hXrLr3CN0WkvNG6yq7duXTxdy4PVjCbQ= priv=MC4CAQAwBQYDK2VwBCIEICSq/dZTvM' + 'jrr8Hg+eN0gK65gxyHlaYUe4r1U1sPihCx msg=JKr91lO8yOuvweD543SArrmDHIeVphR7ivVTWw+KELEQxZOwPb86WVJjBvd/u' + 'kTHdR7DZPo8VcT0l/ry34EHpA== sig=KFmo8ftzXVqSULCUMRUNhlBMfefmy+0VO8UMolvF+UOotV1JwkEEZOcmSyg9EWVKIXOM' + 'B68IfH1K2gXpHQxfAg== e=found last=15 s=10 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAKaDrKtijJqQNTGAs4SjXCDeppFhy/+4hw0EEcP7RDuQ= priv=MC4CAQAwBQYDK2VwBCIEIHvxvxcNZx' + '3ZDWCrYkaKlas9jiasu8iH3H5FwBEIAb7Y msg=e/G/Fw1nHdkNYKtiRoqVqz2OJqy7yIfcfkXAEQgBvtjHAMJR1bUg1qnRH/1Hh' + 'MbrLxLXGyfulx+F8cjJN1esvA== sig=sFTX3iyflKR5m2sR8rP6ewIsjZipzmf++c2JEeaok2Q39Mr6vk+9fjShgLxcFIFFgT23' + '1uefW/NuOaXM55zXBQ== e=found last=15 s=11 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEALXeyps1HGvnry/sfxJFQL74JB4fp364ZLci4sxY20ug= priv=MC4CAQAwBQYDK2VwBCIEIFHTuURvDU' + 'ZMA5MZBkpI0yzpxlUnfiKV/heGDMn252uR msg=RG8NRkwDkxkGSkjTLOnGVSd+IpX+F4YMyfbna5EukDTld5Q1mSeSpmsVMgHyd' + 'YkxP2UoedKRk5SnXRNau3LzDg== sig=Z9dj62fa58/n87NByueSsYTRqIVN4fDrPCboA4gn67LbwKvk+mxqW7q1VhuIbezE/zAq' + 'nR+gSHBcpqULXNIZCg== e=found last=15 s=12 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA6Dcj4MkHU4xBWLKFifU68MFEWCIF6SghDt6IqlLJmyU= priv=MC4CAQAwBQYDK2VwBCIEIGy4Ilmouh' + 'ud5VXi0lORWHwOTQJtH6yqrfMdDKP+l15y msg=HQyj/pdectpV18BNI/oKscXVzA/U3FFazG3VudeNQPaqdYKTDgqj90+w39Ygm' + 'EASEKHAiJFOgBwPCnW9u6nAgA== sig=QEL8y1Mi35lT/oOCeKKpXzl96RA2BBfMLDa0KLiuln4Z2+KR8qchRrIRfXXC9t1H7b2x' + 'mJNxYOuRPwXxQcTgDg== e=found last=15 s=13 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAmRhZw8oEnIrry5Z7Car8nId/RZIktNNM21PhHYcC42w= priv=MC4CAQAwBQYDK2VwBCIEIH/2eGpNDL' + '9bt5u/YX/QdVPgipkSn2M4PKJbCGs6VNsF msg=azpU2wVQq8+ivBND+3koNl2tBg4PS0AH4uwQFxtJBPoh9RpJTfn7GFMyU7FMO' + 'qKFHuTjUCo2HIHvHTWh/axxNQ== sig=lGfSbaVhYfAin+eplZ4CAjyLEmUsjG7osizR3KuCxWTzFlldvUSsW+Gm35xZKMOauRZ+' + 'DkS2WvNTl/N5D6/BAQ== e=found last=15 s=14 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAJOtRlu0L9Bby3Lt6hGKO1ZKBu4ojLFtIsoXYzkqoZ1Q= priv=MC4CAQAwBQYDK2VwBCIEIJPwWgfC2F' + '2+yHHEzn0EnuB1k0u2zf3JFni3uJessp+0 msg=BJ7gdZNLts39yRZ4t7iXrLKftJhRr8cU7oJi6R9tR6HL/5T/Ay6paA99m/5W4' + 'xOvnLXMLYyQMiIKWL19xpwl9Q== sig=XW0K1md1tEmNCBTpGoA3yRCB3Op21iusDK2AjsZNAn1QEv8sU0gfryAMsFcVNKBHfD/1' + 'O/rFhEnIilJCJzxmBQ== e=found last=15 s=15 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAPNyof7w3fkcXoGkxej+pRuOo/lZZl8llz+sFTC533pA= priv=MC4CAQAwBQYDK2VwBCIEIHepITUh/w' + 'U0rOsw+gj0nJDVBOP8NNcfPunnszWuOMD8 msg=9JyQ1QTj/DTXHz7p57M1rjjA/AXTdXJ42Q2agrQ2q6t2/QtKXw38ruzd+Cgn7' + 'BiQh34VobH1nI+U8iNs5Y478Q== sig=AjN4sKm3QzWhPmYxz2JaJnI+Lg8W+k6HisEd1zuUUgYtrN87ZU2WW32tV0kIUD9+BN67' + 'wc5kHxh+8SEPZavrBw== e=found last=15 s=16 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAzkHxJznPU9DJiucv1+2X0i26nE1i0mT/r1nJhYIN7wE= priv=MC4CAQAwBQYDK2VwBCIEILLR9xTLKQ' + 'cYv2OZnMfsv+n5SqJa5negXoPMGnUTYGnr msg=wCqaHgQtGsfUQCmB0podKvnqPDPVffe+VledlvNK+WHilMWzUrhGIJxEOs+B9' + 'irK4Z2GlpeF5tegvEDotsBcgw== sig=PI7Zrpi35BOUYUSJRSLoByUb9qLm/SMmAHsUBqV0ctRDWbTZ8ykBhtVtJ3goYM7J9iF3' + 'shya0vWNN/S9/MJ6Dw== e=found last=15 s=17 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEASGSB0Fn4MOHyAzNSOjsrHujWhMdlF/Y5qUMTUElJ6q0= priv=MC4CAQAwBQYDK2VwBCIEICVS/lslhJ' + 'Xcd8QlVfmCc4pWYQqsLKD99ER6s3sje2i2 msg=cnsPsY/JS6jGU6EGMsR6gXe6J0H4Jl3LZoqzSJNKUmfL/CJ7T+H3Yqhr7FARs' + '1Y3+imigLev/sc4drLSDO3ibw== sig=tJmNH9AY+YoAWCICSnEyaf8fqjM8du3jJRe0EmEtzcdZd6rB3SbW2yQp0wIHClZXd9OO' + 'P1srEvo8zJ74rfGqBA== e=found last=15 s=18 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEABRY1yzmzOJvB7iZubJVuf9F5YDn84009N7E4DrBQoLc= priv=MC4CAQAwBQYDK2VwBCIEIKw/q0wCL6' + 'AyKPnxq1zTPg+TSbhWXcRkhcOqBu3cWZIl msg=8c8ugaw/q0wCL6AyKPnxq1zTPg+TSbhWXcRkhcOqBu3cWZIl1o/ci9DU3ei+A' + '0CkkTz/4GwCWK3rFm882vaGJA== sig=1naAyx2bkm+SE2S8tZ4iybhTm0TuAdjpSb2UzJrSShRSumNODc8/szccFsPYMJua8Fb+' + 'E0jqPHpO0ChRGtrLBQ== e=found last=15 s=19 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAsO6k+vQg7tnj3fZdu6CCQF9CW1s4rvb03pyQBV+2emU= priv=MC4CAQAwBQYDK2VwBCIEIMXKsUH14w' + '6eQ5FZb/QBvsL92Cljl/yJO2wg+phHnhbJ msg=bCD6mEeeFsn6shSIMur/Wm9zCh6elj7Dz433t9O6i6QxXNnrcsPMKiL8o7K3V' + 'iU71Yp0/iy7vhZmVfIJ7MHb1Q== sig=GAyYNfKdvvj5RxuMlAAxk3MIEZ3u2zUCF8MXyWpHp9ncBAsr9kNNm1XdcXkBpE6hEXwo' + '4bT8z22cJ3klL5upAQ== e=found last=15 s=20 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAa8VuSIFUJl5cRE4HESdgHI4Dd7es+GAUUHG/X2Qj738= priv=MC4CAQAwBQYDK2VwBCIEIK9ytpbI9H' + 'QAiPPTRPX+ex7kGQN93JnCSzrYP261js46 msg=O+C+O3R3/iT72dRyGCMVGFjYtyhHr8Q8YIKd2CWG+J5YHK1/d0RnotxKGbQog' + 'PY73Q8yE2/ps+4g+6oiU8fLhg== sig=eIuLHX6OfXEW5V88/1sE8m+wh61ONYtFtY68CvUpKoT8dP/j4xW1SfF0lfqDOQOWswHc' + 'aQhk34QFABAYZaP4Cg== e=found last=15 s=21 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAv8+pvop0Ta7Bp8y6uqmlKQSgxDFz8DFObSvPsLV/OVQ= priv=MC4CAQAwBQYDK2VwBCIEIK65NzFFWA' + '2iSgg7W8Qy2e4//YiGET2D3oKUx8MDjxv9 msg=EqQtaCz7Ph9V7ArIxiQ1o6xGj2TYfKWrz7ilGT6CRKi82qCH64MJ4e6DFcEFq' + 'fno53vN9pcX/LU1lDeCTa65Nw== sig=czDhSbwPDX9AjPRzvpCWk+S1fabUjOKWxYaqw8m5mt2BYLWm/xWuX1U4lCfCoWU5NIcJ' + 'vfXEt4aaSQdU4ZRZAA== e=found last=15 s=22 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAH2FcJ9705I7Sba+UcUq/XA5ArgXz70GE86SlYJsgMB4= priv=MC4CAQAwBQYDK2VwBCIEIHlOyKv+3w' + '8wmLp0eDdLxGlfAxLkfuYRhksoIgQNMI0L msg=kRGWQLpyv/xvN/8bp+Mwl7cexrExDFTUZOHGAS3u3jhBW12JVjBs56nGsSrz3' + 'wRuBLsifJyzZmGSChIdppFJyg== sig=NnC8xpl6ZuWmYOsgoDkQgUOztz+4dOUc0gtUhxC24dXSa+WVWHk0C8QionrtqbQd5NaD' + '1tvhMiMEhu7L7yzRDQ== e=found last=15 s=23 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAhYWF20bn1TJgI9nVojvNLxpCmUU6Bp5vn3lCoQrwWQk= priv=MC4CAQAwBQYDK2VwBCIEIKqmytRA9J' + 'qS+KTTzyoB1QNWBXUUh93QXKzXJsguNt9Q msg=ZuVwdmL4XE5tn3R4jO3MOuXQEMACch5lW/arbCVcwJw/dHSSFDX1IyL1aF4uX' + 'OD3upfBDVcTc6qsz/hYbkAUeA== sig=9ouJrxGKnXE6XoIbENg922fQPIt+JywB2BPxwRsR6OlaqBYStgbRPNf3bb9TeGyLDdYN' + 'LoSf7dZ70/5eBcjiCg== e=found last=15 s=24 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEADbuzqyVmVCtgx7sD8zb9rjdBy3PJJ5f+kad96WVwLXE= priv=MC4CAQAwBQYDK2VwBCIEIKlw0he26z' + 'OG8tEld4PqZQd6EKqdkX3jHDFA8iUTVa+d msg=MQiYzCzXzpuzJAef1LZ/DB6D5cLAoyTxC93ugrpOH+ngfEJ0qsp2VdPqXnYWf' + 'BnhYfNbdskoSh9EOvWEpQo2XA== sig=aw6nmXoLl7mdC2UpBflnvCRrlmy2UsnTZMdYyaB2z7qVOGMAEkLjLQJfV5Xv39GK+udw' + '6idE/2gD1//jqf0hDw== e=found last=15 s=25 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAxtErD4XbST61k3wKl2AzQjn8djblZzhft3AwLDp3EZQ= priv=MC4CAQAwBQYDK2VwBCIEIGtv1M/fbN' + 'uz5mzZ4szo8wc1GG/yrAu0XHgXQ4vlux89 msg=98TeuUi+a2/Uz99s27PmbNnizOjzBzUYb/KsC7RceBdDi+W7Hz3rY+ZcledEX' + '25EvQ+4qE09Rpl0MC5VBmvkZg== sig=5z4FYvwPVgFIjSRH+ZTiznPatOrhV+bhqFXv1rQUKAlnPcMB0YYyOq0hxU+4ql/qwJEI' + 'ydp2YcEHr2qwRl2gDA== e=found last=15 s=26 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEApoWJ5QbgT9EsTYL3UsEcdyMvqzCzO8veSi69u481ztI= priv=MC4CAQAwBQYDK2VwBCIEIPqTbXezzG' + 'pUggAMJv8t+DVNdliF2nxn/2vDnK1X4o1Q msg=ApbV0RdPCmXpAOUADxiDFlpUVnBwv1UBDe9piYzMrJSHncHvaptndLrZs4wFG' + 'd/J2GVHGAFUNc17Ycci+pNtdw== sig=XUcaaMjNU9a2xg+CW+5CZhwu2gTCdM4l6TU/5eX7jlJx5ZXGMXWlMAJlw5ABVf4whhDW' + 'KOqJFp3ocNeWNWqhCQ== e=found last=15 s=27 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAIbYAP3Fo1tK++LG+2eJio8eM8bzBtwOAD0keqkXfOE0= priv=MC4CAQAwBQYDK2VwBCIEIPInJkgkuR' + 'vqRlVGwWtOPAuvi5Iq7V3+Qi5UnQ5tieTx msg=z4CI26cC34QV7Jt3j6R1l6znuFouxGSu81Z52tlVm64SabIXMtxevkTwKZhsA' + 'Xc1KaG1uC/frnddJsrAqcmkVg== sig=LNGRpJSbkSoiqd9qOZLGH5l8/lhArVyrKafzN33eXSNn/ivekiIFFihhsJUuggHsKcO/' + 'FYVGtTumbVexXITdBg== e=found last=15 s=28 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAg9DBLBPolLjiRgg97rbXGtvBgg6rL/Bh7olb8Wrayp4= priv=MC4CAQAwBQYDK2VwBCIEIOM/uW95eF' + 'EFkGFxN/WsaWI9u9WkzWJ8VsgANgosmkvR msg=B1j00+gfooAPuj61aJk6/SiFDhvv3NN0YJrjP7lveXhRBZBhcTf1rGliPbvVp' + 'M1ifFbIADYKLJpL0V9EbSbToA== sig=UDVDheI9R7+eG12Jgmly0MNvcARbzXWdFF63GZ+UfsdkmxjT9dwwRDLyJjq8woS6Q95F' + 'JCRIbFayEgsYUq61DA== e=found last=15 s=29 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEANvRnMLBo6qzQ6VozhEweNezEzJC9OG39Z+++BsZqRYk= priv=MC4CAQAwBQYDK2VwBCIEIMEP/y4Ie3' + 'WP6qNqdGrcOrGMZkJB6gE5gMKHsFlMA2C1 msg=QIUNL4x3zaIeDdZxLa+SlIaEhFQCCTkcGXlYUrFnF0Dk8hcldfJu5QLFoHqym' + '9DZ635m/6pBS/usceli0Syeug== sig=2M4yKpIpuB/EpT0okcwmJRlaI8KgqcciiMBRgZtfhX0f4oByHiTYgO/IuxdtXKyWaOhj' + 'A/F2U5awKuhy0Mx6Dg== e=found last=15 s=30 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAgmokf7oW1H+pFBLS4D4m0AxPQJLyH0QC94GmcEycikA= priv=MC4CAQAwBQYDK2VwBCIEIPlPHSQQH7' + 'iZdC2feUGAYnXcTcZhjBKfHD3jXIC0mkJ9 msg=ddxNxmGMEp8cPeNcgLSaQn2oXrcT7wQkwsJlZ4tXgrw11lvBbDGR+T5b7e6PG' + '33dPpkezlPbL/H6Aj9TTmS+eg== sig=hLyXjs32r67cou3mo08c/ZXxsnk5tEMIiePjPEFEtxRIEM7YL0IlhmKAiKzTWX7+1+2H' + 'izWxp4TMIQls+cCKAg== e=found last=15 s=31 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA3t3wHEsYYdgKhp2i0HEW1Fcnt5pYBPpTsrGfddK8RMo= priv=MC4CAQAwBQYDK2VwBCIEIHxwN3rm97' + 'wsulvTSWKpfhq/uk5SPGaRuaO//7n4Y4Cm msg=eub3vCy6W9NJYql+Gr+6TlI8ZpG5o7//ufhjgKbqRqtx5gCkF14PaXUe8DBs+' + 'oEHQ7Lb8hHMCNonvXfsiHfbFA== sig=FujuTlPyuZ6ye+N/1+y9jbNJjihFCS2HHGNIQPBLHy/a5JQ/ma2iEu1dQRvy/9X8ApaR' + 'KV0+xOsmlk0Zg5FQDA== e=found last=15 s=32 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEA/gy2n68UztL4x3epQEPIklfOMK9t6k0Hg06V+igrrJ8= priv=MC4CAQAwBQYDK2VwBCIEILh/oxGMBq' + 'oe9T+9hnzuP+pa406OzjenfQd2rSQmazvU msg=EYwGqh71P72GfO4/6lrjTo7ON6d9B3atJCZrO9SyM3u95m2kRQkhPtB8EPrrb' + 'N+sSAY5v2+vMXwb+Hn0mAYjTw== sig=zO+8encogwn/U4SF91n//S/wNXR3pZrhU50v3nVy8eprI6AKcGF4T131Rk2bmrXdmtt6' + 'CaLkKQ9UP2GPohDfCg== e=found last=15 s=33 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAHtYhM7lFrRHW9FqjuSEdDZ1tctjede+MoV0R1UMtVVg= priv=MC4CAQAwBQYDK2VwBCIEIJD6PKp3Mu' + 'lK/B/Np+Cdu+Cfo6x2EPkJJliRnj1G9xs/ msg=Q/p5WuG23JyPgshQbo5YGam23fQ5OVqjC0fCzYVXRw+C9vDQdLODe5D6PKp3M' + 'ulK/B/Np+Cdu+Cfo6x2EPkJJg== sig=t4XSeew/w5x52oghg7VR7yDP6cP2JkP+1qCbuYJyUNW/lmNKD16Tk3SWktl4o3HzmpQe' + 'wS3lxx1vR2pKhkPqAw== e=found last=15 s=34 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAEI/536MsgF7aZ9O6hLaT2cGEwCIQRajWmvxE+iv+5Ig= priv=MC4CAQAwBQYDK2VwBCIEIE5+N8mBMq' + 'bcslWpsFiYUJLEbnKC1CZgwnql5scPhVqA msg=1CZgwnql5scPhVqAJy5QN89FfioiZlPgPcwVjCM2AgM5Frk3eACOherjcVcSU' + 'Sth7u2NWh3IJGkOy+UgE6g3/w== sig=9iS9EP9mkQOoxQoGzcznIChrPQGdAA763KQjwnN5k4HmVBX/abYK5XIk6H+sfZ88Qq7V' + 'OFy8c1H1CwYb465AAg== e=found last=15 s=35 in subShifted_NP'),
+    ('pub=MCowBQYDK2VwAyEAvdP5ffItF2siN+QBywHeCpXDFhjxK7SZwT2MfjSoipU= priv=MC4CAQAwBQYDK2VwBCIEINx5YWaFb5' + '7Vnoqc93w5yK8TSWlY+7GEYVjpc2WkiPI/ msg=Ggwp5bmATPmRhoheAaYfJTYxkSrIXYcSTqxi3HlhZoVvntWeipz3fDnIrxNJa' + 'Vj7sYRhWOlzZaSI8j9oTJ1ygA== sig=c5HoX+KDVG2wM7o0o4dKJUy/zczPaKDUcnWhsmP3d6evqfDbRNAQpLopFdO9dyfuEv1H' + '1gn+qLQUVvZcuwLDDw== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAhPw0vNPFREOs5U1MkD0yCWZ3WCOmwVSvN2jF1Oizqbk= priv=MC4CAQAwBQYDK2VwBCIEIP80+hG+p3' + 'eZq1Ez2fIwZVisdXlokktg+bLNtBeM/GQA msg=2I3ilxrJP/fye0bwPSNTluAceuuI6hS1a9t7J9YSlIX9WOwvrnoz2BUKVPkLp' + 'HmyEK7JHMDttj4l6BQiCOl//w== sig=kp9BeH0HbGR8wWV5vERw/tZtGHuYdpNvcUO7fyzEAp+avoeJFptyh7jzuvic/lcH8+W4' + '3kjvq2wn7t+Y4QOCAA== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEA6yB65NH24xZ3gPJpAf2oZiobm/CDOsW2mTA5NYHiu9Q= priv=MC4CAQAwBQYDK2VwBCIEIA8QPr2HS5' + 'Ph1RitdsIwIn6rAvIhxGzrI0iMNTQXdaOK msg=xaumAcR/MN99ugA1y5nJ/KZ89v2ubNtaOKMr85InQXbcd6tQUDJKVgi1s5E00' + 'FUzZNayymWz0FIZmpuB+B3D6A== sig=2Hh82APLUonf07pjWJPbqNkIvH0FKaGuqR6uZy0SolDLBOQRUUo19t6txaNjafroKvKi' + 'vxp4BJZK//UZANV/AQ== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAjzPeoBYWUh6lK8tL5zvJMe3quOc9DHDHqjaqmlQ9eCs= priv=MC4CAQAwBQYDK2VwBCIEIM/KKNbVtH' + 'GuvVjVRndMVx+uGHioSJfRTLV3mMT/qs0O msg=xoQTj8hSoCBUbsW5fls1TN4WIBm8+r9Q4dG8neWlAU5D0pb5V7PzbBUFJWeMN' + '0nvqEZA2EOlmOckFJwvw4kbvg== sig=RvTiLTOBLVlUPXgblZ51/UkOE6Yen7x4M02mxNRnKQIQvRW6Xy3qME2Z0Am2zJnQUl5N' + 'zmX7bwYSxgxpmI88AQ== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAOMqNF1zplUOboWpKGEScst68qibTpF7Ty7VY/uEvaNU= priv=MC4CAQAwBQYDK2VwBCIEIJJEH78Xa9' + '7lbOZ9O6bgZKJcrcU3smco0u0Px5GkGxTV msg=4RytsCg8AEt67XM/kkQfvxdr3uVs5n07puBkolytxTeyZyjS7Q/HkaQbFNVoj' + 'P80jljxWzNLoGaGN7N1kr2qSg== sig=f9A3HtPy45UhJ3k5woskx1PE0Gkk9Lb3WJdwYlWLkvPR5U3U3twjEF7C7yTQ/GqOHDQP' + 'n/oRZjkr6BAezbrQAQ== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAn2s7D0uz1lKQ3j1cJQXWJEJ0Wh8kfI024cBGrsoWS94= priv=MC4CAQAwBQYDK2VwBCIEIPvpiAgD9M' + 'jVzjq4GBEEvyJRG7qBtOA8LhyL8TxM9zxh msg=TPc8YdLsCNMm5JB7iuu+8qy8DRSFi0fGLIdlMQxyHKr52bnlHDKvhOXdJfm4M' + 'Ni2nwnHKety6zzPKhdsz5N0AA== sig=k/NSvGBfyOC9cFSGbMk4VRRZAD26DZoYFTfPI1nqv26HRtzmyOPRUt1XUKVdlPCk9BWJ' + 'KxMIOViE5fubQtr9Cg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEARcA9TGMLvA1xCpTlIBTFBqX4BmnojWpbQrHqeuGtTUQ= priv=MC4CAQAwBQYDK2VwBCIEIFcykuAmQT' + 'TxkQFc39T6K/esqAVIzjf4BvD9w4Ahh1uh msg=K/esqAVIzjf4BvD9w4Ahh1uhbFnf3RWoWc5DBj2U1Wlr2XkEMiCIphy2Vb+nV' + 'G60fxCc0imaymlJcl3DaK1FIQ== sig=T2XgkyPeNG3Bcmss6YCOLZnVZmzP1bB/traUHj3kFdLx/auEXgaF9U0q2aELe2gejVOX' + '4SODJ9KBHKcwNZMcBg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAEFWkTeyURoIn6Fdnr9db6WjB/JI4C1a93wJNXpE+n2g= priv=MC4CAQAwBQYDK2VwBCIEIJer93jUjX' + 'CZbxF8P9jpHcFh5/ERuJ9y1K0GUsg1rpA3 msg=Wi4GxXDWlO0X6fW7ceLYt9zsTRM/RODJRDt4+8iOqvV3Llhdd9bPhSNUX+5tU' + 'RNUCmoimd3zQHNB7/fqwbmYhg== sig=bpus92mglDkcS+4xjQ+Ss5Ft1CwwIpULew8VxDr96oZkn7fUKd/qzvWB3bpPRLVZvDbn' + '62DC/LnB+lXSy+MCBg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAIcToYs2BkuC7McB+khCggsYBK/z+V6bESJv1eUURkUw= priv=MC4CAQAwBQYDK2VwBCIEIMJVSyDIMf' + '6tDX+3WusTQgjWUh0fHmZF6iW7u6u+gE5b msg=t1rrE0II1lIdHx5mReolu7urvoBOWzYTMa6Os5soq/7Qpkx03upSddEsdODq6' + 'HCFlmQFnFbohWP41Uz2lgBTtw== sig=a9y3fKIcCCZHwj7X/2MEewgV/Xv4pB9Zz8uXbEBaIGv1v07OfhOXpxxgyNVDmf4Vt82Z' + 'Mz5i1W3TOnf9vaw2AQ== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEA+WkpaGYP1Cvz8vBKHJx04KpK9zvI8I2hTJWaGnDJE7M= priv=MC4CAQAwBQYDK2VwBCIEIET7Foh0nu' + 'hOMyT4pwuSE6YCWA54Xvec6sh+9uc2ePGW msg=USWDYo45MeZ+xhVE+xaIdJ7oTjMk+KcLkhOmAlgOeF73nOrIfvbnNnjxlt9BB' + 'gMDMjVHespfGh1nnVWNl5Smfg== sig=uC/wtzmLNI2UbMX9XT1oUMULIUjxNyVyqlrXkoqNg2MqrE6E5Gcz7DkhBQ/Ol/oTZOYX' + 'PFguXpWGqhcmPdmDAw== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEA0at7YQAiYd3RvIpYZeHUsNUbyD4rUIABSZyqSPPnXjY= priv=MC4CAQAwBQYDK2VwBCIEIExle8MpAA' + '8rxusxmLjsBOb2+W1ICTbAKlCkmFX7qcNr msg=6l+NN69pJyLPhPHmX1oFxraO8QIpuDmQ+Uxle8MpAA8rxusxmLjsBOb2+W1IC' + 'TbAKlCkmFX7qcNrgJ31OoRIqQ== sig=zl36421pKuQEwy4ntSijob95iSlcogE3m9IfgmXLAM48qcj0949WG0ntxb2Dl586oHWB' + 'xzmeoFuq6fzUzQtQBg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAE0fGq8+sf4e5ickaVLPbQPgHBO+ZeaWtpK2higapw1M= priv=MC4CAQAwBQYDK2VwBCIEIG/IPZ4pME' + 'kp6savNxRiP6quWDYQK+QphYwNjnkLYZBL msg=q2P8BeCMaOU0+waVNHyZYzyqlWE/2blKeAbHVkpa/Jm/51KUZapuwDEubITmJ' + '9Z6RMenYnNe8sLIFUkrfKWkkA== sig=ZjKYto3cRI88GehOVcKB2QNkv8IdXZ3h+HtCHIvhF7GgpYjWARP9VI8zsUJW33uVo1Kp' + '+5++TKqY/34+SqLUCA== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAFMeh30CrxMMFUGihtrh1E7r2A50qRb8Jxm/1Z8peFMA= priv=MC4CAQAwBQYDK2VwBCIEIFFX9MW5r0' + 'TrFR+GweEl0UA2ecEVXapCRsJPcEPk+Xf2 msg=qpfc0g0cQGsgzFtZILynE9onlFFX9MW5r0TrFR+GweEl0UA2ecEVXapCRsJPc' + 'EPk+Xf2nFZ2cbWMkyFX5Ic6FQ== sig=bCT+JnzEdUpa6x0K+FnAPa1fnUhy4pmK5EAYs7ORaGs45qp62ENQUWj1BMn8ZpFAfUYV' + '1tuGBhhua73MXB3jBA== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAgKIrpZiZVMIQ3DmybKkOaOWEKOlkijaFC9tSdgZ+6mI= priv=MC4CAQAwBQYDK2VwBCIEIINS33Irrr' + 'EnxMCTDJEQ//g6WKEyEuCwVzp5uXoqQDmh msg=H2fmoXw40oSrSe3Fcx/YGCYR/RvtoE0xqxRalfjlWQDMmzi6Bog0of2dUZlmx' + 'I9iWaAsyrtIyVKwRN5Ujbxocg== sig=dwHERSdPaxQryZmDLnWub8m66a8wxZPuCuTKkOPmwZ5IuYWUl63iD3s+aoJfiJk8+xAl' + 'KlDtPUnGx+6fOzV4AQ== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAVTk5x6SQaQHh7UH7zfBGl6U4+Txb+pOxqmPOIo8PyGI= priv=MC4CAQAwBQYDK2VwBCIEIJtw2Gsoqh' + 'wCCtOgUtYXiYpUyWzo2XP9MDakoofhTCOk msg=AgrToFLWF4mKVMls6Nlz/TA2pKKH4UwjpBHkfNY7KkqtW18eIhEu1M7D+Anhd' + 'fnsQVkDczHBzFtuPgwaZ9xc7A== sig=ZPB3kbWf3G0ySlhg6Bvbxh4S28WvRAELGYf/v/T/hAwgMQ6Oq3pPiY93KUvDEe+80AAV' + 'InG37+dGKVT9RbioCg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAc4H7Rb8wDjfvj94WftKwolGe9mwglkEpUkiLR+Jty6A= priv=MC4CAQAwBQYDK2VwBCIEIKvCOCYg1Q' + '7U4+fgMnRRYn3Lmht/xc55aM/WtBF4ZsJh msg=uaJtcfOWBY0KxeIXXV2vWCUB4vIcUC8TeEzWWWniuImpUU7wPZHsFWnf4XiUJ' + 'ar5+Am19TjeUfYIQK2QZh9dxg== sig=DBW8lV47/jBOCGxQUBdi2QUwkx6KeXFgcRsChQffiMhm/Unrqzk5zvhWbXPrSsinG9wy' + 'TmUz/h2M/GeCiirnAg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAxXas85OYbLLHbFEE9nW61ip2ov4wzmMm2zkUlsHhyOU= priv=MC4CAQAwBQYDK2VwBCIEIKarC8sbbY' + 'xXbGTaWwJjCxMX6MCKbDiIfdvCKblsmQd6 msg=E3zm8Nva7r1TcFRgXVOBVYxhG/3b822pblFZEdf03s4dbUqjx1qdA3tLUczSs' + '7NuNmY+6t1Vnp3q70OYUtJTNg== sig=W5ItndbbkVnAWv3xoM/Bj7SvcQC4lErIKKRVd/d7jT090BREWsANppGc82oj17nshxVi' + 'xxr+BxRRv36+a4IOAA== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEAlKpznUGJM4bQhLgPau5E6MQvqQnBCcvofDwkU5QhlRU= priv=MC4CAQAwBQYDK2VwBCIEICumaRhwUV' + 'QTUkSBfw5WtTNVajg+0w8HBRWZOB2FXDgi msg=7UkYLhNEfWfsBQDQVsYNNFaDDFRd1LNbyM9VNtNOe9ctGtYrpmkYcFFUE1JEg' + 'X8OVrUzVWo4PtMPBwUVmTgdhQ== sig=XA8nmvcN7v3nHMnSTtRo5Yy516C/ba0+gFdHGBj/tQ241veNGhQSB1lX8iHHtMnuEf+g' + '9MebNCooXTTv4dbSAg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEANg3t8r6SaUHzAkC3bSq3njFriUtFxo/HNr9f3cJjrtA= priv=MC4CAQAwBQYDK2VwBCIEIGpGaYZfVH' + 'akKwQqYoptONNYpQKvYIwvL8Vyj8vg3YuM msg=aYZfVHakKwQqYoptONNYpQKvYIwvL8Vyj8vg3YuMN6uGjDsal51/W8o7BK0ns' + 'SMc/XuQzHFgSonaZS50YAl76g== sig=XRPIQLqcqeZYZtd0OV/ugRKYT1aZKJmwS1wbIxRHjEdTgOSvLRexlEYh8xPrspcfPXh8' + 'FM6E70PSrk4+sGwvCg== e=infinite loop regression'),
+    ('pub=MCowBQYDK2VwAyEA69MJYVrwsGt5DugorT6VD7zSG3WQ4yOqXiRjUOP3LCQ= priv=MC4CAQAwBQYDK2VwBCIEIL2PFNE+QW' + 'Z53Ah9hoHeuEEEbw0Ew2ypwWts3l02nNOP msg=UG8S6ZNCvY8U0T5BZnncCH2Ggd64QQRvDQTDbKnBa2zeXTac04/SEviN0EcPR' + 'MD4b6uP03S9WDO2T2MYPkoXMw== sig=1Dgxn3qUqRaC+CMASAT16JtFBWL8qoF8SEBbQL8YYM/SPzN72c/7EbKCIUkdgrUD4iHV' + 'c2IHLCjHDeQPbSqnAw== e=infinite loop regression')
+  );
+var
+  I: Int32;
+  LTest: String;
+  LParts: TCryptoLibStringArray;
+  LX509PubBytes, LX509PrivBytes, LMsg, LSig, LPubBytes, LPrivBytes: TBytes;
+  LPub: IEd25519PublicKeyParameters;
+  LPriv: IEd25519PrivateKeyParameters;
+  LPubDerived: IEd25519PublicKeyParameters;
+  LSigner: ISigner;
+  LSigDerived: TBytes;
+  LError: String;
+begin
+  for I := 0 to TestCaseCount - 1 do
+  begin
+    LTest := TestCases[I];
+    LParts := TStringUtilities.SplitString(LTest, ' ', 5);
+    if System.Length(LParts) <> 5 then
+      Fail('invalid test case format; expected five parts (pub=, priv=, msg=, sig=, e=), but got ' +
+        LTest);
+    if not TStringUtilities.StartsWith(LParts[0], 'pub=') or
+      not TStringUtilities.StartsWith(LParts[1], 'priv=') or
+      not TStringUtilities.StartsWith(LParts[2], 'msg=') or
+      not TStringUtilities.StartsWith(LParts[3], 'sig=') or
+      not TStringUtilities.StartsWith(LParts[4], 'e=') then
+      Fail('invalid test case format; expected five parts (pub=, priv=, msg=, sig=, e=), but got ' +
+        LTest);
+
+    LX509PubBytes := DecodeBase64(TStringUtilities.Substring(LParts[0], 5));
+    LX509PrivBytes := DecodeBase64(TStringUtilities.Substring(LParts[1], 6));
+    LMsg := DecodeBase64(TStringUtilities.Substring(LParts[2], 5));
+    LSig := DecodeBase64(TStringUtilities.Substring(LParts[3], 5));
+    LError := TStringUtilities.Substring(LParts[4], 3);
+
+    if System.Length(LX509PubBytes) < 12 then
+      Fail('x509PubBytes too short');
+    if System.Length(LX509PrivBytes) < 16 then
+      Fail('x509PrivBytes too short');
+    LPubBytes := TArrayUtilities.CopyOfRange<Byte>(LX509PubBytes, 12,
+      System.Length(LX509PubBytes));
+    LPrivBytes := TArrayUtilities.CopyOfRange<Byte>(LX509PrivBytes, 16,
+      System.Length(LX509PrivBytes));
+
+    LPub := TEd25519PublicKeyParameters.Create(LPubBytes);
+    LPriv := TEd25519PrivateKeyParameters.Create(LPrivBytes);
+    LPubDerived := LPriv.GeneratePublicKey();
+
+    if not AreEqual(LPubDerived.GetEncoded(), LPub.GetEncoded()) then
+      Fail('different derived public keys; expected=' + EncodeHex(LPub.GetEncoded()) +
+        ' derived=' + EncodeHex(LPubDerived.GetEncoded()));
+
+    LSigner := TEd25519Signer.Create();
+    LSigner.Init(True, LPriv as ICipherParameters);
+    LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+    LSigDerived := LSigner.GenerateSignature();
+
+    if not AreEqual(LSigDerived, LSig) then
+      Fail('different signatures of message; expected=' + EncodeHex(LSig) +
+        ' actual=' + EncodeHex(LSigDerived));
+
+    LSigner.Init(False, LPub as ICipherParameters);
+    LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+    CheckTrue(LSigner.VerifySignature(LSig),
+      'signature verification failed for test vector: ' + LError);
+  end;
+end;
 
-  DoEd25519Test(2, TEd25519SignerAlgorithm.Ed25519,
-    '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c',
-    '3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c', '72',
-    '92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c0072');
-
-  DoEd25519Test(3, TEd25519SignerAlgorithm.Ed25519,
-    'c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025',
-    'fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025', 'af82',
-    '6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40aaf82');
-
-  DoEd25519Test(4, TEd25519SignerAlgorithm.Ed25519,
-    '0d4a05b07352a5436e180356da0ae6efa0345ff7fb1572575772e8005ed978e9e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057',
-    'e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057',
-    'cbc77b', 'd9868d52c2bebce5f3fa5a79891970f309cb6591e3e1702a70276fa97c24b3a8e58606c38c9758529da50ee31b8219cba45271c689afa60b0ea26c99db19b00ccbc77b');
-
-  DoEd25519Test(5, TEd25519SignerAlgorithm.Ed25519,
-    '6df9340c138cc188b5fe4464ebaa3f7fc206a2d55c3434707e74c9fc04e20ebbc0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7',
-    'c0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7',
-    '5f4c8989',
-    '124f6fc6b0d100842769e71bd530664d888df8507df6c56dedfdb509aeb93416e26b918d38aa06305df3095697c18b2aa832eaa52edc0ae49fbae5a85e150c075f4c8989');
+procedure TTestEd25519HigherLevel.TestRegressionInfiniteLoop;
+begin
+  TestRegressionInfiniteLoopImpl();
 end;
 
 initialization
 
-// Register any test cases with the test runner
-
 {$IFDEF FPC}
   RegisterTest(TTestEd25519HigherLevel);
 {$ELSE}

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

@@ -44,8 +44,6 @@ uses
   ClpISecP521R1Custom,
   ClpSecT283Custom,
   ClpISecT283Custom,
-  ClpCurve25519Custom,
-  ClpICurve25519Custom,
   ClpIECC,
   ClpIAsn1Objects,
   ClpScalarSplitParameters,
@@ -124,22 +122,6 @@ type
     // */
     class property Names: TCryptoLibStringArray read GetNames;
 
-  type
-
-    /// <summary>
-    /// curve25519
-    /// </summary>
-    TCurve25519Holder = class sealed(TX9ECParametersHolder,
-      IX9ECParametersHolder)
-
-    strict protected
-      function CreateParameters(): IX9ECParameters; override;
-
-    public
-      class function Instance(): IX9ECParametersHolder; static;
-
-    end;
-
   type
 
     /// <summary>
@@ -366,9 +348,6 @@ begin
 
   Fnames := TList<String>.Create();
 
-  DefineCurveWithOid('curve25519', TCryptlibObjectIdentifiers.Curvey25519,
-    TCurve25519Holder.Instance);
-
   DefineCurveWithOid('secp256k1', TSecObjectIdentifiers.SecP256k1,
     TSecP256K1Holder.Instance);
 
@@ -391,38 +370,6 @@ begin
   DefineCurveAlias('P-521', TSecObjectIdentifiers.SecP521r1);
 end;
 
-{ TCustomNamedCurves.TCurve25519Holder }
-
-function TCustomNamedCurves.TCurve25519Holder.CreateParameters: IX9ECParameters;
-var
-  curve: IECCurve;
-  G: IX9ECPoint;
-  S: TCryptoLibByteArray;
-begin
-  S := Nil;
-  curve := ConfigureCurve(TCurve25519.Create() as ICurve25519);
-
-  { *
-    * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form
-    * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3).
-    *
-    * The Curve25519 paper doesn't say which of the two possible y values the base
-    * point has. The choice here is guided by language in the Ed25519 paper.
-    *
-    * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14)
-    * }
-  G := ConfigureBasepoint(curve,
-    '042AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9');
-
-  result := TX9ECParameters.Create(curve, G, curve.Order, curve.Cofactor, S);
-end;
-
-class function TCustomNamedCurves.TCurve25519Holder.Instance
-  : IX9ECParametersHolder;
-begin
-  result := TCurve25519Holder.Create();
-end;
-
 { TCustomNamedCurves.TSecP256K1Holder }
 
 function TCustomNamedCurves.TSecP256K1Holder.CreateParameters: IX9ECParameters;

+ 10 - 13
CryptoLib/src/Crypto/Generators/ClpEd25519KeyPairGenerator.pas

@@ -22,7 +22,6 @@ unit ClpEd25519KeyPairGenerator;
 interface
 
 uses
-  ClpIEd25519,
   ClpAsymmetricCipherKeyPair,
   ClpIEd25519KeyPairGenerator,
   ClpIEd25519PrivateKeyParameters,
@@ -40,11 +39,10 @@ type
   strict private
   var
     FRandom: ISecureRandom;
-    FEd25519Instance: IEd25519;
 
   public
-    constructor Create(const Ed25519Instance: IEd25519);
-    procedure Init(const parameters: IKeyGenerationParameters);
+    constructor Create();
+    procedure Init(const AParameters: IKeyGenerationParameters);
 
     function GenerateKeyPair(): IAsymmetricCipherKeyPair;
 
@@ -54,26 +52,25 @@ implementation
 
 { TEd25519KeyPairGenerator }
 
-constructor TEd25519KeyPairGenerator.Create(const Ed25519Instance: IEd25519);
+constructor TEd25519KeyPairGenerator.Create();
 begin
   inherited Create();
-  FEd25519Instance := Ed25519Instance;
 end;
 
 function TEd25519KeyPairGenerator.GenerateKeyPair: IAsymmetricCipherKeyPair;
 var
-  privateKey: IEd25519PrivateKeyParameters;
-  publicKey: IEd25519PublicKeyParameters;
+  LPrivateKey: IEd25519PrivateKeyParameters;
+  LPublicKey: IEd25519PublicKeyParameters;
 begin
-  privateKey := TEd25519PrivateKeyParameters.Create(FEd25519Instance, FRandom);
-  publicKey := privateKey.GeneratePublicKey();
-  result := TAsymmetricCipherKeyPair.Create(publicKey, privateKey);
+  LPrivateKey := TEd25519PrivateKeyParameters.Create(FRandom);
+  LPublicKey := LPrivateKey.GeneratePublicKey();
+  Result := TAsymmetricCipherKeyPair.Create(LPublicKey, LPrivateKey);
 end;
 
-procedure TEd25519KeyPairGenerator.Init(const parameters
+procedure TEd25519KeyPairGenerator.Init(const AParameters
   : IKeyGenerationParameters);
 begin
-  FRandom := parameters.random;
+  FRandom := AParameters.Random;
 end;
 
 end.

+ 1 - 3
CryptoLib/src/Crypto/Generators/ClpGeneratorUtilities.pas

@@ -30,7 +30,6 @@ uses
   ClpCryptoLibTypes,
   ClpDsaKeyPairGenerator,
   ClpECKeyPairGenerator,
-  ClpEd25519,
   ClpEd25519KeyPairGenerator,
   ClpEdECObjectIdentifiers,
   ClpDHKeyPairGenerator,
@@ -40,7 +39,6 @@ uses
   ClpIDsaKeyPairGenerator,
   ClpIDHKeyPairGenerator,
   ClpIECKeyPairGenerator,
-  ClpIEd25519,
   ClpIEd25519KeyPairGenerator,
   ClpIRsaKeyPairGenerator,
   ClpIX25519KeyPairGenerator,
@@ -385,7 +383,7 @@ begin
   end;
   if LCanonicalName = 'Ed25519' then
   begin
-    Result := TEd25519KeyPairGenerator.Create(TEd25519.Create() as IEd25519) as IEd25519KeyPairGenerator;
+    Result := TEd25519KeyPairGenerator.Create() as IEd25519KeyPairGenerator;
     Exit;
   end;
   if LCanonicalName = 'X25519' then

+ 100 - 98
CryptoLib/src/Crypto/Parameters/ClpEd25519PrivateKeyParameters.pas

@@ -24,7 +24,6 @@ interface
 uses
   Classes,
   ClpEd25519,
-  ClpIEd25519,
   ClpISecureRandom,
   ClpAsymmetricKeyParameter,
   ClpIEd25519PrivateKeyParameters,
@@ -35,10 +34,13 @@ uses
   ClpCryptoLibTypes;
 
 resourcestring
-  SEOFInPrivateKey = 'EOF encountered in middle of %s private key';
+  SEOFInPrivateKey = 'EOF encountered in middle of Ed25519 private key';
   SUnsupportedAlgorithm = 'Unsupported Algorithm';
-  SCtxNotNil = 'Ctx must be Nil for %s Algorithm';
-  SMsgLen = 'MsgLen must be Equal to "PreHashSize" for %sph Algorithm';
+  SCtxNotNil = 'Ctx must be Nil for Ed25519 Algorithm';
+  SCtxNil = 'Ctx must not be Nil for Ed25519ctx/Ed25519ph';
+  SCtxLength = 'Ctx length must be at most 255';
+  SMsgLen = 'MsgLen must be Equal to PreHashSize for Ed25519ph Algorithm';
+  SMustHaveLengthKeySize = 'must have length %d';
 
 type
   TEd25519PrivateKeyParameters = class sealed(TAsymmetricKeyParameter,
@@ -47,7 +49,7 @@ type
   strict private
   var
     FData: TCryptoLibByteArray;
-    FEd25519Instance: IEd25519;
+    FCachedPublicKey: IEd25519PublicKeyParameters;
 
   public
 
@@ -55,23 +57,20 @@ type
     KeySize = Int32(TEd25519.SecretKeySize);
     SignatureSize = Int32(TEd25519.SignatureSize);
 
-    constructor Create(const Ed25519Instance: IEd25519;
-      const random: ISecureRandom); overload;
-    constructor Create(const Ed25519Instance: IEd25519;
-      const buf: TCryptoLibByteArray; off: Int32); overload;
-    constructor Create(const Ed25519Instance: IEd25519;
-      input: TStream); overload;
+    constructor Create(const ARandom: ISecureRandom); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray; AOff: Int32); overload;
+    constructor Create(AInput: TStream); overload;
 
-    procedure Encode(const buf: TCryptoLibByteArray; off: Int32); inline;
+    procedure Encode(const ABuf: TCryptoLibByteArray; AOff: Int32); inline;
     function GetEncoded(): TCryptoLibByteArray; inline;
-    function GeneratePublicKey(): IEd25519PublicKeyParameters; inline;
+    function GeneratePublicKey(): IEd25519PublicKeyParameters;
 
-    procedure Sign(algorithm: TEd25519.TEd25519Algorithm;
-      const publicKey: IEd25519PublicKeyParameters;
-      const ctx, msg: TCryptoLibByteArray; msgOff, msgLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32);
+    procedure Sign(AAlgorithm: TEd25519.TAlgorithm;
+      const ACtx, AMsg: TCryptoLibByteArray; AMsgOff, AMsgLen: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32);
 
-    function Equals(const other: IEd25519PrivateKeyParameters): Boolean;
+    function Equals(const AOther: IEd25519PrivateKeyParameters): Boolean;
       reintroduce; overload;
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -85,133 +84,136 @@ implementation
 function TEd25519PrivateKeyParameters.GeneratePublicKey
   : IEd25519PublicKeyParameters;
 var
-  publicKey: TCryptoLibByteArray;
+  LPoint: TEd25519.IPublicPoint;
 begin
-  System.SetLength(publicKey, TEd25519.PublicKeySize);
-  FEd25519Instance.GeneratePublicKey(FData, 0, publicKey, 0);
-  result := TEd25519PublicKeyParameters.Create(publicKey, 0);
+  if FCachedPublicKey = nil then
+  begin
+    LPoint := TEd25519.GeneratePublicKey(FData, 0);
+    FCachedPublicKey := TEd25519PublicKeyParameters.Create(LPoint);
+  end;
+  Result := FCachedPublicKey;
 end;
 
 function TEd25519PrivateKeyParameters.GetEncoded: TCryptoLibByteArray;
 begin
-  result := System.Copy(FData);
+  Result := System.Copy(FData);
 end;
 
-constructor TEd25519PrivateKeyParameters.Create(const Ed25519Instance: IEd25519;
-  const random: ISecureRandom);
+constructor TEd25519PrivateKeyParameters.Create(const ARandom: ISecureRandom);
+var
+  LEd25519: TEd25519;
 begin
-  Inherited Create(true);
+  Inherited Create(True);
   System.SetLength(FData, KeySize);
-  FEd25519Instance := Ed25519Instance;
-  FEd25519Instance.GeneratePrivateKey(random, FData);
+  LEd25519 := TEd25519.Create();
+  try
+    LEd25519.GeneratePrivateKey(ARandom, FData);
+  finally
+    LEd25519.Free;
+  end;
 end;
 
-constructor TEd25519PrivateKeyParameters.Create(const Ed25519Instance: IEd25519;
-  const buf: TCryptoLibByteArray; off: Int32);
+constructor TEd25519PrivateKeyParameters.Create(const ABuf: TCryptoLibByteArray);
 begin
-  Inherited Create(true);
+  if System.Length(ABuf) <> KeySize then
+    raise EArgumentCryptoLibException.CreateResFmt(@SMustHaveLengthKeySize,
+      [KeySize]);
+  Create(ABuf, 0);
+end;
+
+constructor TEd25519PrivateKeyParameters.Create(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
+begin
+  Inherited Create(True);
   System.SetLength(FData, KeySize);
-  FEd25519Instance := Ed25519Instance;
-  System.Move(buf[off], FData[0], KeySize * System.SizeOf(Byte));
+  System.Move(ABuf[AOff], FData[0], KeySize * System.SizeOf(Byte));
 end;
 
-constructor TEd25519PrivateKeyParameters.Create(const Ed25519Instance: IEd25519;
-  input: TStream);
+constructor TEd25519PrivateKeyParameters.Create(AInput: TStream);
 begin
-  Inherited Create(true);
+  Inherited Create(True);
   System.SetLength(FData, KeySize);
-  FEd25519Instance := Ed25519Instance;
-  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
-  begin
-    raise EEndOfStreamCryptoLibException.CreateResFmt(@SEOFInPrivateKey,
-      [FEd25519Instance.AlgorithmName]);
-  end;
+  if KeySize <> TStreamUtilities.ReadFully(AInput, FData) then
+    raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPrivateKey);
 end;
 
-procedure TEd25519PrivateKeyParameters.Encode(const buf: TCryptoLibByteArray;
-  off: Int32);
+procedure TEd25519PrivateKeyParameters.Encode(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
 begin
-  System.Move(FData[0], buf[off], KeySize * System.SizeOf(Byte));
+  System.Move(FData[0], ABuf[AOff], KeySize * System.SizeOf(Byte));
 end;
 
-function TEd25519PrivateKeyParameters.Equals(const other
+function TEd25519PrivateKeyParameters.Equals(const AOther
   : IEd25519PrivateKeyParameters): Boolean;
 begin
-  if (other = Self as IEd25519PrivateKeyParameters) then
+  if (AOther = Self as IEd25519PrivateKeyParameters) then
   begin
-    result := true;
+    Result := True;
     Exit;
   end;
 
-  if (other = Nil) then
+  if (AOther = nil) then
   begin
-    result := false;
+    Result := False;
     Exit;
   end;
-  result := TArrayUtilities.FixedTimeEquals(FData, other.GetEncoded())
+  Result := TArrayUtilities.FixedTimeEquals(FData, AOther.GetEncoded());
 end;
 
 function TEd25519PrivateKeyParameters.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}
 begin
-  result := TArrayUtilities.GetArrayHashCode(FData);
+  Result := TArrayUtilities.GetArrayHashCode(FData);
 end;
 
-procedure TEd25519PrivateKeyParameters.Sign
-  (algorithm: TEd25519.TEd25519Algorithm;
-  const publicKey: IEd25519PublicKeyParameters;
-  const ctx, msg: TCryptoLibByteArray; msgOff, msgLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
+procedure TEd25519PrivateKeyParameters.Sign(AAlgorithm: TEd25519.TAlgorithm;
+  const ACtx, AMsg: TCryptoLibByteArray; AMsgOff, AMsgLen: Int32;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32);
 var
-  pk: TCryptoLibByteArray;
+  LPublicKey: IEd25519PublicKeyParameters;
+  LPk: TCryptoLibByteArray;
+  LEd25519: TEd25519;
 begin
-  System.SetLength(pk, TEd25519.PublicKeySize);
-
-  if (publicKey = Nil) then
-  begin
-    FEd25519Instance.GeneratePublicKey(FData, 0, pk, 0);
-  end
-  else
-  begin
-    publicKey.Encode(pk, 0);
-  end;
-
-  case algorithm of
-    TEd25519.TEd25519Algorithm.Ed25519:
-      begin
-        if (ctx <> Nil) then
+  LPublicKey := GeneratePublicKey();
+  System.SetLength(LPk, TEd25519.PublicKeySize);
+  LPublicKey.Encode(LPk, 0);
+
+  LEd25519 := TEd25519.Create();
+  try
+    case AAlgorithm of
+      TEd25519.TAlgorithm.Ed25519:
         begin
-          raise EArgumentCryptoLibException.CreateResFmt(@SCtxNotNil,
-            [FEd25519Instance.AlgorithmName]);
+          if ACtx <> nil then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SCtxNotNil);
+          LEd25519.Sign(FData, 0, LPk, 0, AMsg, AMsgOff, AMsgLen, ASig, ASigOff);
         end;
 
-        FEd25519Instance.Sign(FData, 0, pk, 0, msg, msgOff, msgLen,
-          sig, sigOff);
-      end;
-
-    TEd25519.TEd25519Algorithm.Ed25519ctx:
-      begin
-        FEd25519Instance.Sign(FData, 0, pk, 0, ctx, msg, msgOff, msgLen,
-          sig, sigOff);
-      end;
-
-    TEd25519.TEd25519Algorithm.Ed25519ph:
-      begin
-        if (TEd25519.PreHashSize <> msgLen) then
+      TEd25519.TAlgorithm.Ed25519ctx:
         begin
-          raise EArgumentCryptoLibException.CreateResFmt(@SMsgLen,
-            [FEd25519Instance.AlgorithmName]);
+          if ACtx = nil then
+            raise EArgumentNilCryptoLibException.CreateRes(@SCtxNil);
+          if System.Length(ACtx) > 255 then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SCtxLength);
+          LEd25519.Sign(FData, 0, LPk, 0, ACtx, AMsg, AMsgOff, AMsgLen, ASig,
+            ASigOff);
         end;
 
-        FEd25519Instance.SignPrehash(FData, 0, pk, 0, ctx, msg, msgOff,
-          sig, sigOff);
-      end
-  else
-    begin
-      raise EInvalidOperationCryptoLibException.CreateRes
-        (@SUnsupportedAlgorithm);
+      TEd25519.TAlgorithm.Ed25519ph:
+        begin
+          if ACtx = nil then
+            raise EArgumentNilCryptoLibException.CreateRes(@SCtxNil);
+          if System.Length(ACtx) > 255 then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SCtxLength);
+          if TEd25519.PrehashSize <> AMsgLen then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SMsgLen);
+          LEd25519.SignPrehash(FData, 0, LPk, 0, ACtx, AMsg, AMsgOff, ASig,
+            ASigOff);
+        end
+    else
+      raise EInvalidOperationCryptoLibException.CreateRes(@SUnsupportedAlgorithm);
     end;
-
+  finally
+    LEd25519.Free;
   end;
 end;
 

+ 114 - 28
CryptoLib/src/Crypto/Parameters/ClpEd25519PublicKeyParameters.pas

@@ -32,6 +32,8 @@ uses
 
 resourcestring
   SEOFInPublicKey = 'EOF encountered in middle of Ed25519 public key';
+  SInvalidPublicKey = 'invalid public key';
+  SMustHaveLengthKeySize = 'must have length %d';
 
 type
   TEd25519PublicKeyParameters = class sealed(TAsymmetricKeyParameter,
@@ -39,20 +41,26 @@ type
 
   strict private
   var
-    FData: TCryptoLibByteArray;
+    FPublicPoint: TEd25519.IPublicPoint;
 
   public
 
     const
     KeySize = Int32(TEd25519.PublicKeySize);
 
-    constructor Create(const buf: TCryptoLibByteArray; off: Int32); overload;
-    constructor Create(input: TStream); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray; AOff: Int32); overload;
+    constructor Create(AInput: TStream); overload;
+    constructor Create(const APublicPoint: TEd25519.IPublicPoint); overload;
 
-    procedure Encode(const buf: TCryptoLibByteArray; off: Int32); inline;
+    procedure Encode(const ABuf: TCryptoLibByteArray; AOff: Int32); inline;
     function GetEncoded(): TCryptoLibByteArray; inline;
 
-    function Equals(const other: IEd25519PublicKeyParameters): Boolean;
+    function Verify(AAlgorithm: TEd25519.TAlgorithm;
+      const ACtx, AMsg: TCryptoLibByteArray; AMsgOff, AMsgLen: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32): Boolean;
+
+    function Equals(const AOther: IEd25519PublicKeyParameters): Boolean;
       reintroduce; overload;
     function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}override;
@@ -63,56 +71,134 @@ implementation
 
 { TEd25519PublicKeyParameters }
 
-function TEd25519PublicKeyParameters.GetEncoded: TCryptoLibByteArray;
+constructor TEd25519PublicKeyParameters.Create(const ABuf: TCryptoLibByteArray);
 begin
-  result := System.Copy(FData);
+  if System.Length(ABuf) <> KeySize then
+    raise EArgumentCryptoLibException.CreateResFmt(@SMustHaveLengthKeySize,
+      [KeySize]);
+  Create(ABuf, 0);
 end;
 
-constructor TEd25519PublicKeyParameters.Create(const buf: TCryptoLibByteArray;
-  off: Int32);
+constructor TEd25519PublicKeyParameters.Create(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
+var
+  LPoint: TEd25519.IPublicPoint;
 begin
-  Inherited Create(false);
-  System.SetLength(FData, KeySize);
-  System.Move(buf[off], FData[0], KeySize * System.SizeOf(Byte));
+  Inherited Create(False);
+  LPoint := TEd25519.ValidatePublicKeyPartialExport(ABuf, AOff);
+  if LPoint = nil then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidPublicKey);
+  FPublicPoint := LPoint;
 end;
 
-constructor TEd25519PublicKeyParameters.Create(input: TStream);
+constructor TEd25519PublicKeyParameters.Create(AInput: TStream);
+var
+  LData: TCryptoLibByteArray;
+  LPoint: TEd25519.IPublicPoint;
 begin
-  Inherited Create(false);
-  System.SetLength(FData, KeySize);
-  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
-  begin
+  Inherited Create(False);
+  System.SetLength(LData, KeySize);
+  if KeySize <> TStreamUtilities.ReadFully(AInput, LData) then
     raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPublicKey);
-  end;
+  LPoint := TEd25519.ValidatePublicKeyPartialExport(LData, 0);
+  if LPoint = nil then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidPublicKey);
+  FPublicPoint := LPoint;
 end;
 
-procedure TEd25519PublicKeyParameters.Encode(const buf: TCryptoLibByteArray;
-  off: Int32);
+constructor TEd25519PublicKeyParameters.Create(const APublicPoint
+  : TEd25519.IPublicPoint);
 begin
-  System.Move(FData[0], buf[off], KeySize * System.SizeOf(Byte));
+  Inherited Create(False);
+  if APublicPoint = nil then
+    raise EArgumentNilCryptoLibException.CreateRes(@SInvalidPublicKey);
+  FPublicPoint := APublicPoint;
+end;
+
+procedure TEd25519PublicKeyParameters.Encode(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
+begin
+  TEd25519.EncodePublicPoint(FPublicPoint, ABuf, AOff);
+end;
+
+function TEd25519PublicKeyParameters.GetEncoded: TCryptoLibByteArray;
+begin
+  System.SetLength(Result, KeySize);
+  Encode(Result, 0);
+end;
+
+function TEd25519PublicKeyParameters.Verify(AAlgorithm: TEd25519.TAlgorithm;
+  const ACtx, AMsg: TCryptoLibByteArray; AMsgOff, AMsgLen: Int32;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32): Boolean;
+var
+  LEd25519: TEd25519;
+begin
+  LEd25519 := TEd25519.Create();
+  try
+    case AAlgorithm of
+      TEd25519.TAlgorithm.Ed25519:
+        begin
+          if ACtx <> nil then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SInvalidPublicKey);
+          Result := LEd25519.Verify(ASig, ASigOff, FPublicPoint, AMsg, AMsgOff,
+            AMsgLen);
+        end;
+      TEd25519.TAlgorithm.Ed25519ctx:
+        begin
+          if ACtx = nil then
+            raise EArgumentNilCryptoLibException.CreateRes(@SInvalidPublicKey);
+          if System.Length(ACtx) > 255 then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes
+              (@SInvalidPublicKey);
+          Result := LEd25519.Verify(ASig, ASigOff, FPublicPoint, ACtx, AMsg,
+            AMsgOff, AMsgLen);
+        end;
+      TEd25519.TAlgorithm.Ed25519ph:
+        begin
+          if ACtx = nil then
+            raise EArgumentNilCryptoLibException.CreateRes(@SInvalidPublicKey);
+          if System.Length(ACtx) > 255 then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes
+              (@SInvalidPublicKey);
+          if TEd25519.PrehashSize <> AMsgLen then
+            raise EArgumentOutOfRangeCryptoLibException.CreateRes
+              (@SInvalidPublicKey);
+          Result := LEd25519.VerifyPreHash(ASig, ASigOff, FPublicPoint, ACtx,
+            AMsg, AMsgOff);
+        end
+    else
+      raise EArgumentOutOfRangeCryptoLibException.CreateRes(@SInvalidPublicKey);
+    end;
+  finally
+    LEd25519.Free;
+  end;
 end;
 
-function TEd25519PublicKeyParameters.Equals(const other
+function TEd25519PublicKeyParameters.Equals(const AOther
   : IEd25519PublicKeyParameters): Boolean;
+var
+  LEncoded, LOtherEncoded: TCryptoLibByteArray;
 begin
-  if (other = Self as IEd25519PublicKeyParameters) then
+  if (AOther = Self as IEd25519PublicKeyParameters) then
   begin
-    result := true;
+    Result := True;
     Exit;
   end;
 
-  if (other = Nil) then
+  if (AOther = nil) then
   begin
-    result := false;
+    Result := False;
     Exit;
   end;
-  result := TArrayUtilities.FixedTimeEquals(FData, other.GetEncoded())
+  LEncoded := GetEncoded();
+  LOtherEncoded := AOther.GetEncoded();
+  Result := TArrayUtilities.FixedTimeEquals(LEncoded, LOtherEncoded);
 end;
 
 function TEd25519PublicKeyParameters.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
 {$ENDIF DELPHI}
 begin
-  result := TArrayUtilities.GetArrayHashCode(FData);
+  Result := TArrayUtilities.GetArrayHashCode(GetEncoded());
 end;
 
 end.

+ 30 - 14
CryptoLib/src/Crypto/Parameters/ClpX25519PrivateKeyParameters.pas

@@ -36,6 +36,7 @@ uses
 resourcestring
   SEOFInPrivateKey = 'EOF encountered in middle of X25519 private key';
   SAgreementCalculationFailed = 'X25519 Agreement Failed';
+  SMustHaveLengthKeySize = 'must have length %d';
 
 type
   TX25519PrivateKeyParameters = class sealed(TAsymmetricKeyParameter,
@@ -44,6 +45,7 @@ type
   strict private
   var
     FData: TCryptoLibByteArray;
+  class function Validate(const ABuf: TCryptoLibByteArray): TCryptoLibByteArray; static;
 
   public
 
@@ -51,9 +53,10 @@ type
     KeySize = Int32(TX25519.ScalarSize);
     SecretSize = Int32(TX25519.PointSize);
 
-    constructor Create(const random: ISecureRandom); overload;
-    constructor Create(const buf: TCryptoLibByteArray; off: Int32); overload;
-    constructor Create(input: TStream); overload;
+    constructor Create(const ARandom: ISecureRandom); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray; AOff: Int32); overload;
+    constructor Create(AInput: TStream); overload;
 
     procedure Encode(const buf: TCryptoLibByteArray; off: Int32); inline;
     function GetEncoded(): TCryptoLibByteArray; inline;
@@ -101,26 +104,39 @@ begin
   result := System.Copy(FData);
 end;
 
-constructor TX25519PrivateKeyParameters.Create(const random: ISecureRandom);
+class function TX25519PrivateKeyParameters.Validate(const ABuf: TCryptoLibByteArray): TCryptoLibByteArray;
+begin
+  if System.Length(ABuf) <> TX25519PrivateKeyParameters.KeySize then
+    raise EArgumentCryptoLibException.CreateResFmt(@SMustHaveLengthKeySize,
+      [TX25519PrivateKeyParameters.KeySize]);
+  Result := ABuf;
+end;
+
+constructor TX25519PrivateKeyParameters.Create(const ARandom: ISecureRandom);
 begin
   Inherited Create(true);
-  System.SetLength(FData, KeySize);
-  TX25519.GeneratePrivateKey(random, FData);
+  System.SetLength(FData, TX25519PrivateKeyParameters.KeySize);
+  TX25519.GeneratePrivateKey(ARandom, FData);
 end;
 
-constructor TX25519PrivateKeyParameters.Create(const buf: TCryptoLibByteArray;
-  off: Int32);
+constructor TX25519PrivateKeyParameters.Create(const ABuf: TCryptoLibByteArray);
+begin
+  Create(TX25519PrivateKeyParameters.Validate(ABuf), 0);
+end;
+
+constructor TX25519PrivateKeyParameters.Create(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
 begin
   Inherited Create(true);
-  System.SetLength(FData, KeySize);
-  System.Move(buf[off], FData[0], KeySize * System.SizeOf(Byte));
+  System.SetLength(FData, TX25519PrivateKeyParameters.KeySize);
+  System.Move(ABuf[AOff], FData[0], TX25519PrivateKeyParameters.KeySize * System.SizeOf(Byte));
 end;
 
-constructor TX25519PrivateKeyParameters.Create(input: TStream);
+constructor TX25519PrivateKeyParameters.Create(AInput: TStream);
 begin
   Inherited Create(true);
-  System.SetLength(FData, KeySize);
-  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
+  System.SetLength(FData, TX25519PrivateKeyParameters.KeySize);
+  if (TX25519PrivateKeyParameters.KeySize <> TStreamUtilities.ReadFully(AInput, FData)) then
   begin
     raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPrivateKey);
   end;
@@ -129,7 +145,7 @@ end;
 procedure TX25519PrivateKeyParameters.Encode(const buf: TCryptoLibByteArray;
   off: Int32);
 begin
-  System.Move(FData[0], buf[off], KeySize * System.SizeOf(Byte));
+  System.Move(FData[0], buf[off], TX25519PrivateKeyParameters.KeySize * System.SizeOf(Byte));
 end;
 
 function TX25519PrivateKeyParameters.Equals(const other

+ 27 - 12
CryptoLib/src/Crypto/Parameters/ClpX25519PublicKeyParameters.pas

@@ -32,6 +32,7 @@ uses
 
 resourcestring
   SEOFInPublicKey = 'EOF encountered in middle of X25519 public key';
+  SMustHaveLengthKeySize = 'must have length %d';
 
 type
   TX25519PublicKeyParameters = class sealed(TAsymmetricKeyParameter,
@@ -40,16 +41,18 @@ type
   strict private
   var
     FData: TCryptoLibByteArray;
+  class function Validate(const ABuf: TCryptoLibByteArray): TCryptoLibByteArray; static;
 
   public
 
     const
     KeySize = Int32(TX25519.PointSize);
 
-    constructor Create(const buf: TCryptoLibByteArray; off: Int32); overload;
-    constructor Create(input: TStream); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray); overload;
+    constructor Create(const ABuf: TCryptoLibByteArray; AOff: Int32); overload;
+    constructor Create(AInput: TStream); overload;
 
-    procedure Encode(const buf: TCryptoLibByteArray; off: Int32); inline;
+    procedure Encode(const ABuf: TCryptoLibByteArray; AOff: Int32); inline;
     function GetEncoded(): TCryptoLibByteArray; inline;
 
     function Equals(const other: IX25519PublicKeyParameters): Boolean;
@@ -63,33 +66,45 @@ implementation
 
 { TX25519PublicKeyParameters }
 
+class function TX25519PublicKeyParameters.Validate(const ABuf: TCryptoLibByteArray): TCryptoLibByteArray;
+begin
+  if System.Length(ABuf) <> TX25519PublicKeyParameters.KeySize then
+    raise EArgumentCryptoLibException.CreateResFmt(@SMustHaveLengthKeySize, [TX25519PublicKeyParameters.KeySize]);
+  Result := ABuf;
+end;
+
 function TX25519PublicKeyParameters.GetEncoded: TCryptoLibByteArray;
 begin
   result := System.Copy(FData);
 end;
 
-constructor TX25519PublicKeyParameters.Create(const buf: TCryptoLibByteArray;
-  off: Int32);
+constructor TX25519PublicKeyParameters.Create(const ABuf: TCryptoLibByteArray);
+begin
+  Create(TX25519PublicKeyParameters.Validate(ABuf), 0);
+end;
+
+constructor TX25519PublicKeyParameters.Create(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
 begin
   Inherited Create(false);
-  System.SetLength(FData, KeySize);
-  System.Move(buf[off], FData[0], KeySize * System.SizeOf(Byte));
+  System.SetLength(FData, TX25519PublicKeyParameters.KeySize);
+  System.Move(ABuf[AOff], FData[0], TX25519PublicKeyParameters.KeySize * System.SizeOf(Byte));
 end;
 
-constructor TX25519PublicKeyParameters.Create(input: TStream);
+constructor TX25519PublicKeyParameters.Create(AInput: TStream);
 begin
   Inherited Create(false);
   System.SetLength(FData, KeySize);
-  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
+  if (KeySize <> TStreamUtilities.ReadFully(AInput, FData)) then
   begin
     raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPublicKey);
   end;
 end;
 
-procedure TX25519PublicKeyParameters.Encode(const buf: TCryptoLibByteArray;
-  off: Int32);
+procedure TX25519PublicKeyParameters.Encode(const ABuf: TCryptoLibByteArray;
+  AOff: Int32);
 begin
-  System.Move(FData[0], buf[off], KeySize * System.SizeOf(Byte));
+  System.Move(FData[0], ABuf[AOff], KeySize * System.SizeOf(Byte));
 end;
 
 function TX25519PublicKeyParameters.Equals(const other

+ 147 - 51
CryptoLib/src/Crypto/Signers/ClpEd25519CtxSigner.pas

@@ -23,9 +23,10 @@ interface
 
 uses
   Classes,
-  ClpIEd25519,
+  SyncObjs,
   ClpEd25519,
   ClpICipherParameters,
+  ClpISigner,
   ClpIEd25519CtxSigner,
   ClpIEd25519PrivateKeyParameters,
   ClpIEd25519PublicKeyParameters,
@@ -33,25 +34,50 @@ uses
   ClpCryptoLibTypes;
 
 resourcestring
+  SContextNil = 'Ctx must not be Nil for Ed25519ctx/Ed25519ph';
   SNotInitializedForSigning =
     'Ed25519CtxSigner not Initialised for Signature Generation.';
   SNotInitializedForVerifying =
     'Ed25519CtxSigner not Initialised for Verification';
 
 type
-  TEd25519CtxSigner = class(TInterfacedObject, IEd25519CtxSigner)
+  TEd25519CtxSigner = class(TInterfacedObject, ISigner, IEd25519CtxSigner)
+
+  strict private
+  type
+    TBuffer = class
+    strict private
+    var
+      FStream: TMemoryStream;
+      FLock: TCriticalSection;
+
+      function GetBufferContent: TCryptoLibByteArray;
+      procedure ResetInternal;
+
+    public
+      constructor Create();
+      destructor Destroy(); override;
+
+      procedure WriteByte(AInput: Byte);
+      procedure Write(const ABuf: TCryptoLibByteArray; AOff, ALen: Int32);
+      procedure Reset();
+
+      function GenerateSignature(const APrivateKey
+        : IEd25519PrivateKeyParameters;
+        const AContext: TCryptoLibByteArray): TCryptoLibByteArray;
+      function VerifySignature(const APublicKey: IEd25519PublicKeyParameters;
+        const AContext: TCryptoLibByteArray;
+        const ASignature: TCryptoLibByteArray): Boolean;
+    end;
 
   strict private
   var
     FContext: TCryptoLibByteArray;
-    FBuffer: TMemoryStream;
+    FBuffer: TBuffer;
     FForSigning: Boolean;
-    FEd25519Instance: IEd25519;
     FPrivateKey: IEd25519PrivateKeyParameters;
     FPublicKey: IEd25519PublicKeyParameters;
 
-    function Aggregate: TCryptoLibByteArray; inline;
-
   strict protected
     function GetAlgorithmName: String; virtual;
 
@@ -76,34 +102,131 @@ type
 
 implementation
 
-{ TEd25519CtxSigner }
+{ TEd25519CtxSigner.TBuffer }
+
+constructor TEd25519CtxSigner.TBuffer.Create();
+begin
+  Inherited Create();
+  FStream := TMemoryStream.Create();
+  FLock := TCriticalSection.Create();
+end;
 
-function TEd25519CtxSigner.Aggregate: TCryptoLibByteArray;
+destructor TEd25519CtxSigner.TBuffer.Destroy;
+begin
+  FLock.Free;
+  FStream.Free;
+  inherited Destroy;
+end;
+
+function TEd25519CtxSigner.TBuffer.GetBufferContent: TCryptoLibByteArray;
 begin
   Result := nil;
-  if FBuffer.Size > 0 then
+  if FStream.Size > 0 then
   begin
-    FBuffer.Position := 0;
-    System.SetLength(Result, FBuffer.Size);
-    FBuffer.Read(Result[0], FBuffer.Size);
+    FStream.Position := 0;
+    System.SetLength(Result, FStream.Size);
+    FStream.Read(Result[0], FStream.Size);
   end;
 end;
 
-procedure TEd25519CtxSigner.BlockUpdate(const ABuf: TCryptoLibByteArray;
-  AOff, ALength: Int32);
+procedure TEd25519CtxSigner.TBuffer.ResetInternal;
+var
+  LCount: Int64;
+begin
+  LCount := FStream.Size;
+  if LCount > 0 then
+  begin
+    FillChar(PByte(FStream.Memory)^, LCount, 0);
+  end;
+  FStream.Clear;
+  FStream.SetSize(Int64(0));
+end;
+
+procedure TEd25519CtxSigner.TBuffer.Reset();
+begin
+  FLock.Enter;
+  try
+    ResetInternal;
+  finally
+    FLock.Leave;
+  end;
+end;
+
+procedure TEd25519CtxSigner.TBuffer.WriteByte(AInput: Byte);
+var
+  LB: TCryptoLibByteArray;
+begin
+  LB := TCryptoLibByteArray.Create(AInput);
+  FStream.Write(LB[0], 1);
+end;
+
+procedure TEd25519CtxSigner.TBuffer.Write(const ABuf: TCryptoLibByteArray;
+  AOff, ALen: Int32);
+begin
+  if (ABuf <> nil) and (ALen > 0) then
+    FStream.Write(ABuf[AOff], ALen);
+end;
+
+function TEd25519CtxSigner.TBuffer.GenerateSignature(const APrivateKey
+  : IEd25519PrivateKeyParameters;
+  const AContext: TCryptoLibByteArray): TCryptoLibByteArray;
+var
+  LBuf: TCryptoLibByteArray;
+  LCount: Int32;
 begin
-  if ABuf <> nil then
+  FLock.Enter;
+  try
+    LBuf := GetBufferContent();
+    LCount := System.Length(LBuf);
+    System.SetLength(Result, TEd25519PrivateKeyParameters.SignatureSize);
+    APrivateKey.Sign(TEd25519.TAlgorithm.Ed25519ctx, AContext, LBuf, 0,
+      LCount, Result, 0);
+    ResetInternal;
+  finally
+    FLock.Leave;
+  end;
+end;
+
+function TEd25519CtxSigner.TBuffer.VerifySignature(const APublicKey
+  : IEd25519PublicKeyParameters; const AContext: TCryptoLibByteArray;
+  const ASignature: TCryptoLibByteArray): Boolean;
+var
+  LBuf: TCryptoLibByteArray;
+  LCount: Int32;
+begin
+  if TEd25519.SignatureSize <> System.Length(ASignature) then
   begin
-    FBuffer.Write(ABuf[AOff], ALength);
+    Reset();
+    Result := False;
+    Exit;
   end;
+  FLock.Enter;
+  try
+    LBuf := GetBufferContent();
+    LCount := System.Length(LBuf);
+    Result := APublicKey.Verify(TEd25519.TAlgorithm.Ed25519ctx, AContext,
+      LBuf, 0, LCount, ASignature, 0);
+    ResetInternal;
+  finally
+    FLock.Leave;
+  end;
+end;
+
+{ TEd25519CtxSigner }
+
+procedure TEd25519CtxSigner.BlockUpdate(const ABuf: TCryptoLibByteArray;
+  AOff, ALength: Int32);
+begin
+  FBuffer.Write(ABuf, AOff, ALength);
 end;
 
 constructor TEd25519CtxSigner.Create(const AContext: TCryptoLibByteArray);
 begin
   Inherited Create();
-  FBuffer := TMemoryStream.Create();
+  if AContext = nil then
+    raise EArgumentNilCryptoLibException.CreateRes(@SContextNil);
+  FBuffer := TBuffer.Create();
   FContext := System.Copy(AContext);
-  FEd25519Instance := TEd25519.Create();
 end;
 
 destructor TEd25519CtxSigner.Destroy;
@@ -114,7 +237,7 @@ end;
 
 function TEd25519CtxSigner.GetAlgorithmName: String;
 begin
-  Result := 'Ed25519Ctx';
+  Result := 'Ed25519ctx';
 end;
 
 procedure TEd25519CtxSigner.Init(AForSigning: Boolean;
@@ -124,10 +247,8 @@ begin
 
   if (AForSigning) then
   begin
-    // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
-
     FPrivateKey := AParameters as IEd25519PrivateKeyParameters;
-    FPublicKey := FPrivateKey.GeneratePublicKey();
+    FPublicKey := nil;
   end
   else
   begin
@@ -140,13 +261,12 @@ end;
 
 procedure TEd25519CtxSigner.Reset;
 begin
-  FBuffer.Clear;
-  FBuffer.SetSize(Int64(0));
+  FBuffer.Reset();
 end;
 
 procedure TEd25519CtxSigner.Update(AInput: Byte);
 begin
-  FBuffer.Write(TCryptoLibByteArray.Create(AInput)[0], 1);
+  FBuffer.WriteByte(AInput);
 end;
 
 function TEd25519CtxSigner.GetMaxSignatureSize: Int32;
@@ -155,48 +275,24 @@ begin
 end;
 
 function TEd25519CtxSigner.GenerateSignature: TCryptoLibByteArray;
-var
-  LSignature, LBuf: TCryptoLibByteArray;
-  LCount: Int32;
 begin
   if ((not FForSigning) or (FPrivateKey = nil)) then
   begin
     raise EInvalidOperationCryptoLibException.CreateRes
       (@SNotInitializedForSigning);
   end;
-
-  System.SetLength(LSignature, TEd25519PrivateKeyParameters.SignatureSize);
-  LBuf := Aggregate();
-  LCount := System.Length(LBuf);
-
-  FPrivateKey.Sign(TEd25519.TEd25519Algorithm.Ed25519ctx, FPublicKey, FContext,
-    LBuf, 0, LCount, LSignature, 0);
-  Reset();
-  Result := LSignature;
+  Result := FBuffer.GenerateSignature(FPrivateKey, FContext);
 end;
 
 function TEd25519CtxSigner.VerifySignature(const ASignature
   : TCryptoLibByteArray): Boolean;
-var
-  LBuf, LPk: TCryptoLibByteArray;
-  LCount: Int32;
 begin
   if ((FForSigning) or (FPublicKey = nil)) then
   begin
     raise EInvalidOperationCryptoLibException.CreateRes
       (@SNotInitializedForVerifying);
   end;
-  if (TEd25519.SignatureSize <> System.Length(ASignature)) then
-  begin
-    Result := false;
-    Exit;
-  end;
-  LPk := FPublicKey.GetEncoded();
-  LBuf := Aggregate();
-  LCount := System.Length(LBuf);
-  Result := FEd25519Instance.Verify(ASignature, 0, LPk, 0, FContext, LBuf,
-    0, LCount);
-  Reset();
+  Result := FBuffer.VerifySignature(FPublicKey, FContext, ASignature);
 end;
 
 end.

+ 17 - 16
CryptoLib/src/Crypto/Signers/ClpEd25519PhSigner.pas

@@ -23,9 +23,9 @@ interface
 
 uses
   ClpIDigest,
-  ClpIEd25519,
   ClpEd25519,
   ClpICipherParameters,
+  ClpISigner,
   ClpIEd25519PhSigner,
   ClpIEd25519PrivateKeyParameters,
   ClpIEd25519PublicKeyParameters,
@@ -40,14 +40,13 @@ resourcestring
   SPreHashDigestFailed = 'PreHash Digest Failed';
 
 type
-  TEd25519PhSigner = class(TInterfacedObject, IEd25519PhSigner)
+  TEd25519PhSigner = class(TInterfacedObject, ISigner, IEd25519PhSigner)
 
   strict private
   var
     FPreHash: IDigest;
     FContext: TCryptoLibByteArray;
     FForSigning: Boolean;
-    FEd25519Instance: IEd25519;
     FPrivateKey: IEd25519PrivateKeyParameters;
     FPublicKey: IEd25519PublicKeyParameters;
 
@@ -87,8 +86,7 @@ constructor TEd25519PhSigner.Create(const AContext: TCryptoLibByteArray);
 begin
   Inherited Create();
   FContext := System.Copy(AContext);
-  FEd25519Instance := TEd25519.Create();
-  FPreHash := FEd25519Instance.CreatePreHash();
+  FPreHash := TEd25519.CreatePreHash();
 end;
 
 destructor TEd25519PhSigner.Destroy;
@@ -98,7 +96,7 @@ end;
 
 function TEd25519PhSigner.GetAlgorithmName: String;
 begin
-  Result := 'Ed25519Ph';
+  Result := 'Ed25519ph';
 end;
 
 procedure TEd25519PhSigner.Init(AForSigning: Boolean;
@@ -108,10 +106,8 @@ begin
 
   if (AForSigning) then
   begin
-    // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
-
     FPrivateKey := AParameters as IEd25519PrivateKeyParameters;
-    FPublicKey := FPrivateKey.GeneratePublicKey();
+    FPublicKey := nil;
   end
   else
   begin
@@ -155,15 +151,15 @@ begin
 
   System.SetLength(LSignature, TEd25519PrivateKeyParameters.SignatureSize);
 
-  FPrivateKey.Sign(TEd25519.TEd25519Algorithm.Ed25519Ph, FPublicKey, FContext,
-    LMsg, 0, TEd25519.PreHashSize, LSignature, 0);
+  FPrivateKey.Sign(TEd25519.TAlgorithm.Ed25519ph, FContext, LMsg, 0,
+    TEd25519.PreHashSize, LSignature, 0);
   Result := LSignature;
 end;
 
 function TEd25519PhSigner.VerifySignature(const ASignature
   : TCryptoLibByteArray): Boolean;
 var
-  LPk: TCryptoLibByteArray;
+  LMsg: TCryptoLibByteArray;
 begin
   if ((FForSigning) or (FPublicKey = nil)) then
   begin
@@ -172,12 +168,17 @@ begin
   end;
   if (TEd25519.SignatureSize <> System.Length(ASignature)) then
   begin
-    Result := false;
+    FPreHash.Reset();
+    Result := False;
     Exit;
   end;
-  LPk := FPublicKey.GetEncoded();
-  Result := FEd25519Instance.VerifyPrehash(ASignature, 0, LPk, 0, FContext,
-    FPreHash);
+  System.SetLength(LMsg, TEd25519.PreHashSize);
+  if (TEd25519.PreHashSize <> FPreHash.DoFinal(LMsg, 0)) then
+  begin
+    raise EInvalidOperationCryptoLibException.CreateRes(@SPreHashDigestFailed);
+  end;
+  Result := FPublicKey.Verify(TEd25519.TAlgorithm.Ed25519ph, FContext, LMsg, 0,
+    TEd25519.PreHashSize, ASignature, 0);
 end;
 
 end.

+ 140 - 49
CryptoLib/src/Crypto/Signers/ClpEd25519Signer.pas

@@ -23,9 +23,10 @@ interface
 
 uses
   Classes,
-  ClpIEd25519,
+  SyncObjs,
   ClpEd25519,
   ClpICipherParameters,
+  ClpISigner,
   ClpIEd25519Signer,
   ClpIEd25519PrivateKeyParameters,
   ClpIEd25519PublicKeyParameters,
@@ -39,18 +40,40 @@ resourcestring
     'Ed25519Signer not Initialised for Verification';
 
 type
-  TEd25519Signer = class(TInterfacedObject, IEd25519Signer)
+  TEd25519Signer = class(TInterfacedObject, ISigner, IEd25519Signer)
+
+  strict private
+  type
+    TBuffer = class
+    strict private
+    var
+      FStream: TMemoryStream;
+      FLock: TCriticalSection;
+
+      function GetBufferContent: TCryptoLibByteArray;
+      procedure ResetInternal;
+
+    public
+      constructor Create();
+      destructor Destroy(); override;
+
+      procedure WriteByte(AInput: Byte);
+      procedure Write(const ABuf: TCryptoLibByteArray; AOff, ALen: Int32);
+      procedure Reset();
+
+      function GenerateSignature(const APrivateKey
+        : IEd25519PrivateKeyParameters): TCryptoLibByteArray;
+      function VerifySignature(const APublicKey: IEd25519PublicKeyParameters;
+        const ASignature: TCryptoLibByteArray): Boolean;
+    end;
 
   strict private
   var
-    FBuffer: TMemoryStream;
+    FBuffer: TBuffer;
     FForSigning: Boolean;
-    FEd25519Instance: IEd25519;
     FPrivateKey: IEd25519PrivateKeyParameters;
     FPublicKey: IEd25519PublicKeyParameters;
 
-    function Aggregate: TCryptoLibByteArray; inline;
-
   strict protected
     function GetAlgorithmName: String; virtual;
 
@@ -75,33 +98,127 @@ type
 
 implementation
 
-{ TEd25519Signer }
+{ TEd25519Signer.TBuffer }
+
+constructor TEd25519Signer.TBuffer.Create();
+begin
+  Inherited Create();
+  FStream := TMemoryStream.Create();
+  FLock := TCriticalSection.Create();
+end;
 
-function TEd25519Signer.Aggregate: TCryptoLibByteArray;
+destructor TEd25519Signer.TBuffer.Destroy;
+begin
+  FLock.Free;
+  FStream.Free;
+  inherited Destroy;
+end;
+
+function TEd25519Signer.TBuffer.GetBufferContent: TCryptoLibByteArray;
 begin
   Result := nil;
-  if FBuffer.Size > 0 then
+  if FStream.Size > 0 then
   begin
-    FBuffer.Position := 0;
-    System.SetLength(Result, FBuffer.Size);
-    FBuffer.Read(Result[0], FBuffer.Size);
+    FStream.Position := 0;
+    System.SetLength(Result, FStream.Size);
+    FStream.Read(Result[0], FStream.Size);
   end;
 end;
 
-procedure TEd25519Signer.BlockUpdate(const ABuf: TCryptoLibByteArray;
-  AOff, ALength: Int32);
+procedure TEd25519Signer.TBuffer.ResetInternal;
+var
+  LCount: Int64;
+begin
+  LCount := FStream.Size;
+  if LCount > 0 then
+  begin
+    FillChar(PByte(FStream.Memory)^, LCount, 0);
+  end;
+  FStream.Clear;
+  FStream.SetSize(Int64(0));
+end;
+
+procedure TEd25519Signer.TBuffer.Reset();
+begin
+  FLock.Enter;
+  try
+    ResetInternal;
+  finally
+    FLock.Leave;
+  end;
+end;
+
+procedure TEd25519Signer.TBuffer.WriteByte(AInput: Byte);
+var
+  LB: TCryptoLibByteArray;
+begin
+  LB := TCryptoLibByteArray.Create(AInput);
+  FStream.Write(LB[0], 1);
+end;
+
+procedure TEd25519Signer.TBuffer.Write(const ABuf: TCryptoLibByteArray;
+  AOff, ALen: Int32);
+begin
+  if (ABuf <> nil) and (ALen > 0) then
+    FStream.Write(ABuf[AOff], ALen);
+end;
+
+function TEd25519Signer.TBuffer.GenerateSignature(const APrivateKey
+  : IEd25519PrivateKeyParameters): TCryptoLibByteArray;
+var
+  LBuf: TCryptoLibByteArray;
+  LCount: Int32;
 begin
-  if ABuf <> nil then
+  FLock.Enter;
+  try
+    LBuf := GetBufferContent();
+    LCount := System.Length(LBuf);
+    System.SetLength(Result, TEd25519PrivateKeyParameters.SignatureSize);
+    APrivateKey.Sign(TEd25519.TAlgorithm.Ed25519, nil, LBuf, 0, LCount,
+      Result, 0);
+    ResetInternal;
+  finally
+    FLock.Leave;
+  end;
+end;
+
+function TEd25519Signer.TBuffer.VerifySignature(const APublicKey
+  : IEd25519PublicKeyParameters;
+  const ASignature: TCryptoLibByteArray): Boolean;
+var
+  LBuf: TCryptoLibByteArray;
+  LCount: Int32;
+begin
+  if TEd25519.SignatureSize <> System.Length(ASignature) then
   begin
-    FBuffer.Write(ABuf[AOff], ALength);
+    Reset();
+    Result := False;
+    Exit;
   end;
+  FLock.Enter;
+  try
+    LBuf := GetBufferContent();
+    LCount := System.Length(LBuf);
+    Result := APublicKey.Verify(TEd25519.TAlgorithm.Ed25519, nil, LBuf, 0,
+      LCount, ASignature, 0);
+    ResetInternal;
+  finally
+    FLock.Leave;
+  end;
+end;
+
+{ TEd25519Signer }
+
+procedure TEd25519Signer.BlockUpdate(const ABuf: TCryptoLibByteArray;
+  AOff, ALength: Int32);
+begin
+  FBuffer.Write(ABuf, AOff, ALength);
 end;
 
 constructor TEd25519Signer.Create();
 begin
   Inherited Create();
-  FBuffer := TMemoryStream.Create();
-  FEd25519Instance := TEd25519.Create;
+  FBuffer := TBuffer.Create();
 end;
 
 destructor TEd25519Signer.Destroy;
@@ -122,10 +239,8 @@ begin
 
   if (AForSigning) then
   begin
-    // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
-
     FPrivateKey := AParameters as IEd25519PrivateKeyParameters;
-    FPublicKey := FPrivateKey.GeneratePublicKey();
+    FPublicKey := nil;
   end
   else
   begin
@@ -138,13 +253,12 @@ end;
 
 procedure TEd25519Signer.Reset;
 begin
-  FBuffer.Clear;
-  FBuffer.SetSize(Int64(0));
+  FBuffer.Reset();
 end;
 
 procedure TEd25519Signer.Update(AInput: Byte);
 begin
-  FBuffer.Write(TCryptoLibByteArray.Create(AInput)[0], 1);
+  FBuffer.WriteByte(AInput);
 end;
 
 function TEd25519Signer.GetMaxSignatureSize: Int32;
@@ -153,47 +267,24 @@ begin
 end;
 
 function TEd25519Signer.GenerateSignature: TCryptoLibByteArray;
-var
-  LSignature, LBuf: TCryptoLibByteArray;
-  LCount: Int32;
 begin
   if ((not FForSigning) or (FPrivateKey = nil)) then
   begin
     raise EInvalidOperationCryptoLibException.CreateRes
       (@SNotInitializedForSigning);
   end;
-
-  System.SetLength(LSignature, TEd25519PrivateKeyParameters.SignatureSize);
-  LBuf := Aggregate();
-  LCount := System.Length(LBuf);
-
-  FPrivateKey.Sign(TEd25519.TEd25519Algorithm.Ed25519, FPublicKey, nil, LBuf, 0,
-    LCount, LSignature, 0);
-  Reset();
-  Result := LSignature;
+  Result := FBuffer.GenerateSignature(FPrivateKey);
 end;
 
 function TEd25519Signer.VerifySignature(const ASignature
   : TCryptoLibByteArray): Boolean;
-var
-  LBuf, LPk: TCryptoLibByteArray;
-  LCount: Int32;
 begin
   if ((FForSigning) or (FPublicKey = nil)) then
   begin
     raise EInvalidOperationCryptoLibException.CreateRes
       (@SNotInitializedForVerifying);
   end;
-  if (TEd25519.SignatureSize <> System.Length(ASignature)) then
-  begin
-    Result := false;
-    Exit;
-  end;
-  LPk := FPublicKey.GetEncoded();
-  LBuf := Aggregate();
-  LCount := System.Length(LBuf);
-  Result := FEd25519Instance.Verify(ASignature, 0, LPk, 0, LBuf, 0, LCount);
-  Reset();
+  Result := FBuffer.VerifySignature(FPublicKey, ASignature);
 end;
 
 end.

+ 46 - 2
CryptoLib/src/GeneralUtilities/ClpStringUtilities.pas

@@ -41,7 +41,15 @@ type
     /// Split a string by delimiter into an array.
     /// </summary>
     class function SplitString(const AInput: string; ADelimiter: Char)
-      : TCryptoLibStringArray; static;
+      : TCryptoLibStringArray; overload; static;
+    /// <summary>
+    /// Split a string by delimiter into an array, with a maximum number of parts.
+    /// When AMaxCount is greater than 0, returns at most AMaxCount parts; the last
+    /// part contains the remainder of the string (including any remaining delimiters).
+    /// String indices are 1-based.
+    /// </summary>
+    class function SplitString(const AInput: string; ADelimiter: Char;
+      AMaxCount: Int32): TCryptoLibStringArray; overload; static;
     /// <summary>
     /// Compare two strings ignoring case.
     /// </summary>
@@ -157,7 +165,7 @@ begin
     { Split the string and fill the resulting array }
 
     I := 0;
-    LLen := System.Length(ADelimiter);
+    LLen := 1;
     LPosStart := 1;
     LPosDel := System.Pos(ADelimiter, AInput);
     while LPosDel > 0 do
@@ -171,6 +179,42 @@ begin
   end;
 end;
 
+class function TStringUtilities.SplitString(const AInput: string; ADelimiter: Char;
+  AMaxCount: Int32): TCryptoLibStringArray;
+var
+  LPosStart, LPosDel, J, K: Int32;
+begin
+  Result := nil;
+  if AMaxCount <= 0 then
+  begin
+    Result := SplitString(AInput, ADelimiter);
+    Exit;
+  end;
+  if AInput = '' then
+  begin
+    System.SetLength(Result, 1);
+    Result[0] := '';
+    Exit;
+  end;
+  System.SetLength(Result, AMaxCount);
+  LPosStart := 1;
+  for J := 0 to AMaxCount - 2 do
+  begin
+    LPosDel := PosEx(ADelimiter, AInput, LPosStart);
+    if LPosDel < 1 then
+    begin
+      Result[J] := System.Copy(AInput, LPosStart, System.Length(AInput));
+      for K := J + 1 to AMaxCount - 1 do
+        Result[K] := '';
+      System.SetLength(Result, J + 1);
+      Exit;
+    end;
+    Result[J] := System.Copy(AInput, LPosStart, LPosDel - LPosStart);
+    LPosStart := LPosDel + 1;
+  end;
+  Result[AMaxCount - 1] := System.Copy(AInput, LPosStart, System.Length(AInput));
+end;
+
 class function TStringUtilities.EqualsIgnoreCase(const A, B: String): Boolean;
 begin
   Result := SameText(A, B);

+ 3 - 4
CryptoLib/src/Interfaces/Crypto/Parameters/ClpIEd25519PrivateKeyParameters.pas

@@ -35,10 +35,9 @@ type
     function GetEncoded(): TCryptoLibByteArray;
     function GeneratePublicKey(): IEd25519PublicKeyParameters;
 
-    procedure Sign(algorithm: TEd25519.TEd25519Algorithm;
-      const publicKey: IEd25519PublicKeyParameters;
-      const ctx, msg: TCryptoLibByteArray; msgOff, msgLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32);
+    procedure Sign(AAlgorithm: TEd25519.TAlgorithm;
+      const ACtx, AMsg: TCryptoLibByteArray; AMsgOff, AMsgLen: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32);
 
     function Equals(const other: IEd25519PrivateKeyParameters)
       : Boolean; overload;

+ 7 - 2
CryptoLib/src/Interfaces/Crypto/Parameters/ClpIEd25519PublicKeyParameters.pas

@@ -22,6 +22,7 @@ unit ClpIEd25519PublicKeyParameters;
 interface
 
 uses
+  ClpEd25519,
   ClpIAsymmetricKeyParameter,
   ClpCryptoLibTypes;
 
@@ -29,10 +30,14 @@ type
   IEd25519PublicKeyParameters = interface(IAsymmetricKeyParameter)
     ['{84C0E096-F4BA-438D-9E20-3ECFAE341E63}']
 
-    procedure Encode(const buf: TCryptoLibByteArray; off: Int32);
+    procedure Encode(const ABuf: TCryptoLibByteArray; AOff: Int32);
     function GetEncoded(): TCryptoLibByteArray;
 
-    function Equals(const other: IEd25519PublicKeyParameters): Boolean;
+    function Verify(AAlgorithm: TEd25519.TAlgorithm;
+      const ACtx, AMsg: TCryptoLibByteArray; AMsgOff, AMsgLen: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32): Boolean;
+
+    function Equals(const AOther: IEd25519PublicKeyParameters): Boolean;
       overload;
   end;
 

+ 0 - 64
CryptoLib/src/Interfaces/Math/EC/Custom/Djb/ClpICurve25519Custom.pas

@@ -1,64 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpICurve25519Custom;
-
-{$I ..\..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpBigInteger,
-  ClpIECC,
-  ClpCryptoLibTypes;
-
-type
-  ICurve25519FieldElement = Interface(IAbstractFpFieldElement)
-    ['{50046C65-BACE-4E68-9AEF-09AAD33DFD62}']
-
-    function GetX: TCryptoLibUInt32Array;
-    property X: TCryptoLibUInt32Array read GetX;
-  end;
-
-type
-  ICurve25519Point = Interface(IAbstractFpPoint)
-    ['{49280930-32AC-4F84-BBCE-C9A9DF18E71E}']
-
-    function CalculateJacobianModifiedW(const z: ICurve25519FieldElement;
-      const ZSquared: TCryptoLibUInt32Array): ICurve25519FieldElement;
-    function GetJacobianModifiedW(): ICurve25519FieldElement;
-    function TwiceJacobianModified(calculateW: Boolean): ICurve25519Point;
-
-  end;
-
-type
-  ICurve25519 = Interface(IAbstractFpCurve)
-    ['{56BB2C20-454C-4C42-A603-AD7429362D82}']
-
-    function GetQ: TBigInteger;
-    property Q: TBigInteger read GetQ;
-
-  end;
-
-type
-  ICurve25519LookupTable = Interface(IAbstractECLookupTable)
-    ['{79FE1276-3D22-4A20-A4F1-58F0C0532BAC}']
-  end;
-
-implementation
-
-end.

+ 0 - 100
CryptoLib/src/Interfaces/Math/EC/Rfc8032/ClpIEd25519.pas

@@ -1,100 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpIEd25519;
-
-{$I ..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpIDigest,
-  ClpISecureRandom,
-  ClpCryptoLibTypes;
-
-type
-  IEd25519 = interface(IInterface)
-    ['{2C6CD9DD-8809-44E6-979D-1EBE465CE9E2}']
-
-    function GetAlgorithmName: String;
-    function CreatePreHash(): IDigest;
-
-    procedure GeneratePrivateKey(const random: ISecureRandom;
-      const k: TCryptoLibByteArray);
-
-    procedure GeneratePublicKey(const sk: TCryptoLibByteArray; skOff: Int32;
-      pk: TCryptoLibByteArray; pkOff: Int32);
-
-    procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-      const m: TCryptoLibByteArray; mOff, mLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32; const m: TCryptoLibByteArray;
-      mOff, mLen: Int32; const sig: TCryptoLibByteArray;
-      sigOff: Int32); overload;
-
-    procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-      const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-      const ctx, ph: TCryptoLibByteArray; phOff: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx, ph: TCryptoLibByteArray; phOff: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-      const ctx: TCryptoLibByteArray; const ph: IDigest;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx: TCryptoLibByteArray; const ph: IDigest;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    function Verify(const sig: TCryptoLibByteArray; sigOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32; const m: TCryptoLibByteArray;
-      mOff, mLen: Int32): Boolean; overload;
-
-    function Verify(const sig: TCryptoLibByteArray; sigOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32): Boolean; overload;
-
-    function VerifyPreHash(const sig: TCryptoLibByteArray; sigOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx, ph: TCryptoLibByteArray; phOff: Int32): Boolean; overload;
-
-    function VerifyPreHash(const sig: TCryptoLibByteArray; sigOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx: TCryptoLibByteArray; const ph: IDigest): Boolean; overload;
-
-    property AlgorithmName: String read GetAlgorithmName;
-
-  end;
-
-implementation
-
-end.

+ 0 - 1408
CryptoLib/src/Math/EC/Custom/Djb/ClpCurve25519Custom.pas

@@ -1,1408 +0,0 @@
-{ *********************************************************************************** }
-{ *                              CryptoLib Library                                  * }
-{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
-{ *                 Github Repository <https://github.com/Xor-el>                   * }
-
-{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
-{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
-
-{ *                              Acknowledgements:                                  * }
-{ *                                                                                 * }
-{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
-{ *                           development of this library                           * }
-
-{ * ******************************************************************************* * }
-
-(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
-
-unit ClpCurve25519Custom;
-
-{$I ..\..\..\..\Include\CryptoLib.inc}
-
-interface
-
-uses
-  ClpECC,
-  ClpIECC,
-  ClpNat,
-  ClpMod,
-  ClpNat256,
-  ClpBigInteger,
-  ClpICurve25519Custom,
-  ClpECCurveConstants,
-  ClpBitUtilities,
-  ClpEncoders,
-  ClpArrayUtilities,
-  ClpCryptoLibTypes;
-
-resourcestring
-  SInvalidValueForCurve25519FieldElement =
-    'Value Invalid for Curve25519FieldElement "%s"';
-  SOneOfECFieldElementIsNil = 'Exactly One of the Field Elements is Nil';
-
-type
-  // 2^255 - 2^4 - 2^1 - 1
-  TCurve25519Field = class sealed(TObject)
-
-  strict private
-  const
-    P7 = UInt32($7FFFFFFF);
-    PInv = UInt32($13);
-
-    class var
-
-      FP, FPExt: TCryptoLibUInt32Array;
-
-    class function AddPTo(const z: TCryptoLibUInt32Array): UInt32;
-      static; inline;
-
-    class function AddPExtTo(const zz: TCryptoLibUInt32Array): UInt32;
-      static; inline;
-
-    class function SubPFrom(const z: TCryptoLibUInt32Array): Int32;
-      static; inline;
-
-    class function SubPExtFrom(const zz: TCryptoLibUInt32Array): Int32;
-      static; inline;
-
-    class function GetP: TCryptoLibUInt32Array; static; inline;
-
-    class procedure Boot(); static;
-    class constructor Curve25519Field();
-
-  public
-    class procedure Add(const x, y, z: TCryptoLibUInt32Array); static; inline;
-    class procedure AddExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure AddOne(const x, z: TCryptoLibUInt32Array); static; inline;
-    class function FromBigInteger(const x: TBigInteger): TCryptoLibUInt32Array;
-      static; inline;
-    class procedure Half(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Multiply(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure MultiplyAddToExt(const x, y, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Negate(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce(const xx, z: TCryptoLibUInt32Array); static; inline;
-    class procedure Reduce27(x: UInt32; const z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Square(const x, z: TCryptoLibUInt32Array); static; inline;
-    class procedure SquareN(const x: TCryptoLibUInt32Array; n: Int32;
-      const z: TCryptoLibUInt32Array); static; inline;
-    class procedure Subtract(const x, y, z: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure SubtractExt(const xx, yy, zz: TCryptoLibUInt32Array);
-      static; inline;
-    class procedure Twice(const x, z: TCryptoLibUInt32Array); static; inline;
-
-    class property P: TCryptoLibUInt32Array read GetP;
-
-  end;
-
-type
-  TCurve25519FieldElement = class(TAbstractFpFieldElement,
-    ICurve25519FieldElement)
-
-  strict private
-    class var
-
-      FPRECOMP_POW2: TCryptoLibUInt32Array;
-
-    function Equals(const other: ICurve25519FieldElement): Boolean;
-      reintroduce; overload;
-
-    class function GetQ: TBigInteger; static; inline;
-
-    class procedure Boot(); static;
-    class constructor Curve25519FieldElement();
-
-  strict protected
-  var
-    Fx: TCryptoLibUInt32Array;
-
-    function GetFieldName: string; override;
-    function GetFieldSize: Int32; override;
-    function GetIsOne: Boolean; override;
-    function GetIsZero: Boolean; override;
-
-    function GetX: TCryptoLibUInt32Array; inline;
-    property x: TCryptoLibUInt32Array read GetX;
-
-  public
-    constructor Create(); overload;
-    constructor Create(const x: TBigInteger); overload;
-    constructor Create(const x: TCryptoLibUInt32Array); overload;
-
-    function TestBitZero: Boolean; override;
-    function ToBigInteger(): TBigInteger; override;
-
-    function Add(const b: IECFieldElement): IECFieldElement; override;
-    function AddOne(): IECFieldElement; override;
-    function Subtract(const b: IECFieldElement): IECFieldElement; override;
-
-    function Multiply(const b: IECFieldElement): IECFieldElement; override;
-    function Divide(const b: IECFieldElement): IECFieldElement; override;
-    function Negate(): IECFieldElement; override;
-    function Square(): IECFieldElement; override;
-
-    function Invert(): IECFieldElement; override;
-
-    /// <summary>
-    /// return a sqrt root - the routine verifies that the calculation
-    /// returns the right value - if <br />none exists it returns null.
-    /// </summary>
-    function Sqrt(): IECFieldElement; override;
-
-    function Equals(const other: IECFieldElement): Boolean; overload; override;
-
-    function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}override;
-
-    property IsZero: Boolean read GetIsZero;
-    property IsOne: Boolean read GetIsOne;
-    property FieldName: string read GetFieldName;
-    property FieldSize: Int32 read GetFieldSize;
-
-    class property Q: TBigInteger read GetQ;
-
-  end;
-
-type
-  TCurve25519Point = class sealed(TAbstractFpPoint, ICurve25519Point)
-
-  strict protected
-    function Detach(): IECPoint; override;
-    function CalculateJacobianModifiedW(const z: ICurve25519FieldElement;
-      const ZSquared: TCryptoLibUInt32Array): ICurve25519FieldElement; virtual;
-    function GetJacobianModifiedW(): ICurve25519FieldElement; virtual;
-    function TwiceJacobianModified(calculateW: Boolean)
-      : ICurve25519Point; virtual;
-
-  public
-
-    /// <summary>
-    /// Create a point which encodes without point compression.
-    /// </summary>
-    /// <param name="curve">
-    /// the curve to use
-    /// </param>
-    /// <param name="x">
-    /// affine x co-ordinate
-    /// </param>
-    /// <param name="y">
-    /// affine y co-ordinate
-    /// </param>
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement);
-      overload; deprecated 'Use ECCurve.createPoint to construct points';
-
-    /// <summary>
-    /// Create a point that encodes with or without point compresion.
-    /// </summary>
-    /// <param name="curve">
-    /// the curve to use
-    /// </param>
-    /// <param name="x">
-    /// affine x co-ordinate
-    /// </param>
-    /// <param name="y">
-    /// affine y co-ordinate
-    /// </param>
-    /// <param name="withCompression">
-    /// if true encode with point compression
-    /// </param>
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      withCompression: Boolean); overload;
-      deprecated
-      'Per-point compression property will be removed, see GetEncoded(boolean)';
-
-    constructor Create(const curve: IECCurve; const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean); overload;
-
-    function Add(const b: IECPoint): IECPoint; override;
-    function Negate(): IECPoint; override;
-
-    function Twice(): IECPoint; override;
-    function TwicePlus(const b: IECPoint): IECPoint; override;
-
-    function ThreeTimes(): IECPoint; override;
-
-    function GetZCoord(index: Int32): IECFieldElement; override;
-
-  end;
-
-type
-  TCurve25519 = class sealed(TAbstractFpCurve, ICurve25519)
-
-  strict private
-
-  type
-    TCurve25519LookupTable = class sealed(TAbstractECLookupTable,
-      ICurve25519LookupTable)
-
-    strict private
-    var
-      Fm_outer: ICurve25519;
-      Fm_table: TCryptoLibUInt32Array;
-      Fm_size: Int32;
-
-      function CreatePoint(const x, y: TCryptoLibUInt32Array): IECPoint;
-
-    strict protected
-
-      function GetSize: Int32; override;
-
-    public
-
-      constructor Create(const outer: ICurve25519;
-        const table: TCryptoLibUInt32Array; size: Int32);
-
-      function Lookup(index: Int32): IECPoint; override;
-      function LookupVar(index: Int32): IECPoint; override;
-
-    end;
-
-  const
-    Curve25519_DEFAULT_COORDS = Int32
-      (TECCurveConstants.COORD_JACOBIAN_MODIFIED);
-    CURVE25519_FE_INTS = Int32(8);
-
-  var
-    Fq: TBigInteger;
-
-  strict protected
-  var
-    Fm_infinity: ICurve25519Point;
-
-    function GetQ: TBigInteger; virtual;
-    function GetFieldSize: Int32; override;
-    function GetInfinity: IECPoint; override;
-
-    function CloneCurve(): IECCurve; override;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      withCompression: Boolean): IECPoint; overload; override;
-
-    function CreateRawPoint(const x, y: IECFieldElement;
-      const zs: TCryptoLibGenericArray<IECFieldElement>;
-      withCompression: Boolean): IECPoint; overload; override;
-
-  public
-    constructor Create();
-    function FromBigInteger(const x: TBigInteger): IECFieldElement; override;
-
-    function SupportsCoordinateSystem(coord: Int32): Boolean; override;
-
-    function CreateCacheSafeLookupTable(const points
-      : TCryptoLibGenericArray<IECPoint>; off, len: Int32)
-      : IECLookupTable; override;
-
-    property Q: TBigInteger read GetQ;
-    property Infinity: IECPoint read GetInfinity;
-    property FieldSize: Int32 read GetFieldSize;
-
-  end;
-
-implementation
-
-{ TCurve25519Field }
-
-class function TCurve25519Field.AddPTo(const z: TCryptoLibUInt32Array): UInt32;
-var
-  c: Int64;
-begin
-  c := Int64(z[0]) - PInv;
-  z[0] := UInt32(c);
-  c := c shr 32;
-  if (c <> 0) then
-  begin
-    c := TNat.DecAt(7, z, 1);
-  end;
-  c := c + (Int64(z[7]) + (P7 + 1));
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
-end;
-
-class function TCurve25519Field.AddPExtTo
-  (const zz: TCryptoLibUInt32Array): UInt32;
-var
-  c: Int64;
-begin
-  c := Int64(zz[0]) + FPExt[0];
-  zz[0] := UInt32(c);
-  c := c shr 32;
-  if (c <> 0) then
-  begin
-    c := TNat.IncAt(8, zz, 1);
-  end;
-  c := c + (Int64(zz[8]) - PInv);
-  zz[8] := UInt32(c);
-  c := c shr 32;
-  if (c <> 0) then
-  begin
-    c := TNat.DecAt(15, zz, 9);
-  end;
-  c := c + (Int64(zz[15]) + (FPExt[15] + 1));
-  zz[15] := UInt32(c);
-  c := c shr 32;
-  result := UInt32(c);
-end;
-
-class function TCurve25519Field.SubPFrom(const z: TCryptoLibUInt32Array): Int32;
-var
-  c: Int64;
-begin
-  c := Int64(z[0]) + PInv;
-  z[0] := UInt32(c);
-  c := c shr 32;
-  if (c <> 0) then
-  begin
-    c := TNat.IncAt(7, z, 1);
-  end;
-  c := c + (Int64(z[7]) - (P7 + 1));
-  z[7] := UInt32(c);
-  c := c shr 32;
-  result := Int32(c);
-end;
-
-class function TCurve25519Field.SubPExtFrom
-  (const zz: TCryptoLibUInt32Array): Int32;
-var
-  c: Int64;
-begin
-  c := Int64(zz[0]) - FPExt[0];
-  zz[0] := UInt32(c);
-  c := c shr 32;
-  if (c <> 0) then
-  begin
-    c := TNat.DecAt(8, zz, 1);
-  end;
-  c := c + (Int64(zz[8]) + PInv);
-  zz[8] := UInt32(c);
-  c := c shr 32;
-  if (c <> 0) then
-  begin
-    c := TNat.IncAt(15, zz, 9);
-  end;
-  c := c + (Int64(zz[15]) - (FPExt[15] + 1));
-  zz[15] := UInt32(c);
-  c := c shr 32;
-  result := Int32(c);
-end;
-
-class constructor TCurve25519Field.Curve25519Field;
-begin
-  TCurve25519Field.Boot;
-end;
-
-class function TCurve25519Field.GetP: TCryptoLibUInt32Array;
-begin
-  result := FP;
-end;
-
-class procedure TCurve25519Field.Add(const x, y, z: TCryptoLibUInt32Array);
-begin
-  TNat256.Add(x, y, z);
-  if (TNat256.Gte(z, P)) then
-  begin
-    SubPFrom(z);
-  end;
-end;
-
-class procedure TCurve25519Field.AddExt(const xx, yy,
-  zz: TCryptoLibUInt32Array);
-begin
-  TNat.Add(16, xx, yy, zz);
-  if (TNat.Gte(16, zz, FPExt)) then
-  begin
-    SubPExtFrom(zz);
-  end;
-end;
-
-class procedure TCurve25519Field.AddOne(const x, z: TCryptoLibUInt32Array);
-begin
-  TNat.Inc(8, x, z);
-  if (TNat256.Gte(z, P)) then
-  begin
-    SubPFrom(z);
-  end;
-end;
-
-class procedure TCurve25519Field.Boot;
-begin
-  FP := TCryptoLibUInt32Array.Create($FFFFFFED, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $7FFFFFFF);
-  FPExt := TCryptoLibUInt32Array.Create($00000169, $00000000, $00000000,
-    $00000000, $00000000, $00000000, $00000000, $00000000, $FFFFFFED, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $3FFFFFFF);
-end;
-
-class function TCurve25519Field.FromBigInteger(const x: TBigInteger)
-  : TCryptoLibUInt32Array;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat.FromBigInteger(256, x);
-  while (TNat256.Gte(z, P)) do
-  begin
-    TNat256.SubFrom(P, z, 0);
-  end;
-  result := z;
-end;
-
-class procedure TCurve25519Field.Half(const x, z: TCryptoLibUInt32Array);
-begin
-  if ((x[0] and 1) = 0) then
-  begin
-    TNat.ShiftDownBit(8, x, 0, z);
-  end
-  else
-  begin
-    TNat256.Add(x, P, z);
-    TNat.ShiftDownBit(8, z, 0);
-  end;
-end;
-
-class procedure TCurve25519Field.Reduce(const xx, z: TCryptoLibUInt32Array);
-var
-  xx07, c, z7: UInt32;
-begin
-{$IFDEF DEBUG}
-  System.Assert((xx[15] shr 30) = 0);
-{$ENDIF DEBUG}
-  xx07 := xx[7];
-  TNat.ShiftUpBit(8, xx, 8, xx07, z, 0);
-  c := TNat256.MulByWordAddTo(PInv, xx, z) shl 1;
-  z7 := z[7];
-  c := c + ((z7 shr 31) - (xx07 shr 31));
-  z7 := z7 and P7;
-  z7 := z7 + (TNat.AddWordTo(7, c * PInv, z));
-  z[7] := z7;
-  if ((z7 >= P7) and (TNat256.Gte(z, P))) then
-  begin
-    SubPFrom(z);
-  end;
-end;
-
-class procedure TCurve25519Field.Multiply(const x, y, z: TCryptoLibUInt32Array);
-var
-  tt: TCryptoLibUInt32Array;
-begin
-  tt := TNat256.CreateExt();
-  TNat256.Mul(x, y, tt);
-  Reduce(tt, z);
-end;
-
-class procedure TCurve25519Field.MultiplyAddToExt(const x, y,
-  zz: TCryptoLibUInt32Array);
-begin
-  TNat256.MulAddTo(x, y, zz);
-  if (TNat.Gte(16, zz, FPExt)) then
-  begin
-    SubPExtFrom(zz);
-  end;
-end;
-
-class procedure TCurve25519Field.Negate(const x, z: TCryptoLibUInt32Array);
-begin
-  if (TNat256.IsZero(x)) then
-  begin
-    TNat256.Zero(z);
-  end
-  else
-  begin
-    TNat256.Sub(P, x, z);
-  end;
-end;
-
-class procedure TCurve25519Field.Reduce27(x: UInt32;
-  const z: TCryptoLibUInt32Array);
-var
-  z7, c: UInt32;
-begin
-{$IFDEF DEBUG}
-  System.Assert(((x shr 26) = 0));
-{$ENDIF DEBUG}
-  z7 := z[7];
-  c := ((x shl 1) or (z7 shr 31));
-  z7 := z7 and P7;
-  z7 := z7 + (TNat.AddWordTo(7, c * PInv, z));
-  z[7] := z7;
-  if ((z7 >= P7) and (TNat256.Gte(z, P))) then
-  begin
-    SubPFrom(z);
-  end;
-end;
-
-class procedure TCurve25519Field.Square(const x, z: TCryptoLibUInt32Array);
-var
-  tt: TCryptoLibUInt32Array;
-begin
-  tt := TNat256.CreateExt();
-  TNat256.Square(x, tt);
-  Reduce(tt, z);
-end;
-
-class procedure TCurve25519Field.SquareN(const x: TCryptoLibUInt32Array;
-  n: Int32; const z: TCryptoLibUInt32Array);
-var
-  tt: TCryptoLibUInt32Array;
-begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  tt := TNat256.CreateExt();
-  TNat256.Square(x, tt);
-  Reduce(tt, z);
-  System.Dec(n);
-  while (n > 0) do
-  begin
-    TNat256.Square(z, tt);
-    Reduce(tt, z);
-    System.Dec(n);
-  end;
-end;
-
-class procedure TCurve25519Field.Subtract(const x, y, z: TCryptoLibUInt32Array);
-var
-  c: Int32;
-begin
-  c := TNat256.Sub(x, y, z);
-  if (c <> 0) then
-  begin
-    AddPTo(z);
-  end;
-end;
-
-class procedure TCurve25519Field.SubtractExt(const xx, yy,
-  zz: TCryptoLibUInt32Array);
-var
-  c: Int32;
-begin
-  c := TNat.Sub(16, xx, yy, zz);
-  if (c <> 0) then
-  begin
-    AddPExtTo(zz);
-  end;
-end;
-
-class procedure TCurve25519Field.Twice(const x, z: TCryptoLibUInt32Array);
-begin
-  TNat.ShiftUpBit(8, x, 0, z);
-  if (TNat256.Gte(z, P)) then
-  begin
-    SubPFrom(z);
-  end;
-end;
-
-{ TCurve25519FieldElement }
-
-class function TCurve25519FieldElement.GetQ: TBigInteger;
-begin
-  result := TNat256.ToBigInteger(TCurve25519Field.P);
-end;
-
-class procedure TCurve25519FieldElement.Boot;
-begin
-  // Calculated as TBigInteger.ValueOf(2).modPow(Q.shiftRight(2), Q)
-  FPRECOMP_POW2 := TCryptoLibUInt32Array.Create($4A0EA0B0, $C4EE1B27, $AD2FE478,
-    $2F431806, $3DFBD7A7, $2B4D0099, $4FC1DF0B, $2B832480);
-end;
-
-class constructor TCurve25519FieldElement.Curve25519FieldElement;
-begin
-  TCurve25519FieldElement.Boot();
-end;
-
-function TCurve25519FieldElement.GetX: TCryptoLibUInt32Array;
-begin
-  result := Fx;
-end;
-
-constructor TCurve25519FieldElement.Create;
-begin
-  Inherited Create();
-  Fx := TNat256.Create();
-end;
-
-constructor TCurve25519FieldElement.Create(const x: TBigInteger);
-begin
-  if ((not(x.IsInitialized)) or (x.SignValue < 0) or (x.CompareTo(Q) >= 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateResFmt
-      (@SInvalidValueForCurve25519FieldElement, ['x']);
-  end;
-  Inherited Create();
-  Fx := TCurve25519Field.FromBigInteger(x);
-end;
-
-constructor TCurve25519FieldElement.Create(const x: TCryptoLibUInt32Array);
-begin
-  Inherited Create();
-  Fx := x;
-end;
-
-function TCurve25519FieldElement.GetFieldName: string;
-begin
-  result := 'Curve25519Field';
-end;
-
-function TCurve25519FieldElement.GetFieldSize: Int32;
-begin
-  result := Q.BitLength;
-end;
-
-function TCurve25519FieldElement.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
-{$ENDIF DELPHI}
-begin
-  result := Q.GetHashCode() xor TArrayUtilities.GetArrayHashCode(Fx, 0, 8);
-end;
-
-function TCurve25519FieldElement.GetIsOne: Boolean;
-begin
-  result := TNat256.IsOne(Fx);
-end;
-
-function TCurve25519FieldElement.GetIsZero: Boolean;
-begin
-  result := TNat256.IsZero(Fx);
-end;
-
-function TCurve25519FieldElement.Invert: IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TMod.CheckedModOddInverse(TCurve25519Field.P, Fx, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.Multiply(const b: IECFieldElement)
-  : IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TCurve25519Field.Multiply(Fx, (b as ICurve25519FieldElement).x, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.Negate: IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TCurve25519Field.Negate(Fx, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.Sqrt: IECFieldElement;
-var
-  x1, x2, x3, x4, x7, x11, x15, x30, x60, x120, x131, x251, t1,
-    t2: TCryptoLibUInt32Array;
-begin
-
-  (*
-    * Q == 8m + 5, so we use Pocklington's method for this case.
-    *
-    * First, raise this element to the exponent 2^252 - 2^1 (i.e. m + 1)
-    *
-    * Breaking up the exponent's binary representation into "repunits", we get:
-    * { 251 1s } { 1 0s }
-    *
-    * Therefore we need an addition chain containing 251 (the lengths of the repunits)
-    * We use: 1, 2, 3, 4, 7, 11, 15, 30, 60, 120, 131, [251]
-  *)
-
-  x1 := Fx;
-  if ((TNat256.IsZero(x1)) or (TNat256.IsOne(x1))) then
-  begin
-    result := Self as IECFieldElement;
-    Exit;
-  end;
-
-  x2 := TNat256.Create();
-  TCurve25519Field.Square(x1, x2);
-  TCurve25519Field.Multiply(x2, x1, x2);
-  x3 := x2;
-  TCurve25519Field.Square(x2, x3);
-  TCurve25519Field.Multiply(x3, x1, x3);
-  x4 := TNat256.Create();
-  TCurve25519Field.Square(x3, x4);
-  TCurve25519Field.Multiply(x4, x1, x4);
-  x7 := TNat256.Create();
-  TCurve25519Field.SquareN(x4, 3, x7);
-  TCurve25519Field.Multiply(x7, x3, x7);
-  x11 := x3;
-  TCurve25519Field.SquareN(x7, 4, x11);
-  TCurve25519Field.Multiply(x11, x4, x11);
-  x15 := x7;
-  TCurve25519Field.SquareN(x11, 4, x15);
-  TCurve25519Field.Multiply(x15, x4, x15);
-  x30 := x4;
-  TCurve25519Field.SquareN(x15, 15, x30);
-  TCurve25519Field.Multiply(x30, x15, x30);
-  x60 := x15;
-  TCurve25519Field.SquareN(x30, 30, x60);
-  TCurve25519Field.Multiply(x60, x30, x60);
-  x120 := x30;
-  TCurve25519Field.SquareN(x60, 60, x120);
-  TCurve25519Field.Multiply(x120, x60, x120);
-  x131 := x60;
-  TCurve25519Field.SquareN(x120, 11, x131);
-  TCurve25519Field.Multiply(x131, x11, x131);
-  x251 := x11;
-  TCurve25519Field.SquareN(x131, 120, x251);
-  TCurve25519Field.Multiply(x251, x120, x251);
-
-  t1 := x251;
-  TCurve25519Field.Square(t1, t1);
-
-  t2 := x120;
-  TCurve25519Field.Square(t1, t2);
-
-  if (TNat256.Eq(x1, t2)) then
-  begin
-    result := TCurve25519FieldElement.Create(t1);
-    Exit;
-  end;
-
-  (*
-    * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
-    * which is ((4x)^(m + 1))/2 mod Q
-  *)
-  TCurve25519Field.Multiply(t1, FPRECOMP_POW2, t1);
-
-  TCurve25519Field.Square(t1, t2);
-
-  if (TNat256.Eq(x1, t2)) then
-  begin
-    result := TCurve25519FieldElement.Create(t1);
-    Exit;
-  end;
-
-  result := Nil;
-
-end;
-
-function TCurve25519FieldElement.Square: IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TCurve25519Field.Square(Fx, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.Subtract(const b: IECFieldElement)
-  : IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TCurve25519Field.Subtract(Fx, (b as ICurve25519FieldElement).x, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.TestBitZero: Boolean;
-begin
-  result := TNat256.GetBit(Fx, 0) = 1;
-end;
-
-function TCurve25519FieldElement.ToBigInteger: TBigInteger;
-begin
-  result := TNat256.ToBigInteger(Fx);
-end;
-
-function TCurve25519FieldElement.Add(const b: IECFieldElement): IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TCurve25519Field.Add(x, (b as ICurve25519FieldElement).x, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.AddOne: IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TCurve25519Field.AddOne(Fx, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.Divide(const b: IECFieldElement)
-  : IECFieldElement;
-var
-  z: TCryptoLibUInt32Array;
-begin
-  z := TNat256.Create();
-  TMod.CheckedModOddInverse(TCurve25519Field.P, (b as ICurve25519FieldElement).x, z);
-  TCurve25519Field.Multiply(z, Fx, z);
-  result := TCurve25519FieldElement.Create(z);
-end;
-
-function TCurve25519FieldElement.Equals(const other
-  : ICurve25519FieldElement): Boolean;
-begin
-  if ((Self as ICurve25519FieldElement) = other) then
-  begin
-    result := true;
-    Exit;
-  end;
-  if (other = Nil) then
-  begin
-    result := false;
-    Exit;
-  end;
-  result := TNat256.Eq(Fx, other.x);
-end;
-
-function TCurve25519FieldElement.Equals(const other: IECFieldElement): Boolean;
-begin
-  result := Equals(other as ICurve25519FieldElement);
-end;
-
-{ TCurve25519Point }
-
-function TCurve25519Point.Detach: IECPoint;
-begin
-  result := TCurve25519Point.Create(Nil, AffineXCoord, AffineYCoord);
-end;
-
-function TCurve25519Point.CalculateJacobianModifiedW
-  (const z: ICurve25519FieldElement; const ZSquared: TCryptoLibUInt32Array)
-  : ICurve25519FieldElement;
-var
-  a4, W: ICurve25519FieldElement;
-  LZSquared: TCryptoLibUInt32Array;
-begin
-  a4 := curve.A as ICurve25519FieldElement;
-  if (z.IsOne) then
-  begin
-    result := a4;
-    Exit;
-  end;
-
-  W := TCurve25519FieldElement.Create();
-  LZSquared := ZSquared;
-  if (LZSquared = Nil) then
-  begin
-    LZSquared := W.x;
-    TCurve25519Field.Square(z.x, LZSquared);
-  end;
-  TCurve25519Field.Square(LZSquared, W.x);
-  TCurve25519Field.Multiply(W.x, a4.x, W.x);
-  result := W;
-end;
-
-function TCurve25519Point.GetJacobianModifiedW: ICurve25519FieldElement;
-var
-  zz: TCryptoLibGenericArray<IECFieldElement>;
-  W: ICurve25519FieldElement;
-begin
-  zz := RawZCoords;
-  W := zz[1] as ICurve25519FieldElement;
-  if (W = Nil) then
-  begin
-    // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
-    W := CalculateJacobianModifiedW(zz[0] as ICurve25519FieldElement, Nil);
-    zz[1] := W;
-  end;
-  result := W;
-end;
-
-function TCurve25519Point.TwiceJacobianModified(calculateW: Boolean)
-  : ICurve25519Point;
-var
-  x1, Y1, Z1, W1, x3, Y3, Z3, W3: ICurve25519FieldElement;
-  c: UInt32;
-  M, _2Y1, _2Y1Squared, S, _8T: TCryptoLibUInt32Array;
-begin
-  x1 := RawXCoord as ICurve25519FieldElement;
-  Y1 := RawYCoord as ICurve25519FieldElement;
-  Z1 := RawZCoords[0] as ICurve25519FieldElement;
-  W1 := GetJacobianModifiedW();
-
-  M := TNat256.Create();
-  TCurve25519Field.Square(x1.x, M);
-  c := TNat256.AddBothTo(M, M, M);
-  c := c + TNat256.AddTo(W1.x, M, 0);
-  TCurve25519Field.Reduce27(c, M);
-
-  _2Y1 := TNat256.Create();
-  TCurve25519Field.Twice(Y1.x, _2Y1);
-
-  _2Y1Squared := TNat256.Create();
-  TCurve25519Field.Multiply(_2Y1, Y1.x, _2Y1Squared);
-
-  S := TNat256.Create();
-  TCurve25519Field.Multiply(_2Y1Squared, x1.x, S);
-  TCurve25519Field.Twice(S, S);
-
-  _8T := TNat256.Create();
-  TCurve25519Field.Square(_2Y1Squared, _8T);
-  TCurve25519Field.Twice(_8T, _8T);
-
-  x3 := TCurve25519FieldElement.Create(_2Y1Squared);
-  TCurve25519Field.Square(M, x3.x);
-  TCurve25519Field.Subtract(x3.x, S, x3.x);
-  TCurve25519Field.Subtract(x3.x, S, x3.x);
-
-  Y3 := TCurve25519FieldElement.Create(S);
-  TCurve25519Field.Subtract(S, x3.x, Y3.x);
-  TCurve25519Field.Multiply(Y3.x, M, Y3.x);
-  TCurve25519Field.Subtract(Y3.x, _8T, Y3.x);
-
-  Z3 := TCurve25519FieldElement.Create(_2Y1);
-  if (not(TNat256.IsOne(Z1.x))) then
-  begin
-    TCurve25519Field.Multiply(Z3.x, Z1.x, Z3.x);
-  end;
-
-  W3 := Nil;
-  if (calculateW) then
-  begin
-    W3 := TCurve25519FieldElement.Create(_8T);
-    TCurve25519Field.Multiply(W3.x, W1.x, W3.x);
-    TCurve25519Field.Twice(W3.x, W3.x);
-  end;
-
-  result := TCurve25519Point.Create(curve, x3, Y3,
-    TCryptoLibGenericArray<IECFieldElement>.Create(Z3, W3), IsCompressed);
-end;
-
-function TCurve25519Point.GetZCoord(index: Int32): IECFieldElement;
-begin
-  if (index = 1) then
-  begin
-    result := GetJacobianModifiedW();
-    Exit;
-  end;
-
-  result := Inherited GetZCoord(index);
-end;
-
-function TCurve25519Point.Add(const b: IECPoint): IECPoint;
-var
-  LCurve: IECCurve;
-  x1, Y1, Z1, x2, Y2, Z2, x3, Y3, Z3, W3: ICurve25519FieldElement;
-  c: UInt32;
-  tt1, t2, t3, t4, U2, S2, U1, S1, H, R, G, V, HSquared,
-    Z3Squared: TCryptoLibUInt32Array;
-  zs: TCryptoLibGenericArray<IECFieldElement>;
-  Z1IsOne, Z2IsOne: Boolean;
-begin
-  if (IsInfinity) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-  if ((Self as IECPoint) = b) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  LCurve := curve;
-
-  x1 := RawXCoord as ICurve25519FieldElement;
-  Y1 := RawYCoord as ICurve25519FieldElement;
-  Z1 := RawZCoords[0] as ICurve25519FieldElement;
-  x2 := b.RawXCoord as ICurve25519FieldElement;
-  Y2 := b.RawYCoord as ICurve25519FieldElement;
-  Z2 := b.RawZCoords[0] as ICurve25519FieldElement;
-
-  tt1 := TNat256.CreateExt();
-  t2 := TNat256.Create();
-  t3 := TNat256.Create();
-  t4 := TNat256.Create();
-
-  Z1IsOne := Z1.IsOne;
-  if (Z1IsOne) then
-  begin
-    U2 := x2.x;
-    S2 := Y2.x;
-  end
-  else
-  begin
-    S2 := t3;
-    TCurve25519Field.Square(Z1.x, S2);
-
-    U2 := t2;
-    TCurve25519Field.Multiply(S2, x2.x, U2);
-
-    TCurve25519Field.Multiply(S2, Z1.x, S2);
-    TCurve25519Field.Multiply(S2, Y2.x, S2);
-  end;
-
-  Z2IsOne := Z2.IsOne;
-
-  if (Z2IsOne) then
-  begin
-    U1 := x1.x;
-    S1 := Y1.x;
-  end
-  else
-  begin
-    S1 := t4;
-    TCurve25519Field.Square(Z2.x, S1);
-
-    U1 := tt1;
-    TCurve25519Field.Multiply(S1, x1.x, U1);
-
-    TCurve25519Field.Multiply(S1, Z2.x, S1);
-    TCurve25519Field.Multiply(S1, Y1.x, S1);
-  end;
-
-  H := TNat256.Create();
-  TCurve25519Field.Subtract(U1, U2, H);
-
-  R := t2;
-  TCurve25519Field.Subtract(S1, S2, R);
-
-  // Check if b = Self or b = -Self
-  if (TNat256.IsZero(H)) then
-  begin
-    if (TNat256.IsZero(R)) then
-    begin
-      // this == b, i.e. this must be doubled
-      result := Twice();
-      Exit;
-    end;
-
-    // Self = -b, i.e. the result is the point at infinity
-    result := LCurve.Infinity;
-    Exit;
-  end;
-
-  HSquared := TNat256.Create();
-  TCurve25519Field.Square(H, HSquared);
-
-  G := TNat256.Create();
-  TCurve25519Field.Multiply(HSquared, H, G);
-
-  V := t3;
-  TCurve25519Field.Multiply(HSquared, U1, V);
-
-  TCurve25519Field.Negate(G, G);
-  TNat256.Mul(S1, G, tt1);
-
-  c := TNat256.AddBothTo(V, V, G);
-  TCurve25519Field.Reduce27(c, G);
-
-  x3 := TCurve25519FieldElement.Create(t4);
-  TCurve25519Field.Square(R, x3.x);
-  TCurve25519Field.Subtract(x3.x, G, x3.x);
-
-  Y3 := TCurve25519FieldElement.Create(G);
-  TCurve25519Field.Subtract(V, x3.x, Y3.x);
-  TCurve25519Field.MultiplyAddToExt(Y3.x, R, tt1);
-  TCurve25519Field.Reduce(tt1, Y3.x);
-
-  Z3 := TCurve25519FieldElement.Create(H);
-  if (not(Z1IsOne)) then
-  begin
-    TCurve25519Field.Multiply(Z3.x, Z1.x, Z3.x);
-  end;
-  if (not(Z2IsOne)) then
-  begin
-    TCurve25519Field.Multiply(Z3.x, Z2.x, Z3.x);
-  end;
-
-  if ((Z1IsOne) and (Z2IsOne)) then
-  begin
-    Z3Squared := HSquared;
-  end
-  else
-  begin
-    Z3Squared := Nil;
-  end;
-
-  // TODO If the result will only be used in a subsequent addition, we don't need W3
-  W3 := CalculateJacobianModifiedW(Z3, Z3Squared);
-
-  zs := TCryptoLibGenericArray<IECFieldElement>.Create(Z3, W3);
-
-  result := TCurve25519Point.Create(LCurve, x3, Y3, zs, IsCompressed);
-end;
-
-constructor TCurve25519Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, zs, withCompression);
-end;
-
-constructor TCurve25519Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement; withCompression: Boolean);
-begin
-  Inherited Create(curve, x, y, withCompression);
-  if ((x = Nil) <> (y = Nil)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SOneOfECFieldElementIsNil);
-  end;
-end;
-
-constructor TCurve25519Point.Create(const curve: IECCurve;
-  const x, y: IECFieldElement);
-begin
-  Create(curve, x, y, false);
-end;
-
-function TCurve25519Point.Negate: IECPoint;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  result := TCurve25519Point.Create(curve, RawXCoord, RawYCoord.Negate(),
-    RawZCoords, IsCompressed);
-end;
-
-function TCurve25519Point.ThreeTimes: IECPoint;
-begin
-  if ((IsInfinity) or (RawYCoord.IsZero)) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  result := TwiceJacobianModified(false).Add(Self as ICurve25519Point);
-end;
-
-function TCurve25519Point.Twice: IECPoint;
-var
-  LCurve: IECCurve;
-  Y1: IECFieldElement;
-begin
-  if (IsInfinity) then
-  begin
-    result := Self;
-    Exit;
-  end;
-
-  LCurve := curve;
-
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
-  begin
-    result := LCurve.Infinity;
-    Exit;
-  end;
-
-  result := TwiceJacobianModified(true);
-end;
-
-function TCurve25519Point.TwicePlus(const b: IECPoint): IECPoint;
-var
-  Y1: IECFieldElement;
-begin
-  if ((Self as IECPoint) = b) then
-  begin
-    result := ThreeTimes();
-    Exit;
-  end;
-  if (IsInfinity) then
-  begin
-    result := b;
-    Exit;
-  end;
-  if (b.IsInfinity) then
-  begin
-    result := Twice();
-    Exit;
-  end;
-
-  Y1 := RawYCoord;
-  if (Y1.IsZero) then
-  begin
-    result := b;
-    Exit;
-  end;
-
-  result := TwiceJacobianModified(false).Add(b);
-end;
-
-{ TCurve25519 }
-
-constructor TCurve25519.Create;
-begin
-  Fq := TCurve25519FieldElement.Q;
-  Inherited Create(Fq);
-  Fm_infinity := TCurve25519Point.Create(Self as IECCurve, Nil, Nil);
-
-  Fm_a := FromBigInteger(TBigInteger.Create(1,
-    THex.decode
-    ('2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144')));
-  Fm_b := FromBigInteger(TBigInteger.Create(1,
-    THex.decode
-    ('7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864')));
-  Fm_order := TBigInteger.Create(1,
-    THex.decode
-    ('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED'));
-  Fm_cofactor := TBigInteger.ValueOf(8);
-  Fm_coord := Curve25519_DEFAULT_COORDS;
-end;
-
-function TCurve25519.CloneCurve: IECCurve;
-begin
-  result := TCurve25519.Create();
-end;
-
-function TCurve25519.CreateCacheSafeLookupTable(const points
-  : TCryptoLibGenericArray<IECPoint>; off, len: Int32): IECLookupTable;
-var
-  table: TCryptoLibUInt32Array;
-  pos, i: Int32;
-  P: IECPoint;
-begin
-  System.SetLength(table, len * CURVE25519_FE_INTS * 2);
-
-  pos := 0;
-  for i := 0 to System.Pred(len) do
-  begin
-    P := points[off + i];
-    TNat256.Copy((P.RawXCoord as ICurve25519FieldElement).x, 0, table, pos);
-    pos := pos + CURVE25519_FE_INTS;
-    TNat256.Copy((P.RawYCoord as ICurve25519FieldElement).x, 0, table, pos);
-    pos := pos + CURVE25519_FE_INTS;
-  end;
-
-  result := TCurve25519LookupTable.Create(Self as ICurve25519, table, len);
-end;
-
-function TCurve25519.CreateRawPoint(const x, y: IECFieldElement;
-  withCompression: Boolean): IECPoint;
-begin
-  result := TCurve25519Point.Create(Self as IECCurve, x, y, withCompression);
-end;
-
-function TCurve25519.CreateRawPoint(const x, y: IECFieldElement;
-  const zs: TCryptoLibGenericArray<IECFieldElement>; withCompression: Boolean)
-  : IECPoint;
-begin
-  result := TCurve25519Point.Create(Self as IECCurve, x, y, zs,
-    withCompression);
-end;
-
-function TCurve25519.FromBigInteger(const x: TBigInteger): IECFieldElement;
-begin
-  result := TCurve25519FieldElement.Create(x);
-end;
-
-function TCurve25519.GetFieldSize: Int32;
-begin
-  result := Fq.BitLength;
-end;
-
-function TCurve25519.GetInfinity: IECPoint;
-begin
-  result := Fm_infinity;
-end;
-
-function TCurve25519.GetQ: TBigInteger;
-begin
-  result := Fq;
-end;
-
-function TCurve25519.SupportsCoordinateSystem(coord: Int32): Boolean;
-begin
-  case coord of
-    TECCurveConstants.COORD_JACOBIAN_MODIFIED:
-      result := true
-  else
-    result := false;
-  end;
-end;
-
-{ TCurve25519.TCurve25519LookupTable }
-
-constructor TCurve25519.TCurve25519LookupTable.Create(const outer: ICurve25519;
-  const table: TCryptoLibUInt32Array; size: Int32);
-begin
-  Inherited Create();
-  Fm_outer := outer;
-  Fm_table := table;
-  Fm_size := size;
-end;
-
-function TCurve25519.TCurve25519LookupTable.CreatePoint(const x,
-  y: TCryptoLibUInt32Array): IECPoint;
-var
-  XFieldElement, YFieldElement: ICurve25519FieldElement;
-  CURVE25519_AFFINE_ZS: TCryptoLibGenericArray<IECFieldElement>;
-  C_a: TBigInteger;
-begin
-  C_a := TBigInteger.Create(1,
-    THex.decode
-    ('2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144'));
-  CURVE25519_AFFINE_ZS := TCryptoLibGenericArray<IECFieldElement>.Create
-    (TCurve25519FieldElement.Create(TBigInteger.One) as ICurve25519FieldElement,
-    TCurve25519FieldElement.Create(C_a) as ICurve25519FieldElement);
-
-  XFieldElement := TCurve25519FieldElement.Create(x);
-  YFieldElement := TCurve25519FieldElement.Create(y);
-  result := Fm_outer.CreateRawPoint(XFieldElement, YFieldElement,
-    CURVE25519_AFFINE_ZS, false);
-end;
-
-function TCurve25519.TCurve25519LookupTable.GetSize: Int32;
-begin
-  result := Fm_size;
-end;
-
-function TCurve25519.TCurve25519LookupTable.Lookup(index: Int32): IECPoint;
-var
-  x, y: TCryptoLibUInt32Array;
-  pos, i, J: Int32;
-  MASK: UInt32;
-begin
-  x := TNat256.Create();
-  y := TNat256.Create();
-  pos := 0;
-
-  for i := 0 to System.Pred(Fm_size) do
-  begin
-    MASK := UInt32(TBitUtilities.Asr32((i xor index) - 1, 31));
-
-    for J := 0 to System.Pred(CURVE25519_FE_INTS) do
-    begin
-      x[J] := x[J] xor (Fm_table[pos + J] and MASK);
-      y[J] := y[J] xor (Fm_table[pos + CURVE25519_FE_INTS + J] and MASK);
-    end;
-
-    pos := pos + (CURVE25519_FE_INTS * 2);
-  end;
-
-  result := CreatePoint(x, y)
-end;
-
-function TCurve25519.TCurve25519LookupTable.LookupVar(index: Int32): IECPoint;
-var
-  x, y: TCryptoLibUInt32Array;
-  pos, J: Int32;
-begin
-  x := TNat256.Create();
-  y := TNat256.Create();
-  pos := index * CURVE25519_FE_INTS * 2;
-
-  for J := 0 to System.Pred(CURVE25519_FE_INTS) do
-  begin
-    x[J] := Fm_table[pos + J];
-    y[J] := Fm_table[pos + CURVE25519_FE_INTS + J];
-  end;
-
-  result := CreatePoint(x, y)
-end;
-
-end.

+ 147 - 169
CryptoLib/src/Math/EC/Rfc7748/ClpX25519.pas

@@ -22,127 +22,126 @@ unit ClpX25519;
 interface
 
 uses
-  ClpISecureRandom,
-  ClpX25519Field,
-  ClpEd25519,
   ClpArrayUtilities,
-  ClpConverters,
-  ClpCryptoLibTypes;
+  ClpBitUtilities,
+  ClpCryptoLibTypes,
+  ClpEd25519,
+  ClpISecureRandom,
+  ClpX25519Field;
+
+
+resourcestring
+  SInvalidKeyLength = 'Invalid key length';
 
 type
-  TX25519 = class sealed(TObject)
+  TX25519 = class sealed
   strict private
   const
-    C_A = Int32(486662);
-    C_A24 = Int32((C_A + 2) div 4);
-
+    C_A = 486662;
+    C_A24 = (C_A + 2) div 4;
+  class function Decode32(const Abs: TCryptoLibByteArray; AOff: Int32): UInt32; static;
+  class procedure DecodeScalar(const AK: TCryptoLibByteArray; AKOff: Int32;
+    AN: TCryptoLibUInt32Array); static;
+  class procedure PointDouble(AX, AZ: TCryptoLibInt32Array); static;
   public
+  const
+    PointSize = 32;
+    ScalarSize = 32;
 
-    const
-    PointSize = Int32(32);
-    ScalarSize = Int32(32);
-
-    class function CalculateAgreement(const k: TCryptoLibByteArray; kOff: Int32;
-      const u: TCryptoLibByteArray; uOff: Int32; const r: TCryptoLibByteArray;
-      rOff: Int32): Boolean; static; inline;
-
-    class function Decode32(const bs: TCryptoLibByteArray; off: Int32): UInt32;
-      static; inline;
-
-    class procedure DecodeScalar(const k: TCryptoLibByteArray; kOff: Int32;
-      const n: TCryptoLibUInt32Array); static; inline;
-
-    class procedure GeneratePrivateKey(const random: ISecureRandom;
-      const k: TCryptoLibByteArray); static; inline;
+    class function CalculateAgreement(const AK: TCryptoLibByteArray; AKOff: Int32;
+      const AU: TCryptoLibByteArray; AUOff: Int32; AR: TCryptoLibByteArray; AROff: Int32): Boolean; static;
 
-    class procedure GeneratePublicKey(const k: TCryptoLibByteArray; kOff: Int32;
-      r: TCryptoLibByteArray; rOff: Int32); static; inline;
+    class procedure ClampPrivateKey(AK: TCryptoLibByteArray); static;
 
-    class procedure PointDouble(const x, z: TCryptoLibInt32Array); static;
+    class procedure GeneratePrivateKey(const ARandom: ISecureRandom; const AK: TCryptoLibByteArray); static;
 
-    class procedure Precompute(); static;
+    class procedure GeneratePublicKey(const AK: TCryptoLibByteArray; AKOff: Int32;
+      AR: TCryptoLibByteArray; AROff: Int32); static;
 
-    class procedure ScalarMult(const k: TCryptoLibByteArray; kOff: Int32;
-      const u: TCryptoLibByteArray; uOff: Int32; const r: TCryptoLibByteArray;
-      rOff: Int32); static;
+    class procedure Precompute; static;
 
-    class procedure ScalarMultBase(const k: TCryptoLibByteArray; kOff: Int32;
-      const r: TCryptoLibByteArray; rOff: Int32); static;
+    class procedure ScalarMult(const AK: TCryptoLibByteArray; AKOff: Int32;
+      const AU: TCryptoLibByteArray; AUOff: Int32; AR: TCryptoLibByteArray; AROff: Int32); static;
 
+    class procedure ScalarMultBase(const AK: TCryptoLibByteArray; AKOff: Int32;
+      AR: TCryptoLibByteArray; AROff: Int32); static;
   end;
 
 implementation
 
 { TX25519 }
 
-class function TX25519.CalculateAgreement(const k: TCryptoLibByteArray;
-  kOff: Int32; const u: TCryptoLibByteArray; uOff: Int32;
-  const r: TCryptoLibByteArray; rOff: Int32): Boolean;
+class function TX25519.CalculateAgreement(const AK: TCryptoLibByteArray; AKOff: Int32;
+  const AU: TCryptoLibByteArray; AUOff: Int32; AR: TCryptoLibByteArray; AROff: Int32): Boolean;
+begin
+  ScalarMult(AK, AKOff, AU, AUOff, AR, AROff);
+  Result := not TArrayUtilities.AreAllZeroes(AR, AROff, PointSize);
+end;
+
+class procedure TX25519.ClampPrivateKey(AK: TCryptoLibByteArray);
 begin
-  ScalarMult(k, kOff, u, uOff, r, rOff);
-  result := not TArrayUtilities.AreAllZeroes(r, rOff, PointSize);
+  if System.Length(AK) <> ScalarSize then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidKeyLength);
+  AK[0] := AK[0] and $F8;
+  AK[ScalarSize - 1] := AK[ScalarSize - 1] and $7F;
+  AK[ScalarSize - 1] := AK[ScalarSize - 1] or $40;
 end;
 
-class function TX25519.Decode32(const bs: TCryptoLibByteArray;
-  off: Int32): UInt32;
+class function TX25519.Decode32(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32;
+var
+  LN: UInt32;
 begin
-  // UInt32 n := bs[off];
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 8);
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 16);
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 24);
-  // result := n;
-  result := TConverters.ReadBytesAsUInt32LE(PByte(bs), off);
+  LN := ABs[AOff];
+  LN := LN or (UInt32(ABs[AOff + 1]) shl 8);
+  LN := LN or (UInt32(ABs[AOff + 2]) shl 16);
+  LN := LN or (UInt32(ABs[AOff + 3]) shl 24);
+  Result := LN;
 end;
 
-class procedure TX25519.DecodeScalar(const k: TCryptoLibByteArray; kOff: Int32;
-  const n: TCryptoLibUInt32Array);
+class procedure TX25519.DecodeScalar(const AK: TCryptoLibByteArray; AKOff: Int32;
+  AN: TCryptoLibUInt32Array);
 var
-  i: Int32;
+  LI: Int32;
 begin
-  for i := 0 to System.Pred(8) do
+  LI := 0;
+  while LI < 8 do
   begin
-    n[i] := Decode32(k, kOff + i * 4);
+    AN[LI] := Decode32(AK, AKOff + LI * 4);
+    System.Inc(LI);
   end;
-
-  n[0] := n[0] and UInt32($FFFFFFF8);
-  n[7] := n[7] and UInt32($7FFFFFFF);
-  n[7] := n[7] or UInt32($40000000);
+  AN[0] := AN[0] and $FFFFFFF8;
+  AN[7] := AN[7] and $7FFFFFFF;
+  AN[7] := AN[7] or $40000000;
 end;
 
-class procedure TX25519.GeneratePrivateKey(const random: ISecureRandom;
-  const k: TCryptoLibByteArray);
+class procedure TX25519.GeneratePrivateKey(const ARandom: ISecureRandom; const AK: TCryptoLibByteArray);
 begin
-  random.NextBytes(k);
-
-  k[0] := k[0] and $F8;
-  k[ScalarSize - 1] := k[ScalarSize - 1] and $7F;
-  k[ScalarSize - 1] := k[ScalarSize - 1] or $40;
+  if System.Length(AK) <> ScalarSize then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidKeyLength);
+  ARandom.NextBytes(AK);
+  ClampPrivateKey(AK);
 end;
 
-class procedure TX25519.GeneratePublicKey(const k: TCryptoLibByteArray;
-  kOff: Int32; r: TCryptoLibByteArray; rOff: Int32);
+class procedure TX25519.GeneratePublicKey(const AK: TCryptoLibByteArray; AKOff: Int32;
+  AR: TCryptoLibByteArray; AROff: Int32);
 begin
-  ScalarMultBase(k, kOff, r, rOff);
+  ScalarMultBase(AK, AKOff, AR, AROff);
 end;
 
-class procedure TX25519.PointDouble(const x, z: TCryptoLibInt32Array);
+class procedure TX25519.PointDouble(AX, AZ: TCryptoLibInt32Array);
 var
-  A, B: TCryptoLibInt32Array;
+  LA, LB: TCryptoLibInt32Array;
 begin
-  A := TX25519Field.Create();
-  B := TX25519Field.Create();
-
-  TX25519Field.Apm(x, z, A, B);
-  TX25519Field.Sqr(A, A);
-  TX25519Field.Sqr(B, B);
-  TX25519Field.Mul(A, B, x);
-  TX25519Field.Sub(A, B, A);
-  TX25519Field.Mul(A, C_A24, z);
-  TX25519Field.Add(z, B, z);
-  TX25519Field.Mul(z, A, z);
+  LA := TX25519Field.Create();
+  LB := TX25519Field.Create();
+  TX25519Field.Apm(AX, AZ, LA, LB);
+  TX25519Field.Sqr(LA, LA);
+  TX25519Field.Sqr(LB, LB);
+  TX25519Field.Mul(LA, LB, AX);
+  TX25519Field.Sub(LA, LB, LA);
+  TX25519Field.Mul(LA, C_A24, AZ);
+  TX25519Field.Add(AZ, LB, AZ);
+  TX25519Field.Mul(AZ, LA, AZ);
 end;
 
 class procedure TX25519.Precompute;
@@ -150,100 +149,79 @@ begin
   TEd25519.Precompute();
 end;
 
-class procedure TX25519.ScalarMult(const k: TCryptoLibByteArray; kOff: Int32;
-  const u: TCryptoLibByteArray; uOff: Int32; const r: TCryptoLibByteArray;
-  rOff: Int32);
+class procedure TX25519.ScalarMult(const AK: TCryptoLibByteArray; AKOff: Int32;
+  const AU: TCryptoLibByteArray; AUOff: Int32; AR: TCryptoLibByteArray; AROff: Int32);
 var
-  n: TCryptoLibUInt32Array;
-  x1, x2, z2, x3, z3, t1, t2: TCryptoLibInt32Array;
-  bit, swap, word, shift, kt, i: Int32;
+  LN: TCryptoLibUInt32Array;
+  LX1, LX2, LZ2, LX3, LZ3: TCryptoLibInt32Array;
+  LT1, LT2: TCryptoLibInt32Array;
+  LBit, LSwap, LWord, LShift, LKt: Int32;
+  LI: Int32;
 begin
-  System.SetLength(n, 8);
-  DecodeScalar(k, kOff, n);
-
-  x1 := TX25519Field.Create();
-  TX25519Field.Decode(u, uOff, x1);
-  x2 := TX25519Field.Create();
-  TX25519Field.Copy(x1, 0, x2, 0);
-  z2 := TX25519Field.Create();
-  z2[0] := 1;
-  x3 := TX25519Field.Create();
-  x3[0] := 1;
-  z3 := TX25519Field.Create();
-
-  t1 := TX25519Field.Create();
-  t2 := TX25519Field.Create();
-
-{$IFDEF DEBUG}
-  System.Assert((n[7] shr 30) = UInt32(1));
-{$ENDIF DEBUG}
-  bit := 254;
-  swap := 1;
+  System.SetLength(LN, 8);
+  DecodeScalar(AK, AKOff, LN);
+  LX1 := TX25519Field.Create();
+  TX25519Field.Decode(AU, AUOff, LX1);
+  LX2 := TX25519Field.Create();
+  TX25519Field.Copy(LX1, 0, LX2, 0);
+  LZ2 := TX25519Field.Create();
+  LZ2[0] := 1;
+  LX3 := TX25519Field.Create();
+  LX3[0] := 1;
+  LZ3 := TX25519Field.Create();
+  LT1 := TX25519Field.Create();
+  LT2 := TX25519Field.Create();
+  LBit := 254;
+  LSwap := 1;
   repeat
-    TX25519Field.Apm(x3, z3, t1, x3);
-    TX25519Field.Apm(x2, z2, z3, x2);
-    TX25519Field.Mul(t1, x2, t1);
-    TX25519Field.Mul(x3, z3, x3);
-    TX25519Field.Sqr(z3, z3);
-    TX25519Field.Sqr(x2, x2);
-
-    TX25519Field.Sub(z3, x2, t2);
-    TX25519Field.Mul(t2, C_A24, z2);
-    TX25519Field.Add(z2, x2, z2);
-    TX25519Field.Mul(z2, t2, z2);
-    TX25519Field.Mul(x2, z3, x2);
-
-    TX25519Field.Apm(t1, x3, x3, z3);
-    TX25519Field.Sqr(x3, x3);
-    TX25519Field.Sqr(z3, z3);
-    TX25519Field.Mul(z3, x1, z3);
-
-    System.Dec(bit);
-
-    word := bit shr 5;
-    shift := bit and $1F;
-    kt := Int32(n[word] shr shift) and 1;
-    swap := swap xor kt;
-    TX25519Field.CSwap(swap, x2, x3);
-    TX25519Field.CSwap(swap, z2, z3);
-    swap := kt;
-
-  until (bit < 3);
-
-{$IFDEF DEBUG}
-  System.Assert(swap = 0);
-{$ENDIF DEBUG}
-  i := 0;
-  while i < 3 do
-  begin
-    PointDouble(x2, z2);
-    System.Inc(i);
-  end;
-
-  TX25519Field.Inv(z2, z2);
-  TX25519Field.Mul(x2, z2, x2);
-
-  TX25519Field.Normalize(x2);
-  TX25519Field.Encode(x2, r, rOff);
+    TX25519Field.Apm(LX3, LZ3, LT1, LX3);
+    TX25519Field.Apm(LX2, LZ2, LZ3, LX2);
+    TX25519Field.Mul(LT1, LX2, LT1);
+    TX25519Field.Mul(LX3, LZ3, LX3);
+    TX25519Field.Sqr(LZ3, LZ3);
+    TX25519Field.Sqr(LX2, LX2);
+    TX25519Field.Sub(LZ3, LX2, LT2);
+    TX25519Field.Mul(LT2, C_A24, LZ2);
+    TX25519Field.Add(LZ2, LX2, LZ2);
+    TX25519Field.Mul(LZ2, LT2, LZ2);
+    TX25519Field.Mul(LX2, LZ3, LX2);
+    TX25519Field.Apm(LT1, LX3, LX3, LZ3);
+    TX25519Field.Sqr(LX3, LX3);
+    TX25519Field.Sqr(LZ3, LZ3);
+    TX25519Field.Mul(LZ3, LX1, LZ3);
+    System.Dec(LBit);
+    LWord := TBitUtilities.Asr32(LBit, 5);
+    LShift := LBit and $1F;
+    LKt := Int32(LN[LWord] shr LShift) and 1;
+    LSwap := LSwap xor LKt;
+    TX25519Field.CSwap(LSwap, LX2, LX3);
+    TX25519Field.CSwap(LSwap, LZ2, LZ3);
+    LSwap := LKt;
+  until LBit < 3;
+  {$IFDEF DEBUG}
+  System.Assert(LSwap = 0);
+  {$ENDIF}
+  for LI := 0 to 2 do
+    PointDouble(LX2, LZ2);
+  TX25519Field.Inv(LZ2, LZ2);
+  TX25519Field.Mul(LX2, LZ2, LX2);
+  TX25519Field.Normalize(LX2);
+  TX25519Field.Encode(LX2, AR, AROff);
 end;
 
-class procedure TX25519.ScalarMultBase(const k: TCryptoLibByteArray;
-  kOff: Int32; const r: TCryptoLibByteArray; rOff: Int32);
+class procedure TX25519.ScalarMultBase(const AK: TCryptoLibByteArray; AKOff: Int32;
+  AR: TCryptoLibByteArray; AROff: Int32);
 var
-  y, z: TCryptoLibInt32Array;
+  LY, LZ: TCryptoLibInt32Array;
 begin
-  y := TX25519Field.Create();
-  z := TX25519Field.Create();
-
-  TEd25519.ScalarMultBaseYZ(k, kOff, y, z);
-
-  TX25519Field.Apm(z, y, y, z);
-
-  TX25519Field.Inv(z, z);
-  TX25519Field.Mul(y, z, y);
-
-  TX25519Field.Normalize(y);
-  TX25519Field.Encode(y, r, rOff);
+  LY := TX25519Field.Create();
+  LZ := TX25519Field.Create();
+  TEd25519.ScalarMultBaseYZ(AK, AKOff, LY, LZ);
+  TX25519Field.Apm(LZ, LY, LY, LZ);
+  TX25519Field.Inv(LZ, LZ);
+  TX25519Field.Mul(LY, LZ, LY);
+  TX25519Field.Normalize(LY);
+  TX25519Field.Encode(LY, AR, AROff);
 end;
 
 end.

+ 820 - 781
CryptoLib/src/Math/EC/Rfc7748/ClpX25519Field.pas

@@ -22,927 +22,966 @@ unit ClpX25519Field;
 interface
 
 uses
+  ClpMod,
   ClpBitUtilities,
-  ClpConverters,
   ClpArrayUtilities,
   ClpCryptoLibTypes;
 
 type
-  TX25519Field = class sealed(TObject)
-
+  TX25519Field = class sealed
+  public
+  const
+    Size = 10;
   strict private
-
   const
-    M24 = Int32($00FFFFFF);
-    M25 = Int32($01FFFFFF);
-    M26 = Int32($03FFFFFF);
-
-    class var
-
-      FRootNegOne: TCryptoLibInt32Array;
-
-    class procedure Decode128(const bs: TCryptoLibByteArray; off: Int32;
-      const z: TCryptoLibInt32Array; zOff: Int32); static; inline;
-
-    class function Decode32(const bs: TCryptoLibByteArray; off: Int32): UInt32;
-      static; inline;
-
-    class procedure Encode32(n: UInt32; const bs: TCryptoLibByteArray;
-      off: Int32); static; inline;
-
-    class procedure Encode128(const x: TCryptoLibInt32Array; xOff: Int32;
-      const bs: TCryptoLibByteArray; off: Int32); static; inline;
-
-    class procedure PowPm5d8(const x, rx2, rz: TCryptoLibInt32Array); static;
-
-    class procedure Reduce(const z: TCryptoLibInt32Array; c: Int32); static;
-
-    class procedure Boot(); static;
-    class constructor X25519Field();
-
+    M24 = $00FFFFFF;
+    M25 = $01FFFFFF;
+    M26 = $03FFFFFF;
+  class var
+    FP32: TCryptoLibUInt32Array;
+    FRootNegOne: TCryptoLibInt32Array;
+  class procedure Boot; static;
+  class constructor Create;
+  class procedure Decode128(const AX: TCryptoLibUInt32Array; AXOff: Int32;
+    const AZ: TCryptoLibInt32Array; AZOff: Int32); overload; static;
+  class procedure Decode128(const ABs: TCryptoLibByteArray; AOff: Int32;
+    const AZ: TCryptoLibInt32Array; AZOff: Int32); overload; static;
+  class function Decode32(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32; static;
+  class procedure Encode128(const AX: TCryptoLibInt32Array; AXOff: Int32;
+    const AZ: TCryptoLibUInt32Array; AZOff: Int32); overload; static;
+  class procedure Encode128(const AX: TCryptoLibInt32Array; AXOff: Int32;
+    const ABs: TCryptoLibByteArray; AOff: Int32); overload; static;
+  class procedure Encode32(AN: UInt32; const ABs: TCryptoLibByteArray; AOff: Int32); static;
+  class procedure PowPm5d8(const AX: TCryptoLibInt32Array; const ARx2: TCryptoLibInt32Array;
+    const ARz: TCryptoLibInt32Array); static;
+  class procedure Reduce(AZ: TCryptoLibInt32Array; AX: Int32); static;
   public
-
-    const
-    Size = Int32(10);
-
-    class procedure Add(const x, y, z: TCryptoLibInt32Array); static; inline;
-
-    class procedure AddOne(const z: TCryptoLibInt32Array); overload;
-      static; inline;
-
-    class procedure AddOne(const z: TCryptoLibInt32Array; zOff: Int32);
-      overload; static; inline;
-
-    class procedure Apm(const x, y, zp, zm: TCryptoLibInt32Array);
-      static; inline;
-
-    class procedure Carry(const z: TCryptoLibInt32Array); static;
-
-    class procedure CMov(cond: Int32; const x: TCryptoLibInt32Array;
-      xOff: Int32; const z: TCryptoLibInt32Array; zOff: Int32); static;
-
-    class procedure CNegate(ANegate: Int32; const z: TCryptoLibInt32Array);
-      static; inline;
-
-    class procedure Copy(const x: TCryptoLibInt32Array; xOff: Int32;
-      const z: TCryptoLibInt32Array; zOff: Int32); static; inline;
-
-    class function Create(): TCryptoLibInt32Array; static; inline;
-
-    class function CreateTable(n: Int32): TCryptoLibInt32Array; static; inline;
-
-    class procedure CSwap(swap: Int32;
-      const a, b: TCryptoLibInt32Array); static;
-
-    class procedure Decode(const x: TCryptoLibByteArray; xOff: Int32;
-      const z: TCryptoLibInt32Array); static; inline;
-
-    class procedure Encode(const x: TCryptoLibInt32Array;
-      const z: TCryptoLibByteArray; zOff: Int32); static; inline;
-
-    class procedure Inv(const x, z: TCryptoLibInt32Array); static; inline;
-
-    class function IsZero(const x: TCryptoLibInt32Array): Int32; static;
-
-    class function IsZeroVar(const x: TCryptoLibInt32Array): Boolean;
-      static; inline;
-
-    class procedure Mul(const x: TCryptoLibInt32Array; y: Int32;
-      const z: TCryptoLibInt32Array); overload; static;
-
-    class procedure Mul(const x, y, z: TCryptoLibInt32Array); overload; static;
-
-    class procedure Negate(const x, z: TCryptoLibInt32Array); static; inline;
-
-    class procedure Normalize(const z: TCryptoLibInt32Array); static; inline;
-
-    class procedure One(const z: TCryptoLibInt32Array); static; inline;
-
-    class procedure Sqr(const x, z: TCryptoLibInt32Array); overload; static;
-
-    class procedure Sqr(const x: TCryptoLibInt32Array; n: Int32;
-      const z: TCryptoLibInt32Array); overload; static;
-
-    class function SqrtRatioVar(const u, v, z: TCryptoLibInt32Array)
-      : Boolean; static;
-
-    class procedure Sub(const x, y, z: TCryptoLibInt32Array); static; inline;
-
-    class procedure SubOne(const z: TCryptoLibInt32Array); static; inline;
-
-    class procedure Zero(const z: TCryptoLibInt32Array); static; inline;
-
+    class procedure Add(const AX, AY, AZ: TCryptoLibInt32Array); static;
+    class procedure AddOne(const AZ: TCryptoLibInt32Array); overload; static;
+    class procedure AddOne(const AZ: TCryptoLibInt32Array; AZOff: Int32); overload; static;
+    class procedure Apm(const AX, AY, AZp, AZm: TCryptoLibInt32Array); static;
+    class function AreEqual(const AX, AY: TCryptoLibInt32Array): Int32; static;
+    class function AreEqualVar(const AX, AY: TCryptoLibInt32Array): Boolean; static;
+    class procedure Carry(AZ: TCryptoLibInt32Array); static;
+    class procedure CMov(ACond: Int32; const AX: TCryptoLibInt32Array; AXOff: Int32;
+      const AZ: TCryptoLibInt32Array; AZOff: Int32); static;
+    class procedure CNegate(ANegate: Int32; AZ: TCryptoLibInt32Array); static;
+    class procedure Copy(const AX: TCryptoLibInt32Array; AXOff: Int32;
+      const AZ: TCryptoLibInt32Array; AZOff: Int32); static;
+    class function Create: TCryptoLibInt32Array; static;
+    class function CreateTable(AN: Int32): TCryptoLibInt32Array; static;
+    class procedure CSwap(ASwap: Int32; AA, AB: TCryptoLibInt32Array); static;
+    class procedure Decode(const AX: TCryptoLibUInt32Array; AXOff: Int32;
+      AZ: TCryptoLibInt32Array); overload; static;
+    class procedure Decode(const ABs: TCryptoLibByteArray; AZ: TCryptoLibInt32Array); overload; static;
+    class procedure Decode(const ABs: TCryptoLibByteArray; ABsOff: Int32;
+      AZ: TCryptoLibInt32Array); overload; static;
+    class procedure Decode(const ABs: TCryptoLibByteArray; ABsOff: Int32;
+      const AZ: TCryptoLibInt32Array; AZOff: Int32); overload; static;
+    class procedure Encode(const AX: TCryptoLibInt32Array; const AZ: TCryptoLibUInt32Array;
+      AZOff: Int32); overload; static;
+    class procedure Encode(const AX: TCryptoLibInt32Array; const ABs: TCryptoLibByteArray); overload; static;
+    class procedure Encode(const AX: TCryptoLibInt32Array; const ABs: TCryptoLibByteArray;
+      ABsOff: Int32); overload; static;
+    class procedure Encode(const AX: TCryptoLibInt32Array; AXOff: Int32;
+      const ABs: TCryptoLibByteArray; ABsOff: Int32); overload; static;
+    class procedure Inv(const AX, AZ: TCryptoLibInt32Array); static;
+    class procedure InvVar(const AX, AZ: TCryptoLibInt32Array); static;
+    class function IsOne(const AX: TCryptoLibInt32Array): Int32; static;
+    class function IsOneVar(const AX: TCryptoLibInt32Array): Boolean; static;
+    class function IsZero(const AX: TCryptoLibInt32Array): Int32; static;
+    class function IsZeroVar(const AX: TCryptoLibInt32Array): Boolean; static;
+    class procedure Mul(const AX: TCryptoLibInt32Array; AY: Int32; const AZ: TCryptoLibInt32Array); overload; static;
+    class procedure Mul(const AX, AY, AZ: TCryptoLibInt32Array); overload; static;
+    class procedure Negate(const AX, AZ: TCryptoLibInt32Array); static;
+    class procedure Normalize(AZ: TCryptoLibInt32Array); static;
+    class procedure One(AZ: TCryptoLibInt32Array); static;
+    class procedure Sqr(const AX, AZ: TCryptoLibInt32Array); overload; static;
+    class procedure Sqr(const AX: TCryptoLibInt32Array; AN: Int32; const AZ: TCryptoLibInt32Array); overload; static;
+    class function SqrtRatioVar(const AU, AV, AZ: TCryptoLibInt32Array): Boolean; static;
+    class procedure Sub(const AX, AY, AZ: TCryptoLibInt32Array); static;
+    class procedure SubOne(AZ: TCryptoLibInt32Array); static;
+    class procedure Zero(AZ: TCryptoLibInt32Array); static;
   end;
 
 implementation
 
-{ TX25519Field }
-
-class procedure TX25519Field.Boot;
+class constructor TX25519Field.Create;
 begin
-  FRootNegOne := TCryptoLibInt32Array.Create($020EA0B0, $0386C9D2, $00478C4E,
-    $0035697F, $005E8630, $01FBD7A7, $0340264F, $01F0B2B4, $00027E0E,
-    $00570649);
+  Boot;
 end;
 
-class constructor TX25519Field.X25519Field;
+class procedure TX25519Field.Boot;
 begin
-  TX25519Field.Boot();
+  FP32 := TCryptoLibUInt32Array.Create($FFFFFFED, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $7FFFFFFF);
+  FRootNegOne := TCryptoLibInt32Array.Create(-$01F15F50, -$0079362D, $00478C4F, $0035697F,
+    $005E8630, $01FBD7A7, -$00BFD9B1, -$000F4D4B, $00027E0F, $00570649);
 end;
 
-class procedure TX25519Field.Add(const x, y, z: TCryptoLibInt32Array);
+class procedure TX25519Field.Add(const AX, AY, AZ: TCryptoLibInt32Array);
 var
-  i: Int32;
+  LI: Int32;
 begin
-  for i := 0 to System.Pred(Size) do
+  LI := 0;
+  while LI < Size do
   begin
-    z[i] := x[i] + y[i];
+    AZ[LI] := AX[LI] + AY[LI];
+    System.Inc(LI);
   end;
 end;
 
-class procedure TX25519Field.AddOne(const z: TCryptoLibInt32Array);
+class procedure TX25519Field.AddOne(const AZ: TCryptoLibInt32Array);
 begin
-  z[0] := z[0] + 1;
+  AZ[0] := AZ[0] + 1;
 end;
 
-class procedure TX25519Field.AddOne(const z: TCryptoLibInt32Array; zOff: Int32);
+class procedure TX25519Field.AddOne(const AZ: TCryptoLibInt32Array; AZOff: Int32);
 begin
-  z[zOff] := z[zOff] + 1;
+  AZ[AZOff] := AZ[AZOff] + 1;
 end;
 
-class procedure TX25519Field.Apm(const x, y, zp, zm: TCryptoLibInt32Array);
+class procedure TX25519Field.Apm(const AX, AY, AZp, AZm: TCryptoLibInt32Array);
 var
-  i, xi, yi: Int32;
+  LI: Int32;
+  LXi, LYi: Int32;
 begin
-  for i := 0 to System.Pred(Size) do
+  LI := 0;
+  while LI < Size do
   begin
-    xi := x[i];
-    yi := y[i];
-    zp[i] := xi + yi;
-    zm[i] := xi - yi;
+    LXi := AX[LI];
+    LYi := AY[LI];
+    AZp[LI] := LXi + LYi;
+    AZm[LI] := LXi - LYi;
+    System.Inc(LI);
   end;
 end;
 
-class procedure TX25519Field.Carry(const z: TCryptoLibInt32Array);
-var
-  z0, z1, z2, z3, z4, z5, z6, z7, z8, z9: Int32;
-begin
-  z0 := z[0];
-  z1 := z[1];
-  z2 := z[2];
-  z3 := z[3];
-  z4 := z[4];
-  z5 := z[5];
-  z6 := z[6];
-  z7 := z[7];
-  z8 := z[8];
-  z9 := z[9];
-
-  z3 := z3 + TBitUtilities.Asr32(z2, 25);
-  z2 := z2 and M25;
-  z5 := z5 + TBitUtilities.Asr32(z4, 25);
-  z4 := z4 and M25;
-  z8 := z8 + TBitUtilities.Asr32(z7, 25);
-  z7 := z7 and M25;
-  // z0 := z0 + (z9 shr 24) * 19; z9 := z9 and M24;
-  z0 := z0 + (TBitUtilities.Asr32(z9, 25) * 38);
-  z9 := z9 and M25;
-
-  z1 := z1 + TBitUtilities.Asr32(z0, 26);
-  z0 := z0 and M26;
-  z6 := z6 + TBitUtilities.Asr32(z5, 26);
-  z5 := z5 and M26;
-
-  z2 := z2 + TBitUtilities.Asr32(z1, 26);
-  z1 := z1 and M26;
-  z4 := z4 + TBitUtilities.Asr32(z3, 26);
-  z3 := z3 and M26;
-  z7 := z7 + TBitUtilities.Asr32(z6, 26);
-  z6 := z6 and M26;
-  z9 := z9 + TBitUtilities.Asr32(z8, 26);
-  z8 := z8 and M26;
-
-  z[0] := z0;
-  z[1] := z1;
-  z[2] := z2;
-  z[3] := z3;
-  z[4] := z4;
-  z[5] := z5;
-  z[6] := z6;
-  z[7] := z7;
-  z[8] := z8;
-  z[9] := z9;
-end;
-
-class procedure TX25519Field.CMov(cond: Int32; const x: TCryptoLibInt32Array;
-  xOff: Int32; const z: TCryptoLibInt32Array; zOff: Int32);
+class function TX25519Field.AreEqual(const AX, AY: TCryptoLibInt32Array): Int32;
 var
-  i, z_i, diff: Int32;
+  Ld: Int32;
+  LI: Int32;
 begin
-{$IFDEF DEBUG}
-  System.Assert((cond = 0) or (cond = -1));
-{$ENDIF DEBUG}
-  for i := 0 to System.Pred(Size) do
+  Ld := 0;
+  LI := 0;
+  while LI < Size do
   begin
-    z_i := z[zOff + i];
-    diff := z_i xor x[xOff + i];
-    z_i := z_i xor (diff and cond);
-    z[zOff + i] := z_i;
+    Ld := Ld or (AX[LI] xor AY[LI]);
+    System.Inc(LI);
   end;
+  Ld := Ld or TBitUtilities.Asr32(Ld, 16);
+  Ld := Ld and $FFFF;
+  Result := TBitUtilities.Asr32(Ld - 1, 31);
 end;
 
-class procedure TX25519Field.CNegate(ANegate: Int32;
-  const z: TCryptoLibInt32Array);
+class function TX25519Field.AreEqualVar(const AX, AY: TCryptoLibInt32Array): Boolean;
+begin
+  Result := AreEqual(AX, AY) <> 0;
+end;
+
+class procedure TX25519Field.Carry(AZ: TCryptoLibInt32Array);
+var
+  Lz0, Lz1, Lz2, Lz3, Lz4, Lz5, Lz6, Lz7, Lz8, Lz9: Int32;
+begin
+  Lz0 := AZ[0];
+  Lz1 := AZ[1];
+  Lz2 := AZ[2];
+  Lz3 := AZ[3];
+  Lz4 := AZ[4];
+  Lz5 := AZ[5];
+  Lz6 := AZ[6];
+  Lz7 := AZ[7];
+  Lz8 := AZ[8];
+  Lz9 := AZ[9];
+  Lz2 := Lz2 + TBitUtilities.Asr32(Lz1, 26);
+  Lz1 := Lz1 and M26;
+  Lz4 := Lz4 + TBitUtilities.Asr32(Lz3, 26);
+  Lz3 := Lz3 and M26;
+  Lz7 := Lz7 + TBitUtilities.Asr32(Lz6, 26);
+  Lz6 := Lz6 and M26;
+  Lz9 := Lz9 + TBitUtilities.Asr32(Lz8, 26);
+  Lz8 := Lz8 and M26;
+  Lz3 := Lz3 + TBitUtilities.Asr32(Lz2, 25);
+  Lz2 := Lz2 and M25;
+  Lz5 := Lz5 + TBitUtilities.Asr32(Lz4, 25);
+  Lz4 := Lz4 and M25;
+  Lz8 := Lz8 + TBitUtilities.Asr32(Lz7, 25);
+  Lz7 := Lz7 and M25;
+  Lz0 := Lz0 + TBitUtilities.Asr32(Lz9, 25) * 38;
+  Lz9 := Lz9 and M25;
+  Lz1 := Lz1 + TBitUtilities.Asr32(Lz0, 26);
+  Lz0 := Lz0 and M26;
+  Lz6 := Lz6 + TBitUtilities.Asr32(Lz5, 26);
+  Lz5 := Lz5 and M26;
+  Lz2 := Lz2 + TBitUtilities.Asr32(Lz1, 26);
+  Lz1 := Lz1 and M26;
+  Lz4 := Lz4 + TBitUtilities.Asr32(Lz3, 26);
+  Lz3 := Lz3 and M26;
+  Lz7 := Lz7 + TBitUtilities.Asr32(Lz6, 26);
+  Lz6 := Lz6 and M26;
+  Lz9 := Lz9 + TBitUtilities.Asr32(Lz8, 26);
+  Lz8 := Lz8 and M26;
+  AZ[0] := Lz0;
+  AZ[1] := Lz1;
+  AZ[2] := Lz2;
+  AZ[3] := Lz3;
+  AZ[4] := Lz4;
+  AZ[5] := Lz5;
+  AZ[6] := Lz6;
+  AZ[7] := Lz7;
+  AZ[8] := Lz8;
+  AZ[9] := Lz9;
+end;
+
+class procedure TX25519Field.CMov(ACond: Int32; const AX: TCryptoLibInt32Array; AXOff: Int32;
+  const AZ: TCryptoLibInt32Array; AZOff: Int32);
 var
-  mask, i: Int32;
+  LI: Int32;
+  LZi, Ldiff: Int32;
 begin
-{$IFDEF DEBUG}
-  System.Assert(TBitUtilities.Asr32(ANegate, 1) = 0);
-{$ENDIF DEBUG}
-  mask := 0 - ANegate;
-  for i := 0 to System.Pred(Size) do
+  LI := 0;
+  while LI < Size do
   begin
-    z[i] := (z[i] xor mask) - mask;
+    LZi := AZ[AZOff + LI];
+    Ldiff := LZi xor AX[AXOff + LI];
+    LZi := LZi xor (Ldiff and ACond);
+    AZ[AZOff + LI] := LZi;
+    System.Inc(LI);
   end;
 end;
 
-class procedure TX25519Field.Copy(const x: TCryptoLibInt32Array; xOff: Int32;
-  const z: TCryptoLibInt32Array; zOff: Int32);
+class procedure TX25519Field.CNegate(ANegate: Int32; AZ: TCryptoLibInt32Array);
 var
-  i: Int32;
+  LMask: Int32;
+  LI: Int32;
 begin
-  for i := 0 to System.Pred(Size) do
+  {$IFDEF DEBUG}
+  System.Assert(TBitUtilities.Asr32(ANegate, 1) = 0);
+  {$ENDIF}
+  LMask := 0 - ANegate;
+  LI := 0;
+  while LI < Size do
   begin
-    z[zOff + i] := x[xOff + i];
+    AZ[LI] := (AZ[LI] xor LMask) - LMask;
+    System.Inc(LI);
   end;
 end;
 
+class procedure TX25519Field.Copy(const AX: TCryptoLibInt32Array; AXOff: Int32;
+  const AZ: TCryptoLibInt32Array; AZOff: Int32);
+begin
+  System.Move(AX[AXOff], AZ[AZOff], Size * System.SizeOf(Int32));
+end;
+
 class function TX25519Field.Create: TCryptoLibInt32Array;
 begin
-  System.SetLength(Result, Size);
+  Result := TCryptoLibInt32Array.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 end;
 
-class function TX25519Field.CreateTable(n: Int32): TCryptoLibInt32Array;
+class function TX25519Field.CreateTable(AN: Int32): TCryptoLibInt32Array;
 begin
-  System.SetLength(Result, Size * n);
+  System.SetLength(Result, Size * AN);
 end;
 
-class procedure TX25519Field.CSwap(swap: Int32;
-  const a, b: TCryptoLibInt32Array);
+class procedure TX25519Field.CSwap(ASwap: Int32; AA, AB: TCryptoLibInt32Array);
 var
-  mask, i, ai, bi, dummy: Int32;
-begin
-{$IFDEF DEBUG}
-  System.Assert(TBitUtilities.Asr32(swap, 1) = 0);
-  System.Assert(a <> b);
-{$ENDIF DEBUG}
-  mask := 0 - swap;
-  for i := 0 to System.Pred(Size) do
+  Lmask: Int32;
+  LI: Int32;
+  Lai, Lbi, Ldummy: Int32;
+begin
+  Lmask := 0 - ASwap;
+  LI := 0;
+  while LI < Size do
   begin
-    ai := a[i];
-    bi := b[i];
-    dummy := mask and (ai xor bi);
-    a[i] := ai xor dummy;
-    b[i] := bi xor dummy;
+    Lai := AA[LI];
+    Lbi := AB[LI];
+    Ldummy := Lmask and (Lai xor Lbi);
+    AA[LI] := Lai xor Ldummy;
+    AB[LI] := Lbi xor Ldummy;
+    System.Inc(LI);
   end;
 end;
 
-class function TX25519Field.Decode32(const bs: TCryptoLibByteArray;
-  off: Int32): UInt32;
+class function TX25519Field.Decode32(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32;
+var
+  LOff: Int32;
 begin
-  // UInt32 n := bs[off];
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 8);
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 16);
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 24);
-  // result := n;
-  Result := TConverters.ReadBytesAsUInt32LE(PByte(bs), off);
+  LOff := AOff;
+  Result := UInt32(ABs[LOff]);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 8);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 16);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 24);
 end;
 
-class procedure TX25519Field.Decode128(const bs: TCryptoLibByteArray;
-  off: Int32; const z: TCryptoLibInt32Array; zOff: Int32);
+class procedure TX25519Field.Decode128(const AX: TCryptoLibUInt32Array; AXOff: Int32;
+  const AZ: TCryptoLibInt32Array; AZOff: Int32);
 var
-  t0, t1, t2, t3: UInt32;
+  Lt0, Lt1, Lt2, Lt3: UInt32;
 begin
-  t0 := Decode32(bs, off + 0);
-  t1 := Decode32(bs, off + 4);
-  t2 := Decode32(bs, off + 8);
-  t3 := Decode32(bs, off + 12);
-
-  z[zOff + 0] := Int32(t0 and M26);
-  z[zOff + 1] := Int32((t1 shl 6) or (t0 shr 26)) and M26;
-  z[zOff + 2] := Int32((t2 shl 12) or (t1 shr 20)) and M25;
-  z[zOff + 3] := Int32((t3 shl 19) or (t2 shr 13)) and M26;
-  z[zOff + 4] := Int32(t3 shr 7);
+  Lt0 := AX[AXOff + 0];
+  Lt1 := AX[AXOff + 1];
+  Lt2 := AX[AXOff + 2];
+  Lt3 := AX[AXOff + 3];
+  AZ[AZOff + 0] := Int32(Lt0) and M26;
+  AZ[AZOff + 1] := Int32((Lt1 shl 6) or (Lt0 shr 26)) and M26;
+  AZ[AZOff + 2] := Int32((Lt2 shl 12) or (Lt1 shr 20)) and M25;
+  AZ[AZOff + 3] := Int32((Lt3 shl 19) or (Lt2 shr 13)) and M26;
+  AZ[AZOff + 4] := Int32(Lt3 shr 7);
 end;
 
-class procedure TX25519Field.Decode(const x: TCryptoLibByteArray; xOff: Int32;
-  const z: TCryptoLibInt32Array);
+class procedure TX25519Field.Decode128(const ABs: TCryptoLibByteArray; AOff: Int32;
+  const AZ: TCryptoLibInt32Array; AZOff: Int32);
+var
+  Lt0, Lt1, Lt2, Lt3: UInt32;
 begin
-  Decode128(x, xOff, z, 0);
-  Decode128(x, xOff + 16, z, 5);
-  z[9] := z[9] and M24;
+  Lt0 := Decode32(ABs, AOff + 0);
+  Lt1 := Decode32(ABs, AOff + 4);
+  Lt2 := Decode32(ABs, AOff + 8);
+  Lt3 := Decode32(ABs, AOff + 12);
+  AZ[AZOff + 0] := Int32(Lt0) and M26;
+  AZ[AZOff + 1] := Int32((Lt1 shl 6) or (Lt0 shr 26)) and M26;
+  AZ[AZOff + 2] := Int32((Lt2 shl 12) or (Lt1 shr 20)) and M25;
+  AZ[AZOff + 3] := Int32((Lt3 shl 19) or (Lt2 shr 13)) and M26;
+  AZ[AZOff + 4] := Int32(Lt3 shr 7);
 end;
 
-class procedure TX25519Field.Encode32(n: UInt32; const bs: TCryptoLibByteArray;
-  off: Int32);
+class procedure TX25519Field.Decode(const AX: TCryptoLibUInt32Array; AXOff: Int32;
+  AZ: TCryptoLibInt32Array);
 begin
-  // bs[  off] := Byte(n      );
-  // System.Inc(off);
-  // bs[off] := Byte(n shr  8);
-  // System.Inc(off);
-  // bs[off] := Byte(n shr  16);
-  // System.Inc(off);
-  // bs[off] := Byte(n shr  24);
-  TConverters.ReadUInt32AsBytesLE(n, bs, off);
+  Decode128(AX, AXOff, AZ, 0);
+  Decode128(AX, AXOff + 4, AZ, 5);
+  AZ[9] := AZ[9] and M24;
 end;
 
-class procedure TX25519Field.Encode128(const x: TCryptoLibInt32Array;
-  xOff: Int32; const bs: TCryptoLibByteArray; off: Int32);
-var
-  x0, x1, x2, x3, x4, t0, t1, t2, t3: UInt32;
+class procedure TX25519Field.Decode(const ABs: TCryptoLibByteArray; AZ: TCryptoLibInt32Array);
 begin
-  x0 := UInt32(x[xOff + 0]);
-  x1 := UInt32(x[xOff + 1]);
-  x2 := UInt32(x[xOff + 2]);
-  x3 := UInt32(x[xOff + 3]);
-  x4 := UInt32(x[xOff + 4]);
+  Decode(ABs, 0, AZ);
+end;
 
-  t0 := x0 or (x1 shl 26);
-  Encode32(t0, bs, off + 0);
-  t1 := (x1 shr 6) or (x2 shl 20);
-  Encode32(t1, bs, off + 4);
-  t2 := (x2 shr 12) or (x3 shl 13);
-  Encode32(t2, bs, off + 8);
-  t3 := (x3 shr 19) or (x4 shl 7);
-  Encode32(t3, bs, off + 12);
+class procedure TX25519Field.Decode(const ABs: TCryptoLibByteArray; ABsOff: Int32;
+  AZ: TCryptoLibInt32Array);
+begin
+  Decode128(ABs, ABsOff, AZ, 0);
+  Decode128(ABs, ABsOff + 16, AZ, 5);
+  AZ[9] := AZ[9] and M24;
 end;
 
-class procedure TX25519Field.Encode(const x: TCryptoLibInt32Array;
-  const z: TCryptoLibByteArray; zOff: Int32);
+class procedure TX25519Field.Decode(const ABs: TCryptoLibByteArray; ABsOff: Int32;
+  const AZ: TCryptoLibInt32Array; AZOff: Int32);
 begin
-  Encode128(x, 0, z, zOff);
-  Encode128(x, 5, z, zOff + 16);
+  Decode128(ABs, ABsOff, AZ, AZOff);
+  Decode128(ABs, ABsOff + 16, AZ, AZOff + 5);
+  AZ[AZOff + 9] := AZ[AZOff + 9] and M24;
 end;
 
-class procedure TX25519Field.Inv(const x, z: TCryptoLibInt32Array);
+class procedure TX25519Field.Encode32(AN: UInt32; const ABs: TCryptoLibByteArray; AOff: Int32);
 var
-  x2, t: TCryptoLibInt32Array;
+  LOff: Int32;
 begin
-  // z = x^(p-2) = x^7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB
-  // (250 1s) (1 0s) (1 1s) (1 0s) (2 1s)
-  // Addition chain: [1] [2] 3 5 10 15 25 50 75 125 [250]
+  LOff := AOff;
+  ABs[LOff] := Byte(AN);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 8);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 16);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 24);
+end;
 
-  x2 := Create();
-  t := Create();
-  PowPm5d8(x, x2, t);
-  Sqr(t, 3, t);
-  Mul(t, x2, z);
+class procedure TX25519Field.Encode128(const AX: TCryptoLibInt32Array; AXOff: Int32;
+  const AZ: TCryptoLibUInt32Array; AZOff: Int32);
+var
+  Lx0, Lx1, Lx2, Lx3, Lx4: UInt32;
+begin
+  Lx0 := UInt32(AX[AXOff + 0]);
+  Lx1 := UInt32(AX[AXOff + 1]);
+  Lx2 := UInt32(AX[AXOff + 2]);
+  Lx3 := UInt32(AX[AXOff + 3]);
+  Lx4 := UInt32(AX[AXOff + 4]);
+  AZ[AZOff + 0] := Lx0 or (Lx1 shl 26);
+  AZ[AZOff + 1] := (Lx1 shr 6) or (Lx2 shl 20);
+  AZ[AZOff + 2] := (Lx2 shr 12) or (Lx3 shl 13);
+  AZ[AZOff + 3] := (Lx3 shr 19) or (Lx4 shl 7);
 end;
 
-class function TX25519Field.IsZero(const x: TCryptoLibInt32Array): Int32;
+class procedure TX25519Field.Encode128(const AX: TCryptoLibInt32Array; AXOff: Int32;
+  const ABs: TCryptoLibByteArray; AOff: Int32);
 var
-  d, i: Int32;
+  Lx0, Lx1, Lx2, Lx3, Lx4: UInt32;
+  Lt0, Lt1, Lt2, Lt3: UInt32;
 begin
-  d := 0;
-  for i := 0 to System.Pred(Size) do
-  begin
-    d := d or x[i];
-  end;
-  d := (TBitUtilities.Asr32(d, 1)) or (d and 1);
-  Result := (d - 1) shr 31;
+  Lx0 := UInt32(AX[AXOff + 0]);
+  Lx1 := UInt32(AX[AXOff + 1]);
+  Lx2 := UInt32(AX[AXOff + 2]);
+  Lx3 := UInt32(AX[AXOff + 3]);
+  Lx4 := UInt32(AX[AXOff + 4]);
+  Lt0 := Lx0 or (Lx1 shl 26);
+  Encode32(Lt0, ABs, AOff + 0);
+  Lt1 := (Lx1 shr 6) or (Lx2 shl 20);
+  Encode32(Lt1, ABs, AOff + 4);
+  Lt2 := (Lx2 shr 12) or (Lx3 shl 13);
+  Encode32(Lt2, ABs, AOff + 8);
+  Lt3 := (Lx3 shr 19) or (Lx4 shl 7);
+  Encode32(Lt3, ABs, AOff + 12);
 end;
 
-class function TX25519Field.IsZeroVar(const x: TCryptoLibInt32Array): Boolean;
+class procedure TX25519Field.Encode(const AX: TCryptoLibInt32Array; const AZ: TCryptoLibUInt32Array;
+  AZOff: Int32);
 begin
-  Result := IsZero(x) <> 0;
+  Encode128(AX, 0, AZ, AZOff);
+  Encode128(AX, 5, AZ, AZOff + 4);
 end;
 
-class procedure TX25519Field.Mul(const x: TCryptoLibInt32Array; y: Int32;
-  const z: TCryptoLibInt32Array);
+class procedure TX25519Field.Encode(const AX: TCryptoLibInt32Array; const ABs: TCryptoLibByteArray);
+begin
+  Encode128(AX, 0, ABs, 0);
+  Encode128(AX, 5, ABs, 16);
+end;
+
+class procedure TX25519Field.Encode(const AX: TCryptoLibInt32Array; const ABs: TCryptoLibByteArray;
+  ABsOff: Int32);
+begin
+  Encode128(AX, 0, ABs, ABsOff);
+  Encode128(AX, 5, ABs, ABsOff + 16);
+end;
+
+class procedure TX25519Field.Encode(const AX: TCryptoLibInt32Array; AXOff: Int32;
+  const ABs: TCryptoLibByteArray; ABsOff: Int32);
+begin
+  Encode128(AX, AXOff, ABs, ABsOff);
+  Encode128(AX, AXOff + 5, ABs, ABsOff + 16);
+end;
+
+class procedure TX25519Field.Inv(const AX, AZ: TCryptoLibInt32Array);
 var
-  x0, x1, x2, x3, x4, x5, x6, x7, x8, x9: Int32;
-  c0, c1, c2, c3: Int64;
-begin
-  x0 := x[0];
-  x1 := x[1];
-  x2 := x[2];
-  x3 := x[3];
-  x4 := x[4];
-  x5 := x[5];
-  x6 := x[6];
-  x7 := x[7];
-  x8 := x[8];
-  x9 := x[9];
-
-  c0 := Int64(x2) * y;
-  x2 := Int32(c0) and M25;
-  c0 := TBitUtilities.Asr64(c0, 25);
-  c1 := Int64(x4) * y;
-  x4 := Int32(c1) and M25;
-  c1 := TBitUtilities.Asr64(c1, 25);
-  c2 := Int64(x7) * y;
-  x7 := Int32(c2) and M25;
-  c2 := TBitUtilities.Asr64(c2, 25);
-  // c3 := Int64(x9) * y; x9 := Int32(c3) and M24; c3 := TBitUtilities.Asr64(c3 , 24);
-  // c3 := c3 * 19;
-  c3 := Int64(x9) * y;
-  x9 := Int32(c3) and M25;
-  c3 := TBitUtilities.Asr64(c3, 25);
-  c3 := c3 * 38;
-
-  c3 := c3 + (Int64(x0) * y);
-  z[0] := Int32(c3) and M26;
-  c3 := TBitUtilities.Asr64(c3, 26);
-  c1 := c1 + (Int64(x5) * y);
-  z[5] := Int32(c1) and M26;
-  c1 := TBitUtilities.Asr64(c1, 26);
-
-  c3 := c3 + (Int64(x1) * y);
-  z[1] := Int32(c3) and M26;
-  c3 := TBitUtilities.Asr64(c3, 26);
-  c0 := c0 + (Int64(x3) * y);
-  z[3] := Int32(c0) and M26;
-  c0 := TBitUtilities.Asr64(c0, 26);
-  c1 := c1 + (Int64(x6) * y);
-  z[6] := Int32(c1) and M26;
-  c1 := TBitUtilities.Asr64(c1, 26);
-  c2 := c2 + (Int64(x8) * y);
-  z[8] := Int32(c2) and M26;
-  c2 := TBitUtilities.Asr64(c2, 26);
-
-  z[2] := x2 + Int32(c3);
-  z[4] := x4 + Int32(c0);
-  z[7] := x7 + Int32(c1);
-  z[9] := x9 + Int32(c2);
-end;
-
-class procedure TX25519Field.Mul(const x, y, z: TCryptoLibInt32Array);
+  Lt: TCryptoLibInt32Array;
+  Lu: TCryptoLibUInt32Array;
+begin
+  Lt := Create;
+  System.SetLength(Lu, 8);
+  Copy(AX, 0, Lt, 0);
+  Normalize(Lt);
+  Encode(Lt, Lu, 0);
+  TMod.ModOddInverse(FP32, Lu, Lu);
+  Decode(Lu, 0, AZ);
+end;
+
+class procedure TX25519Field.InvVar(const AX, AZ: TCryptoLibInt32Array);
 var
-  x0, x1, x2, x3, x4, y0, y1, y2, y3, y4, u0, u1, u2, u3, u4, z8, z9: Int32;
-  a0, a1, a2, a3, a4, a5, a6, a7, a8, b0, b1, b2, b3, b4, b5, b6, b7, b8, c0,
-    c1, c2, c3, c4, c5, c6, c7, c8, v0, v1, v2, v3, v4, t: Int64;
-begin
-  x0 := x[0];
-  y0 := y[0];
-  x1 := x[1];
-  y1 := y[1];
-  x2 := x[2];
-  y2 := y[2];
-  x3 := x[3];
-  y3 := y[3];
-  x4 := x[4];
-  y4 := y[4];
-
-  u0 := x[5];
-  v0 := y[5];
-  u1 := x[6];
-  v1 := y[6];
-  u2 := x[7];
-  v2 := y[7];
-  u3 := x[8];
-  v3 := y[8];
-  u4 := x[9];
-  v4 := y[9];
-
-  a0 := Int64(x0) * y0;
-  a1 := Int64(x0) * y1 + Int64(x1) * y0;
-  a2 := Int64(x0) * y2 + Int64(x1) * y1 + Int64(x2) * y0;
-  a3 := Int64(x1) * y2 + Int64(x2) * y1;
-  a3 := a3 shl 1;
-  a3 := a3 + (Int64(x0) * y3 + Int64(x3) * y0);
-  a4 := Int64(x2) * y2;
-  a4 := a4 shl 1;
-  a4 := a4 + (Int64(x0) * y4 + Int64(x1) * y3 + Int64(x3) * y1 +
-    Int64(x4) * y0);
-  a5 := Int64(x1) * y4 + Int64(x2) * y3 + Int64(x3) * y2 + Int64(x4) * y1;
-  a5 := a5 shl 1;
-  a6 := Int64(x2) * y4 + Int64(x4) * y2;
-  a6 := a6 shl 1;
-  a6 := a6 + (Int64(x3) * y3);
-  a7 := Int64(x3) * y4 + Int64(x4) * y3;
-  a8 := Int64(x4) * y4;
-  a8 := a8 shl 1;
-
-  b0 := Int64(u0) * v0;
-  b1 := Int64(u0) * v1 + Int64(u1) * v0;
-  b2 := Int64(u0) * v2 + Int64(u1) * v1 + Int64(u2) * v0;
-  b3 := Int64(u1) * v2 + Int64(u2) * v1;
-  b3 := b3 shl 1;
-  b3 := b3 + (Int64(u0) * v3 + Int64(u3) * v0);
-  b4 := Int64(u2) * v2;
-  b4 := b4 shl 1;
-  b4 := b4 + (Int64(u0) * v4 + Int64(u1) * v3 + Int64(u3) * v1 +
-    Int64(u4) * v0);
-  b5 := Int64(u1) * v4 + Int64(u2) * v3 + Int64(u3) * v2 + Int64(u4) * v1;
-  // b5     := b5 shl 1;
-  b6 := Int64(u2) * v4 + Int64(u4) * v2;
-  b6 := b6 shl 1;
-  b6 := b6 + (Int64(u3) * v3);
-  b7 := Int64(u3) * v4 + Int64(u4) * v3;
-  b8 := Int64(u4) * v4;
-  // b8     := b8 shl 1;
-
-  a0 := a0 - (b5 * 76);
-  a1 := a1 - (b6 * 38);
-  a2 := a2 - (b7 * 38);
-  a3 := a3 - (b8 * 76);
-
-  a5 := a5 - b0;
-  a6 := a6 - b1;
-  a7 := a7 - b2;
-  a8 := a8 - b3;
-  // a9 := -b4;
-
-  x0 := x0 + u0;
-  y0 := y0 + v0;
-  x1 := x1 + u1;
-  y1 := y1 + v1;
-  x2 := x2 + u2;
-  y2 := y2 + v2;
-  x3 := x3 + u3;
-  y3 := y3 + v3;
-  x4 := x4 + u4;
-  y4 := y4 + v4;
-
-  c0 := Int64(x0) * y0;
-  c1 := Int64(x0) * y1 + Int64(x1) * y0;
-  c2 := Int64(x0) * y2 + Int64(x1) * y1 + Int64(x2) * y0;
-  c3 := Int64(x1) * y2 + Int64(x2) * y1;
-  c3 := c3 shl 1;
-  c3 := c3 + (Int64(x0) * y3 + Int64(x3) * y0);
-  c4 := Int64(x2) * y2;
-  c4 := c4 shl 1;
-  c4 := c4 + (Int64(x0) * y4 + Int64(x1) * y3 + Int64(x3) * y1 +
-    Int64(x4) * y0);
-  c5 := Int64(x1) * y4 + Int64(x2) * y3 + Int64(x3) * y2 + Int64(x4) * y1;
-  c5 := c5 shl 1;
-  c6 := Int64(x2) * y4 + Int64(x4) * y2;
-  c6 := c6 shl 1;
-  c6 := c6 + (Int64(x3) * y3);
-  c7 := Int64(x3) * y4 + Int64(x4) * y3;
-  c8 := Int64(x4) * y4;
-  c8 := c8 shl 1;
-
-  t := a8 + (c3 - a3);
-  z8 := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  // t       := t + (a9 + (c4 - a4));
-  t := t + ((c4 - a4) - b4);
-  // z9       := Int32(t) and M24; t := TBitUtilities.Asr64(t , 24);
-  // t        := a0 + (t + ((c5 - a5) shl 1)) * 19;
-  z9 := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := a0 + (t + c5 - a5) * 38;
-  z[0] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a1 + (c6 - a6) * 38);
-  z[1] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a2 + (c7 - a7) * 38);
-  z[2] := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := t + (a3 + (c8 - a8) * 38);
-  z[3] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  // t       := t + (a4 - (a9 * 38));
-  t := t + (a4 + b4 * 38);
-  z[4] := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := t + (a5 + (c0 - a0));
-  z[5] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a6 + (c1 - a1));
-  z[6] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a7 + (c2 - a2));
-  z[7] := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := t + z8;
-  z[8] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  z[9] := z9 + Int32(t);
-end;
-
-class procedure TX25519Field.Negate(const x, z: TCryptoLibInt32Array);
+  Lt: TCryptoLibInt32Array;
+  Lu: TCryptoLibUInt32Array;
+begin
+  Lt := Create;
+  System.SetLength(Lu, 8);
+  Copy(AX, 0, Lt, 0);
+  Normalize(Lt);
+  Encode(Lt, Lu, 0);
+  TMod.ModOddInverseVar(FP32, Lu, Lu);
+  Decode(Lu, 0, AZ);
+end;
+
+class function TX25519Field.IsOne(const AX: TCryptoLibInt32Array): Int32;
 var
-  i: Int32;
+  Ld: Int32;
+  LI: Int32;
 begin
-  for i := 0 to System.Pred(Size) do
+  Ld := AX[0] xor 1;
+  LI := 1;
+  while LI < Size do
   begin
-    z[i] := -x[i];
+    Ld := Ld or AX[LI];
+    System.Inc(LI);
   end;
+  Ld := Ld or TBitUtilities.Asr32(Ld, 16);
+  Ld := Ld and $FFFF;
+  Result := TBitUtilities.Asr32(Ld - 1, 31);
 end;
 
-class procedure TX25519Field.Normalize(const z: TCryptoLibInt32Array);
-var
-  x: Int32;
+class function TX25519Field.IsOneVar(const AX: TCryptoLibInt32Array): Boolean;
 begin
-  x := TBitUtilities.Asr32(z[9], 23) and 1;
-  Reduce(z, x);
-  Reduce(z, -x);
-{$IFDEF DEBUG}
-  System.Assert(TBitUtilities.Asr32(z[9], 24) = 0);
-{$ENDIF DEBUG}
+  Result := IsOne(AX) <> 0;
 end;
 
-class procedure TX25519Field.One(const z: TCryptoLibInt32Array);
+class function TX25519Field.IsZero(const AX: TCryptoLibInt32Array): Int32;
 var
-  i: Int32;
+  Ld: Int32;
+  LI: Int32;
 begin
-  z[0] := 1;
-  for i := 1 to System.Pred(Size) do
+  Ld := 0;
+  LI := 0;
+  while LI < Size do
   begin
-    z[i] := 0;
+    Ld := Ld or AX[LI];
+    System.Inc(LI);
   end;
+  Ld := Ld or TBitUtilities.Asr32(Ld, 16);
+  Ld := Ld and $FFFF;
+  Result := TBitUtilities.Asr32(Ld - 1, 31);
 end;
 
-class procedure TX25519Field.PowPm5d8(const x, rx2, rz: TCryptoLibInt32Array);
+class function TX25519Field.IsZeroVar(const AX: TCryptoLibInt32Array): Boolean;
+begin
+  Result := IsZero(AX) <> 0;
+end;
+
+class procedure TX25519Field.Mul(const AX: TCryptoLibInt32Array; AY: Int32; const AZ: TCryptoLibInt32Array);
 var
-  x2, x3, x5, x10, x15, x25, x50, x75, x125, x250, t: TCryptoLibInt32Array;
-begin
-  // z = x^((p-5)/8) = x^FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD
-  // (250 1s) (1 0s) (1 1s)
-  // Addition chain: [1] 2 3 5 10 15 25 50 75 125 [250]
-
-  x2 := rx2;
-  Sqr(x, x2);
-  Mul(x, x2, x2);
-  x3 := Create();
-  Sqr(x2, x3);
-  Mul(x, x3, x3);
-  x5 := x3;
-  Sqr(x3, 2, x5);
-  Mul(x2, x5, x5);
-  x10 := Create();
-  Sqr(x5, 5, x10);
-  Mul(x5, x10, x10);
-  x15 := Create();
-  Sqr(x10, 5, x15);
-  Mul(x5, x15, x15);
-  x25 := x5;
-  Sqr(x15, 10, x25);
-  Mul(x10, x25, x25);
-  x50 := x10;
-  Sqr(x25, 25, x50);
-  Mul(x25, x50, x50);
-  x75 := x15;
-  Sqr(x50, 25, x75);
-  Mul(x25, x75, x75);
-  x125 := x25;
-  Sqr(x75, 50, x125);
-  Mul(x50, x125, x125);
-  x250 := x50;
-  Sqr(x125, 125, x250);
-  Mul(x125, x250, x250);
-
-  t := x125;
-  Sqr(x250, 2, t);
-  Mul(t, x, rz);
-end;
-
-class procedure TX25519Field.Reduce(const z: TCryptoLibInt32Array; c: Int32);
+  Lx0, Lx1, Lx2, Lx3, Lx4, Lx5, Lx6, Lx7, Lx8, Lx9: Int32;
+  Lc0, Lc1, Lc2, Lc3: Int64;
+begin
+  Lx0 := AX[0];
+  Lx1 := AX[1];
+  Lx2 := AX[2];
+  Lx3 := AX[3];
+  Lx4 := AX[4];
+  Lx5 := AX[5];
+  Lx6 := AX[6];
+  Lx7 := AX[7];
+  Lx8 := AX[8];
+  Lx9 := AX[9];
+  Lc0 := Int64(Lx2) * AY;
+  Lx2 := Int32(Lc0) and M25;
+  Lc0 := TBitUtilities.Asr64(Lc0, 25);
+  Lc1 := Int64(Lx4) * AY;
+  Lx4 := Int32(Lc1) and M25;
+  Lc1 := TBitUtilities.Asr64(Lc1, 25);
+  Lc2 := Int64(Lx7) * AY;
+  Lx7 := Int32(Lc2) and M25;
+  Lc2 := TBitUtilities.Asr64(Lc2, 25);
+  Lc3 := Int64(Lx9) * AY;
+  Lx9 := Int32(Lc3) and M25;
+  Lc3 := TBitUtilities.Asr64(Lc3, 25);
+  Lc3 := Lc3 * 38;
+  Lc3 := Lc3 + Int64(Lx0) * AY;
+  AZ[0] := Int32(Lc3) and M26;
+  Lc3 := TBitUtilities.Asr64(Lc3, 26);
+  Lc1 := Lc1 + Int64(Lx5) * AY;
+  AZ[5] := Int32(Lc1) and M26;
+  Lc1 := TBitUtilities.Asr64(Lc1, 26);
+  Lc3 := Lc3 + Int64(Lx1) * AY;
+  AZ[1] := Int32(Lc3) and M26;
+  Lc3 := TBitUtilities.Asr64(Lc3, 26);
+  Lc0 := Lc0 + Int64(Lx3) * AY;
+  AZ[3] := Int32(Lc0) and M26;
+  Lc0 := TBitUtilities.Asr64(Lc0, 26);
+  Lc1 := Lc1 + Int64(Lx6) * AY;
+  AZ[6] := Int32(Lc1) and M26;
+  Lc1 := TBitUtilities.Asr64(Lc1, 26);
+  Lc2 := Lc2 + Int64(Lx8) * AY;
+  AZ[8] := Int32(Lc2) and M26;
+  Lc2 := TBitUtilities.Asr64(Lc2, 26);
+  AZ[2] := Lx2 + Int32(Lc3);
+  AZ[4] := Lx4 + Int32(Lc0);
+  AZ[7] := Lx7 + Int32(Lc1);
+  AZ[9] := Lx9 + Int32(Lc2);
+end;
+
+class procedure TX25519Field.Mul(const AX, AY, AZ: TCryptoLibInt32Array);
 var
-  z9, t: Int32;
-begin
-  z9 := z[9];
-  t := z9;
-  z9 := t and M24;
-  t := TBitUtilities.Asr32(t, 24);
-  t := t + c;
-  t := t * 19;
-  t := t + z[0];
-  z[0] := t and M26;
-  t := TBitUtilities.Asr32(t, 26);
-  t := t + z[1];
-  z[1] := t and M26;
-  t := TBitUtilities.Asr32(t, 26);
-  t := t + z[2];
-  z[2] := t and M25;
-  t := TBitUtilities.Asr32(t, 25);
-  t := t + z[3];
-  z[3] := t and M26;
-  t := TBitUtilities.Asr32(t, 26);
-  t := t + z[4];
-  z[4] := t and M25;
-  t := TBitUtilities.Asr32(t, 25);
-  t := t + z[5];
-  z[5] := t and M26;
-  t := TBitUtilities.Asr32(t, 26);
-  t := t + z[6];
-  z[6] := t and M26;
-  t := TBitUtilities.Asr32(t, 26);
-  t := t + z[7];
-  z[7] := t and M25;
-  t := TBitUtilities.Asr32(t, 25);
-  t := t + z[8];
-  z[8] := t and M26;
-  t := TBitUtilities.Asr32(t, 26);
-  t := t + z9;
-  z[9] := t;
-end;
-
-class procedure TX25519Field.Sqr(const x, z: TCryptoLibInt32Array);
+  Lx0, Ly0, Lx1, Ly1, Lx2, Ly2, Lx3, Ly3, Lx4, Ly4: Int32;
+  Lu0, Lv0, Lu1, Lv1, Lu2, Lv2, Lu3, Lv3, Lu4, Lv4: Int32;
+  La0, La1, La2, La3, La4, La5, La6, La7, La8: Int64;
+  Lb0, Lb1, Lb2, Lb3, Lb4, Lb5, Lb6, Lb7, Lb8: Int64;
+  Lc0, Lc1, Lc2, Lc3, Lc4, Lc5, Lc6, Lc7, Lc8: Int64;
+  Lt: Int64;
+  Lz8, Lz9: Int32;
+begin
+  Lx0 := AX[0];
+  Ly0 := AY[0];
+  Lx1 := AX[1];
+  Ly1 := AY[1];
+  Lx2 := AX[2];
+  Ly2 := AY[2];
+  Lx3 := AX[3];
+  Ly3 := AY[3];
+  Lx4 := AX[4];
+  Ly4 := AY[4];
+  Lu0 := AX[5];
+  Lv0 := AY[5];
+  Lu1 := AX[6];
+  Lv1 := AY[6];
+  Lu2 := AX[7];
+  Lv2 := AY[7];
+  Lu3 := AX[8];
+  Lv3 := AY[8];
+  Lu4 := AX[9];
+  Lv4 := AY[9];
+  La0 := Int64(Lx0) * Ly0;
+  La1 := Int64(Lx0) * Ly1 + Int64(Lx1) * Ly0;
+  La2 := Int64(Lx0) * Ly2 + Int64(Lx1) * Ly1 + Int64(Lx2) * Ly0;
+  La3 := (Int64(Lx1) * Ly2 + Int64(Lx2) * Ly1) shl 1;
+  La3 := La3 + Int64(Lx0) * Ly3 + Int64(Lx3) * Ly0;
+  La4 := (Int64(Lx2) * Ly2) shl 1;
+  La4 := La4 + Int64(Lx0) * Ly4 + Int64(Lx1) * Ly3 + Int64(Lx3) * Ly1 + Int64(Lx4) * Ly0;
+  La5 := (Int64(Lx1) * Ly4 + Int64(Lx2) * Ly3 + Int64(Lx3) * Ly2 + Int64(Lx4) * Ly1) shl 1;
+  La6 := (Int64(Lx2) * Ly4 + Int64(Lx4) * Ly2) shl 1 + Int64(Lx3) * Ly3;
+  La7 := Int64(Lx3) * Ly4 + Int64(Lx4) * Ly3;
+  La8 := (Int64(Lx4) * Ly4) shl 1;
+  Lb0 := Int64(Lu0) * Lv0;
+  Lb1 := Int64(Lu0) * Lv1 + Int64(Lu1) * Lv0;
+  Lb2 := Int64(Lu0) * Lv2 + Int64(Lu1) * Lv1 + Int64(Lu2) * Lv0;
+  Lb3 := (Int64(Lu1) * Lv2 + Int64(Lu2) * Lv1) shl 1;
+  Lb3 := Lb3 + Int64(Lu0) * Lv3 + Int64(Lu3) * Lv0;
+  Lb4 := (Int64(Lu2) * Lv2) shl 1;
+  Lb4 := Lb4 + Int64(Lu0) * Lv4 + Int64(Lu1) * Lv3 + Int64(Lu3) * Lv1 + Int64(Lu4) * Lv0;
+  Lb5 := Int64(Lu1) * Lv4 + Int64(Lu2) * Lv3 + Int64(Lu3) * Lv2 + Int64(Lu4) * Lv1;
+  Lb6 := (Int64(Lu2) * Lv4 + Int64(Lu4) * Lv2) shl 1 + Int64(Lu3) * Lv3;
+  Lb7 := Int64(Lu3) * Lv4 + Int64(Lu4) * Lv3;
+  Lb8 := Int64(Lu4) * Lv4;
+  La0 := La0 - Lb5 * 76;
+  La1 := La1 - Lb6 * 38;
+  La2 := La2 - Lb7 * 38;
+  La3 := La3 - Lb8 * 76;
+  La5 := La5 - Lb0;
+  La6 := La6 - Lb1;
+  La7 := La7 - Lb2;
+  La8 := La8 - Lb3;
+  Lx0 := Lx0 + Lu0;
+  Ly0 := Ly0 + Lv0;
+  Lx1 := Lx1 + Lu1;
+  Ly1 := Ly1 + Lv1;
+  Lx2 := Lx2 + Lu2;
+  Ly2 := Ly2 + Lv2;
+  Lx3 := Lx3 + Lu3;
+  Ly3 := Ly3 + Lv3;
+  Lx4 := Lx4 + Lu4;
+  Ly4 := Ly4 + Lv4;
+  Lc0 := Int64(Lx0) * Ly0;
+  Lc1 := Int64(Lx0) * Ly1 + Int64(Lx1) * Ly0;
+  Lc2 := Int64(Lx0) * Ly2 + Int64(Lx1) * Ly1 + Int64(Lx2) * Ly0;
+  Lc3 := (Int64(Lx1) * Ly2 + Int64(Lx2) * Ly1) shl 1;
+  Lc3 := Lc3 + Int64(Lx0) * Ly3 + Int64(Lx3) * Ly0;
+  Lc4 := (Int64(Lx2) * Ly2) shl 1;
+  Lc4 := Lc4 + Int64(Lx0) * Ly4 + Int64(Lx1) * Ly3 + Int64(Lx3) * Ly1 + Int64(Lx4) * Ly0;
+  Lc5 := (Int64(Lx1) * Ly4 + Int64(Lx2) * Ly3 + Int64(Lx3) * Ly2 + Int64(Lx4) * Ly1) shl 1;
+  Lc6 := (Int64(Lx2) * Ly4 + Int64(Lx4) * Ly2) shl 1 + Int64(Lx3) * Ly3;
+  Lc7 := Int64(Lx3) * Ly4 + Int64(Lx4) * Ly3;
+  Lc8 := (Int64(Lx4) * Ly4) shl 1;
+  Lt := La8 + (Lc3 - La3);
+  Lz8 := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + (Lc4 - La4) - Lb4;
+  Lz9 := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := La0 + (Lt + Lc5 - La5) * 38;
+  AZ[0] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La1 + (Lc6 - La6) * 38;
+  AZ[1] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La2 + (Lc7 - La7) * 38;
+  AZ[2] := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := Lt + La3 + (Lc8 - La8) * 38;
+  AZ[3] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La4 + Lb4 * 38;
+  AZ[4] := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := Lt + La5 + (Lc0 - La0);
+  AZ[5] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La6 + (Lc1 - La1);
+  AZ[6] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La7 + (Lc2 - La2);
+  AZ[7] := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := Lt + Lz8;
+  AZ[8] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  AZ[9] := Lz9 + Int32(Lt);
+end;
+
+class procedure TX25519Field.Negate(const AX, AZ: TCryptoLibInt32Array);
 var
-  x0, x1, x2, x3, x4, u0, u1, u2, u3, u4, x1_2, x2_2, x3_2, x4_2, u1_2, u2_2,
-    u3_2, u4_2, z8, z9: Int32;
-  a0, a1, a2, a3, a4, a5, a6, a7, a8, b0, b1, b2, b3, b4, b5, b6, b7, b8, c0,
-    c1, c2, c3, c4, c5, c6, c7, c8, t: Int64;
-begin
-  x0 := x[0];
-  x1 := x[1];
-  x2 := x[2];
-  x3 := x[3];
-  x4 := x[4];
-
-  u0 := x[5];
-  u1 := x[6];
-  u2 := x[7];
-  u3 := x[8];
-  u4 := x[9];
-
-  x1_2 := x1 * 2;
-  x2_2 := x2 * 2;
-  x3_2 := x3 * 2;
-  x4_2 := x4 * 2;
-
-  a0 := Int64(x0) * x0;
-  a1 := Int64(x0) * x1_2;
-  a2 := Int64(x0) * x2_2 + Int64(x1) * x1;
-  a3 := Int64(x1_2) * x2_2 + Int64(x0) * x3_2;
-  a4 := Int64(x2) * x2_2 + Int64(x0) * x4_2 + Int64(x1) * x3_2;
-  a5 := Int64(x1_2) * x4_2 + Int64(x2_2) * x3_2;
-  a6 := Int64(x2_2) * x4_2 + Int64(x3) * x3;
-  a7 := Int64(x3) * x4_2;
-  a8 := Int64(x4) * x4_2;
-
-  u1_2 := u1 * 2;
-  u2_2 := u2 * 2;
-  u3_2 := u3 * 2;
-  u4_2 := u4 * 2;
-
-  b0 := Int64(u0) * u0;
-  b1 := Int64(u0) * u1_2;
-  b2 := Int64(u0) * u2_2 + Int64(u1) * u1;
-  b3 := Int64(u1_2) * u2_2 + Int64(u0) * u3_2;
-  b4 := Int64(u2) * u2_2 + Int64(u0) * u4_2 + Int64(u1) * u3_2;
-  b5 := Int64(u1_2) * u4_2 + Int64(u2_2) * u3_2;
-  b6 := Int64(u2_2) * u4_2 + Int64(u3) * u3;
-  b7 := Int64(u3) * u4_2;
-  b8 := Int64(u4) * u4_2;
-
-  a0 := a0 - (b5 * 38);
-  a1 := a1 - (b6 * 38);
-  a2 := a2 - (b7 * 38);
-  a3 := a3 - (b8 * 38);
-
-  a5 := a5 - b0;
-  a6 := a6 - b1;
-  a7 := a7 - b2;
-  a8 := a8 - b3;
-  // Int64 a9 = -b4;
-
-  x0 := x0 + u0;
-  x1 := x1 + u1;
-  x2 := x2 + u2;
-  x3 := x3 + u3;
-  x4 := x4 + u4;
-
-  x1_2 := x1 * 2;
-  x2_2 := x2 * 2;
-  x3_2 := x3 * 2;
-  x4_2 := x4 * 2;
-
-  c0 := Int64(x0) * x0;
-  c1 := Int64(x0) * x1_2;
-  c2 := Int64(x0) * x2_2 + Int64(x1) * x1;
-  c3 := Int64(x1_2) * x2_2 + Int64(x0) * x3_2;
-  c4 := Int64(x2) * x2_2 + Int64(x0) * x4_2 + Int64(x1) * x3_2;
-  c5 := Int64(x1_2) * x4_2 + Int64(x2_2) * x3_2;
-  c6 := Int64(x2_2) * x4_2 + Int64(x3) * x3;
-  c7 := Int64(x3) * x4_2;
-  c8 := Int64(x4) * x4_2;
-
-  t := a8 + (c3 - a3);
-  z8 := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  // t  = t + (a9 + (c4 - a4));
-  t := t + ((c4 - a4) - b4);
-  // z9  := Int32(t) and M24; t := TBitUtilities.Asr64(t , 24);
-  // t  := a0 + (t + ((c5 - a5) shl 1)) * 19;
-  z9 := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := a0 + (t + c5 - a5) * 38;
-  z[0] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a1 + (c6 - a6) * 38);
-  z[1] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a2 + (c7 - a7) * 38);
-  z[2] := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := t + (a3 + (c8 - a8) * 38);
-  z[3] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  // t       := t + (a4 - a9 * 38);
-  t := t + (a4 + b4 * 38);
-  z[4] := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := t + (a5 + (c0 - a0));
-  z[5] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a6 + (c1 - a1));
-  z[6] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  t := t + (a7 + (c2 - a2));
-  z[7] := Int32(t) and M25;
-  t := TBitUtilities.Asr64(t, 25);
-  t := t + z8;
-  z[8] := Int32(t) and M26;
-  t := TBitUtilities.Asr64(t, 26);
-  z[9] := z9 + Int32(t);
-end;
-
-class procedure TX25519Field.Sqr(const x: TCryptoLibInt32Array; n: Int32;
-  const z: TCryptoLibInt32Array);
-begin
-{$IFDEF DEBUG}
-  System.Assert(n > 0);
-{$ENDIF DEBUG}
-  Sqr(x, z);
-  System.Dec(n);
-
-  while (n > 0) do
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < Size do
   begin
-    Sqr(z, z);
-    System.Dec(n);
+    AZ[LI] := -AX[LI];
+    System.Inc(LI);
   end;
 end;
 
-class procedure TX25519Field.Sub(const x, y, z: TCryptoLibInt32Array);
+class procedure TX25519Field.Reduce(AZ: TCryptoLibInt32Array; AX: Int32);
 var
-  i: Int32;
+  Lt, Lz9: Int32;
+  Lcc: Int64;
+begin
+  Lt := AZ[9];
+  Lz9 := Lt and M24;
+  Lt := TBitUtilities.Asr32(Lt, 24) + AX;
+  Lcc := Int64(Lt) * 19;
+  Lcc := Lcc + AZ[0];
+  AZ[0] := Int32(Lcc) and M26;
+  Lcc := TBitUtilities.Asr64(Lcc, 26);
+  Lcc := Lcc + AZ[1];
+  AZ[1] := Int32(Lcc) and M26;
+  Lcc := TBitUtilities.Asr64(Lcc, 26);
+  Lcc := Lcc + AZ[2];
+  AZ[2] := Int32(Lcc) and M25;
+  Lcc := TBitUtilities.Asr64(Lcc, 25);
+  Lcc := Lcc + AZ[3];
+  AZ[3] := Int32(Lcc) and M26;
+  Lcc := TBitUtilities.Asr64(Lcc, 26);
+  Lcc := Lcc + AZ[4];
+  AZ[4] := Int32(Lcc) and M25;
+  Lcc := TBitUtilities.Asr64(Lcc, 25);
+  Lcc := Lcc + AZ[5];
+  AZ[5] := Int32(Lcc) and M26;
+  Lcc := TBitUtilities.Asr64(Lcc, 26);
+  Lcc := Lcc + AZ[6];
+  AZ[6] := Int32(Lcc) and M26;
+  Lcc := TBitUtilities.Asr64(Lcc, 26);
+  Lcc := Lcc + AZ[7];
+  AZ[7] := Int32(Lcc) and M25;
+  Lcc := TBitUtilities.Asr64(Lcc, 25);
+  Lcc := Lcc + AZ[8];
+  AZ[8] := Int32(Lcc) and M26;
+  Lcc := TBitUtilities.Asr64(Lcc, 26);
+  AZ[9] := Lz9 + Int32(Lcc);
+end;
+
+class procedure TX25519Field.Normalize(AZ: TCryptoLibInt32Array);
+var
+  Lx: Int32;
 begin
-  for i := 0 to System.Pred(Size) do
-  begin
-    z[i] := x[i] - y[i];
-  end;
+  Lx := TBitUtilities.Asr32(AZ[9], 23) and 1;
+  Reduce(AZ, Lx);
+  Reduce(AZ, -Lx);
+  {$IFDEF DEBUG}
+  System.Assert(TBitUtilities.Asr32(AZ[9], 24) = 0);
+  {$ENDIF}
 end;
 
-class procedure TX25519Field.SubOne(const z: TCryptoLibInt32Array);
+class procedure TX25519Field.One(AZ: TCryptoLibInt32Array);
 begin
-  z[0] := z[0] - 1;
+  AZ[0] := 1;
+  TArrayUtilities.Fill<Int32>(AZ, 1, Size, 0);
 end;
 
-class function TX25519Field.SqrtRatioVar(const u, v,
-  z: TCryptoLibInt32Array): Boolean;
+class procedure TX25519Field.PowPm5d8(const AX: TCryptoLibInt32Array; const ARx2: TCryptoLibInt32Array;
+  const ARz: TCryptoLibInt32Array);
 var
-  uv3, uv7, t, x, vx2: TCryptoLibInt32Array;
-begin
-  uv3 := Create();
-  uv7 := Create();
-
-  Mul(u, v, uv3);
-  Sqr(v, uv7);
-  Mul(uv3, uv7, uv3);
-  Sqr(uv7, uv7);
-  Mul(uv7, uv3, uv7);
-
-  t := Create();
-  x := Create();
-  PowPm5d8(uv7, t, x);
-  Mul(x, uv3, x);
-
-  vx2 := Create();
-  Sqr(x, vx2);
-  Mul(vx2, v, vx2);
+  Lx2, Lx3, Lx5, Lx10, Lx15, Lx25, Lx50, Lx75, Lx125, Lx250, Lt: TCryptoLibInt32Array;
+begin
+  Lx2 := ARx2;
+  Sqr(AX, Lx2);
+  Mul(AX, Lx2, Lx2);
+  Lx3 := Create;
+  Sqr(Lx2, Lx3);
+  Mul(AX, Lx3, Lx3);
+  Lx5 := Lx3;
+  Sqr(Lx3, 2, Lx5);
+  Mul(Lx2, Lx5, Lx5);
+  Lx10 := Create;
+  Sqr(Lx5, 5, Lx10);
+  Mul(Lx5, Lx10, Lx10);
+  Lx15 := Create;
+  Sqr(Lx10, 5, Lx15);
+  Mul(Lx5, Lx15, Lx15);
+  Lx25 := Lx5;
+  Sqr(Lx15, 10, Lx25);
+  Mul(Lx10, Lx25, Lx25);
+  Lx50 := Lx10;
+  Sqr(Lx25, 25, Lx50);
+  Mul(Lx25, Lx50, Lx50);
+  Lx75 := Lx15;
+  Sqr(Lx50, 25, Lx75);
+  Mul(Lx25, Lx75, Lx75);
+  Lx125 := Lx25;
+  Sqr(Lx75, 50, Lx125);
+  Mul(Lx50, Lx125, Lx125);
+  Lx250 := Lx50;
+  Sqr(Lx125, 125, Lx250);
+  Mul(Lx125, Lx250, Lx250);
+  Lt := Lx125;
+  Sqr(Lx250, 2, Lt);
+  Mul(Lt, AX, ARz);
+end;
+
+class procedure TX25519Field.Sqr(const AX, AZ: TCryptoLibInt32Array);
+var
+  Lx0, Lx1, Lx2, Lx3, Lx4, Lu0, Lu1, Lu2, Lu3, Lu4: Int32;
+  Lx1_2, Lx2_2, Lx3_2, Lx4_2, Lu1_2, Lu2_2, Lu3_2, Lu4_2: Int32;
+  La0, La1, La2, La3, La4, La5, La6, La7, La8: Int64;
+  Lb0, Lb1, Lb2, Lb3, Lb4, Lb5, Lb6, Lb7, Lb8: Int64;
+  Lc0, Lc1, Lc2, Lc3, Lc4, Lc5, Lc6, Lc7, Lc8: Int64;
+  Lt: Int64;
+  Lz8, Lz9: Int32;
+begin
+  Lx0 := AX[0];
+  Lx1 := AX[1];
+  Lx2 := AX[2];
+  Lx3 := AX[3];
+  Lx4 := AX[4];
+  Lu0 := AX[5];
+  Lu1 := AX[6];
+  Lu2 := AX[7];
+  Lu3 := AX[8];
+  Lu4 := AX[9];
+  Lx1_2 := Lx1 * 2;
+  Lx2_2 := Lx2 * 2;
+  Lx3_2 := Lx3 * 2;
+  Lx4_2 := Lx4 * 2;
+  La0 := Int64(Lx0) * Lx0;
+  La1 := Int64(Lx0) * Lx1_2;
+  La2 := Int64(Lx0) * Lx2_2 + Int64(Lx1) * Lx1;
+  La3 := Int64(Lx1_2) * Lx2_2 + Int64(Lx0) * Lx3_2;
+  La4 := Int64(Lx2) * Lx2_2 + Int64(Lx0) * Lx4_2 + Int64(Lx1) * Lx3_2;
+  La5 := Int64(Lx1_2) * Lx4_2 + Int64(Lx2_2) * Lx3_2;
+  La6 := Int64(Lx2_2) * Lx4_2 + Int64(Lx3) * Lx3;
+  La7 := Int64(Lx3) * Lx4_2;
+  La8 := Int64(Lx4) * Lx4_2;
+  Lu1_2 := Lu1 * 2;
+  Lu2_2 := Lu2 * 2;
+  Lu3_2 := Lu3 * 2;
+  Lu4_2 := Lu4 * 2;
+  Lb0 := Int64(Lu0) * Lu0;
+  Lb1 := Int64(Lu0) * Lu1_2;
+  Lb2 := Int64(Lu0) * Lu2_2 + Int64(Lu1) * Lu1;
+  Lb3 := Int64(Lu1_2) * Lu2_2 + Int64(Lu0) * Lu3_2;
+  Lb4 := Int64(Lu2) * Lu2_2 + Int64(Lu0) * Lu4_2 + Int64(Lu1) * Lu3_2;
+  Lb5 := Int64(Lu1_2) * Lu4_2 + Int64(Lu2_2) * Lu3_2;
+  Lb6 := Int64(Lu2_2) * Lu4_2 + Int64(Lu3) * Lu3;
+  Lb7 := Int64(Lu3) * Lu4_2;
+  Lb8 := Int64(Lu4) * Lu4_2;
+  La0 := La0 - Lb5 * 38;
+  La1 := La1 - Lb6 * 38;
+  La2 := La2 - Lb7 * 38;
+  La3 := La3 - Lb8 * 38;
+  La5 := La5 - Lb0;
+  La6 := La6 - Lb1;
+  La7 := La7 - Lb2;
+  La8 := La8 - Lb3;
+  Lx0 := Lx0 + Lu0;
+  Lx1 := Lx1 + Lu1;
+  Lx2 := Lx2 + Lu2;
+  Lx3 := Lx3 + Lu3;
+  Lx4 := Lx4 + Lu4;
+  Lx1_2 := Lx1 * 2;
+  Lx2_2 := Lx2 * 2;
+  Lx3_2 := Lx3 * 2;
+  Lx4_2 := Lx4 * 2;
+  Lc0 := Int64(Lx0) * Lx0;
+  Lc1 := Int64(Lx0) * Lx1_2;
+  Lc2 := Int64(Lx0) * Lx2_2 + Int64(Lx1) * Lx1;
+  Lc3 := Int64(Lx1_2) * Lx2_2 + Int64(Lx0) * Lx3_2;
+  Lc4 := Int64(Lx2) * Lx2_2 + Int64(Lx0) * Lx4_2 + Int64(Lx1) * Lx3_2;
+  Lc5 := Int64(Lx1_2) * Lx4_2 + Int64(Lx2_2) * Lx3_2;
+  Lc6 := Int64(Lx2_2) * Lx4_2 + Int64(Lx3) * Lx3;
+  Lc7 := Int64(Lx3) * Lx4_2;
+  Lc8 := Int64(Lx4) * Lx4_2;
+  Lt := La8 + (Lc3 - La3);
+  Lz8 := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + (Lc4 - La4) - Lb4;
+  Lz9 := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := La0 + (Lt + Lc5 - La5) * 38;
+  AZ[0] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La1 + (Lc6 - La6) * 38;
+  AZ[1] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La2 + (Lc7 - La7) * 38;
+  AZ[2] := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := Lt + La3 + (Lc8 - La8) * 38;
+  AZ[3] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La4 + Lb4 * 38;
+  AZ[4] := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := Lt + La5 + (Lc0 - La0);
+  AZ[5] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La6 + (Lc1 - La1);
+  AZ[6] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  Lt := Lt + La7 + (Lc2 - La2);
+  AZ[7] := Int32(Lt) and M25;
+  Lt := TBitUtilities.Asr64(Lt, 25);
+  Lt := Lt + Lz8;
+  AZ[8] := Int32(Lt) and M26;
+  Lt := TBitUtilities.Asr64(Lt, 26);
+  AZ[9] := Lz9 + Int32(Lt);
+end;
+
+class procedure TX25519Field.Sqr(const AX: TCryptoLibInt32Array; AN: Int32; const AZ: TCryptoLibInt32Array);
+begin
+  {$IFDEF DEBUG}
+  System.Assert(AN > 0);
+  {$ENDIF}
+  Sqr(AX, AZ);
+  while AN > 1 do
+  begin
+    System.Dec(AN);
+    Sqr(AZ, AZ);
+  end;
+end;
 
-  Sub(vx2, u, t);
-  Normalize(t);
-  if (IsZeroVar(t)) then
+class function TX25519Field.SqrtRatioVar(const AU, AV, AZ: TCryptoLibInt32Array): Boolean;
+var
+  Luv3, Luv7, Lt, Lx, Lvx2: TCryptoLibInt32Array;
+begin
+  Luv3 := Create;
+  Luv7 := Create;
+  Mul(AU, AV, Luv3);
+  Sqr(AV, Luv7);
+  Mul(Luv3, Luv7, Luv3);
+  Sqr(Luv7, Luv7);
+  Mul(Luv7, Luv3, Luv7);
+  Lt := Create;
+  Lx := Create;
+  PowPm5d8(Luv7, Lt, Lx);
+  Mul(Lx, Luv3, Lx);
+  Lvx2 := Create;
+  Sqr(Lx, Lvx2);
+  Mul(Lvx2, AV, Lvx2);
+  Sub(Lvx2, AU, Lt);
+  Normalize(Lt);
+  if IsZeroVar(Lt) then
+  begin
+    Copy(Lx, 0, AZ, 0);
+    Exit(True);
+  end;
+  Add(Lvx2, AU, Lt);
+  Normalize(Lt);
+  if IsZeroVar(Lt) then
   begin
-    Copy(x, 0, z, 0);
-    Result := true;
-    Exit;
+    Mul(Lx, FRootNegOne, AZ);
+    Exit(True);
   end;
+  Result := False;
+end;
 
-  Add(vx2, u, t);
-  Normalize(t);
-  if (IsZeroVar(t)) then
+class procedure TX25519Field.Sub(const AX, AY, AZ: TCryptoLibInt32Array);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < Size do
   begin
-    Mul(x, FRootNegOne, z);
-    Result := true;
-    Exit;
+    AZ[LI] := AX[LI] - AY[LI];
+    System.Inc(LI);
   end;
+end;
 
-  Result := false;
+class procedure TX25519Field.SubOne(AZ: TCryptoLibInt32Array);
+begin
+  AZ[0] := AZ[0] - 1;
 end;
 
-class procedure TX25519Field.Zero(const z: TCryptoLibInt32Array);
+class procedure TX25519Field.Zero(AZ: TCryptoLibInt32Array);
 begin
-  TArrayUtilities.Fill<Int32>(z, 0, Size, Int32(0));
+  TArrayUtilities.Fill<Int32>(AZ, 0, Size, 0);
 end;
 
 end.
+

+ 140 - 0
CryptoLib/src/Math/EC/Rfc8032/ClpCodec.pas

@@ -0,0 +1,140 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpCodec;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpCryptoLibTypes;
+
+type
+  TCodec = class sealed
+  public
+    class function Decode16(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32; static;
+    class function Decode24(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32; static;
+    class function Decode32(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32; overload; static;
+    class procedure Decode32(const ABs: TCryptoLibByteArray; ABsOff: Int32;
+      AN: TCryptoLibUInt32Array; ANOff: Int32; ANLen: Int32); overload; static;
+    class procedure Encode24(AN: UInt32; const ABs: TCryptoLibByteArray; AOff: Int32); static;
+    class procedure Encode32(AN: UInt32; const ABs: TCryptoLibByteArray; AOff: Int32); overload; static;
+    class procedure Encode32(const AN: TCryptoLibUInt32Array; ANOff: Int32; ANLen: Int32;
+      const ABs: TCryptoLibByteArray; ABsOff: Int32); overload; static;
+    class procedure Encode56(AN: UInt64; ABs: TCryptoLibByteArray; AOff: Int32); static;
+  end;
+
+implementation
+
+{ TCodec }
+
+class function TCodec.Decode16(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32;
+var
+  LOff: Int32;
+begin
+  LOff := AOff;
+  Result := UInt32(ABs[LOff]);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 8);
+end;
+
+class function TCodec.Decode24(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32;
+var
+  LOff: Int32;
+begin
+  LOff := AOff;
+  Result := UInt32(ABs[LOff]);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 8);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 16);
+end;
+
+class function TCodec.Decode32(const ABs: TCryptoLibByteArray; AOff: Int32): UInt32;
+var
+  LOff: Int32;
+begin
+  LOff := AOff;
+  Result := UInt32(ABs[LOff]);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 8);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 16);
+  System.Inc(LOff);
+  Result := Result or (UInt32(ABs[LOff]) shl 24);
+end;
+
+class procedure TCodec.Decode32(const ABs: TCryptoLibByteArray; ABsOff: Int32;
+  AN: TCryptoLibUInt32Array; ANOff: Int32; ANLen: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < ANLen do
+  begin
+    AN[ANOff + LI] := Decode32(ABs, ABsOff + LI * 4);
+    System.Inc(LI);
+  end;
+end;
+
+class procedure TCodec.Encode24(AN: UInt32; const ABs: TCryptoLibByteArray; AOff: Int32);
+var
+  LOff: Int32;
+begin
+  LOff := AOff;
+  ABs[LOff] := Byte(AN);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 8);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 16);
+end;
+
+class procedure TCodec.Encode32(AN: UInt32; const ABs: TCryptoLibByteArray; AOff: Int32);
+var
+  LOff: Int32;
+begin
+  LOff := AOff;
+  ABs[LOff] := Byte(AN);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 8);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 16);
+  System.Inc(LOff);
+  ABs[LOff] := Byte(AN shr 24);
+end;
+
+class procedure TCodec.Encode32(const AN: TCryptoLibUInt32Array; ANOff: Int32; ANLen: Int32;
+  const ABs: TCryptoLibByteArray; ABsOff: Int32);
+var
+  LI: Int32;
+begin
+  LI := 0;
+  while LI < ANLen do
+  begin
+    TCodec.Encode32(AN[ANOff + LI], ABs, ABsOff + LI * 4);
+    System.Inc(LI);
+  end;
+end;
+
+class procedure TCodec.Encode56(AN: UInt64; ABs: TCryptoLibByteArray; AOff: Int32);
+begin
+  Encode32(UInt32(AN), ABs, AOff);
+  Encode24(UInt32(AN shr 32), ABs, AOff + 4);
+end;
+
+end.

+ 1473 - 1960
CryptoLib/src/Math/EC/Rfc8032/ClpEd25519.pas

@@ -23,2253 +23,1766 @@ interface
 
 uses
   SyncObjs,
-  ClpNat,
-  ClpBitUtilities,
-  ClpNat256,
-  ClpInterleave,
+  ClpCodec,
   ClpDigestUtilities,
-  ClpISecureRandom,
+  ClpBitUtilities,
   ClpIDigest,
-  ClpIEd25519,
+  ClpISecureRandom,
+  ClpNat256,
+  ClpScalar25519,
+  ClpWnaf,
   ClpX25519Field,
-  ClpConverters,
-  ClpArrayUtilities,
+  ClpInterleave,
   ClpCryptoLibTypes;
 
 resourcestring
+  SDigestSize = 'Digest must produce 64 bytes';
+  SInvalidOp = 'Invalid point';
   SInvalidCtx = 'ctx';
-  SDigestError = 'Digest Produced Insufficient Data';
 
 type
-  // -x^2 + y^2 == 1 + 0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3 * x^2 * y^2
-  TEd25519 = class(TInterfacedObject, IEd25519)
-
+  /// <summary>
+  /// A low-level implementation of the Ed25519, Ed25519ctx, and Ed25519ph instantiations of the Edwards-Curve Digital
+  /// Signature Algorithm specified in <a href="https://www.rfc-editor.org/rfc/rfc8032">RFC 8032</a>.
+  /// </summary>
+  /// <remarks>
+  /// The implementation strategy is mostly drawn from <a href="https://ia.cr/2012/309">
+  /// Mike Hamburg, "Fast and compact elliptic-curve cryptography"</a>, notably the "signed multi-comb" algorithm (for
+  /// scalar multiplication by a fixed point), the "half Niels coordinates" (for precomputed points), and the
+  /// "extensible coordinates" (for accumulators). Standard
+  /// <a href="https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html">extended coordinates</a> are used during
+  /// precomputations, needing only a single extra point addition formula.
+  /// </remarks>
+  TEd25519 = class(TObject)
   strict private
-
   type
     TPointAccum = record
     private
       Fx, Fy, Fz, Fu, Fv: TCryptoLibInt32Array;
-
-      function GetX: TCryptoLibInt32Array; inline;
-      procedure SetX(const value: TCryptoLibInt32Array); inline;
-      function GetY: TCryptoLibInt32Array; inline;
-      procedure SetY(const value: TCryptoLibInt32Array); inline;
-      function GetZ: TCryptoLibInt32Array; inline;
-      procedure SetZ(const value: TCryptoLibInt32Array); inline;
-      function GetU: TCryptoLibInt32Array; inline;
-      procedure SetU(const value: TCryptoLibInt32Array); inline;
-      function GetV: TCryptoLibInt32Array; inline;
-      procedure SetV(const value: TCryptoLibInt32Array); inline;
-
     public
-      property X: TCryptoLibInt32Array read GetX write SetX;
-      property Y: TCryptoLibInt32Array read GetY write SetY;
-      property Z: TCryptoLibInt32Array read GetZ write SetZ;
-      property U: TCryptoLibInt32Array read GetU write SetU;
-      property V: TCryptoLibInt32Array read GetV write SetV;
-
-      class function CreatePointAccum(): TPointAccum; static;
+      property X: TCryptoLibInt32Array read Fx write Fx;
+      property Y: TCryptoLibInt32Array read Fy write Fy;
+      property Z: TCryptoLibInt32Array read Fz write Fz;
+      property U: TCryptoLibInt32Array read Fu write Fu;
+      property V: TCryptoLibInt32Array read Fv write Fv;
     end;
 
-  type
     TPointAffine = record
     private
       Fx, Fy: TCryptoLibInt32Array;
-
-      function GetX: TCryptoLibInt32Array; inline;
-      procedure SetX(const value: TCryptoLibInt32Array); inline;
-      function GetY: TCryptoLibInt32Array; inline;
-      procedure SetY(const value: TCryptoLibInt32Array); inline;
-
     public
-      property X: TCryptoLibInt32Array read GetX write SetX;
-      property Y: TCryptoLibInt32Array read GetY write SetY;
-
-      class function CreatePointAffine(): TPointAffine; static;
+      property X: TCryptoLibInt32Array read Fx write Fx;
+      property Y: TCryptoLibInt32Array read Fy write Fy;
     end;
 
-  type
-    TPointExt = record
+    TPointExtended = record
     private
       Fx, Fy, Fz, Ft: TCryptoLibInt32Array;
-
-      function GetX: TCryptoLibInt32Array; inline;
-      procedure SetX(const value: TCryptoLibInt32Array); inline;
-      function GetY: TCryptoLibInt32Array; inline;
-      procedure SetY(const value: TCryptoLibInt32Array); inline;
-      function GetZ: TCryptoLibInt32Array; inline;
-      procedure SetZ(const value: TCryptoLibInt32Array); inline;
-      function GetT: TCryptoLibInt32Array; inline;
-      procedure SetT(const value: TCryptoLibInt32Array); inline;
-
     public
-      property X: TCryptoLibInt32Array read GetX write SetX;
-      property Y: TCryptoLibInt32Array read GetY write SetY;
-      property Z: TCryptoLibInt32Array read GetZ write SetZ;
-      property T: TCryptoLibInt32Array read GetT write SetT;
-
-      class function CreatePointExt(): TPointExt; static;
+      property X: TCryptoLibInt32Array read Fx write Fx;
+      property Y: TCryptoLibInt32Array read Fy write Fy;
+      property Z: TCryptoLibInt32Array read Fz write Fz;
+      property T: TCryptoLibInt32Array read Ft write Ft;
     end;
 
-  type
     TPointPrecomp = record
     private
-      Fypx_h, Fymx_h, Fxyd: TCryptoLibInt32Array;
-
-      function GetYpx_h: TCryptoLibInt32Array; inline;
-      procedure SetYpx_h(const value: TCryptoLibInt32Array); inline;
-      function GetYmx_h: TCryptoLibInt32Array; inline;
-      procedure SetYmx_h(const value: TCryptoLibInt32Array); inline;
-      function GetXyd: TCryptoLibInt32Array; inline;
-      procedure SetXyd(const value: TCryptoLibInt32Array); inline;
-
+      Fymx_h, Fypx_h, Fxyd: TCryptoLibInt32Array;
     public
-      property Ypx_h: TCryptoLibInt32Array read GetYpx_h write SetYpx_h;
-      property Ymx_h: TCryptoLibInt32Array read GetYmx_h write SetYmx_h;
-      property Xyd: TCryptoLibInt32Array read GetXyd write SetXyd;
+      property YmxH: TCryptoLibInt32Array read Fymx_h write Fymx_h;
+      property YpxH: TCryptoLibInt32Array read Fypx_h write Fypx_h;
+      property Xyd: TCryptoLibInt32Array read Fxyd write Fxyd;
+    end;
 
-      class function CreatePointPrecomp(): TPointPrecomp; static;
+    TPointPrecompZ = record
+    private
+      Fymx_h, Fypx_h, Fxyd, Fz: TCryptoLibInt32Array;
+    public
+      property YmxH: TCryptoLibInt32Array read Fymx_h write Fymx_h;
+      property YpxH: TCryptoLibInt32Array read Fypx_h write Fypx_h;
+      property Xyd: TCryptoLibInt32Array read Fxyd write Fxyd;
+      property Z: TCryptoLibInt32Array read Fz write Fz;
     end;
 
-  const
-    M28L = Int64($0FFFFFFF);
-    M32L = Int64($FFFFFFFF);
+    TPointTemp = record
+    private
+      Fr0, Fr1: TCryptoLibInt32Array;
+    public
+      property R0: TCryptoLibInt32Array read Fr0 write Fr0;
+      property R1: TCryptoLibInt32Array read Fr1 write Fr1;
+    end;
 
-    PointBytes = Int32(32);
-    ScalarUints = Int32(8);
-    ScalarBytes = Int32(ScalarUints * 4);
+  public
+   type
+    TAlgorithm = (Ed25519, Ed25519ctx, Ed25519ph);
 
-    L0 = Int32($FCF5D3ED); // L0:26/--
-    L1 = Int32($012631A6); // L1:24/22
-    L2 = Int32($079CD658); // L2:27/--
-    L3 = Int32($FF9DEA2F); // L3:23/--
-    L4 = Int32($000014DF); // L4:12/11
+    IPublicPoint = interface
+      ['{8B8C3F2A-1D4E-4A5B-9C6D-7E8F0A1B2C3D}']
+      function GetData: TCryptoLibInt32Array;
 
-    WnafWidthBase = Int32(7);
+      property Data: TCryptoLibInt32Array read GetData;
+    end;
 
-    PrecompBlocks = Int32(8);
-    PrecompTeeth = Int32(4);
-    PrecompSpacing = Int32(8);
-    PrecompPoints = Int32(1 shl (PrecompTeeth - 1));
-    PrecompMask = Int32(PrecompPoints - 1);
+    TPublicPoint = class sealed(TInterfacedObject, IPublicPoint)
+    strict private
+      FData: TCryptoLibInt32Array;
+      function GetData: TCryptoLibInt32Array;
+    public
+      constructor Create(const AData: TCryptoLibInt32Array);
+      property Data: TCryptoLibInt32Array read GetData;
+    end;
 
+  strict private
+  const
+    CoordUints = 8;
+    PointBytes = CoordUints * 4;
+    ScalarUints = 8;
+    ScalarBytes = ScalarUints * 4;
+    WnafWidth128 = 4;
+    WnafWidthBase = 6;
+    PrecompBlocks = 8;
+    PrecompTeeth = 4;
+    PrecompSpacing = 8;
+    PrecompRange = PrecompBlocks * PrecompTeeth * PrecompSpacing;
+    PrecompPoints = 1 shl (PrecompTeeth - 1);
+    PrecompMask = PrecompPoints - 1;
   class var
-
     FDom2Prefix: TCryptoLibByteArray;
-    FP, FL: TCryptoLibUInt32Array;
-    FB_x, FB_y, FC_d, FC_d2, FC_d4: TCryptoLibInt32Array;
+    FP: TCryptoLibUInt32Array;
+    FOrder8_y1, FOrder8_y2: TCryptoLibUInt32Array;
+    FB_x, FB_y, FB128_x, FB128_y: TCryptoLibInt32Array;
+    FC_d, FC_d2, FC_d4: TCryptoLibInt32Array;
     FPrecompLock: TCriticalSection;
-    // TODO[ed25519] Convert to PointPrecomp
-    FPrecompBaseTable: TCryptoLibGenericArray<TPointExt>;
-    FPrecompBase: TCryptoLibInt32Array;
-
-    class function CalculateS(const r, k, s: TCryptoLibByteArray)
-      : TCryptoLibByteArray; static;
-
-    class function CheckContextVar(const ctx: TCryptoLibCustomByteArrayBuffer;
-      phflag: Byte): Boolean; static; inline;
-
-    class function CheckPointVar(const p: TCryptoLibByteArray): Boolean;
-      static; inline;
-
-    class function CheckScalarVar(const s: TCryptoLibByteArray): Boolean;
-      static; inline;
-
-    class function Decode24(const bs: TCryptoLibByteArray; off: Int32): UInt32;
-      static; inline;
-
-    class function Decode32(const bs: TCryptoLibByteArray; off: Int32): UInt32;
-      overload; static; inline;
-
-    class procedure Decode32(const bs: TCryptoLibByteArray; bsOff: Int32;
-      const n: TCryptoLibUInt32Array; nOff, nLen: Int32); overload;
-      static; inline;
-
-    class function DecodePointVar(const p: TCryptoLibByteArray; pOff: Int32;
-      ANegate: Boolean; var r: TPointAffine): Boolean; static;
-
-    class procedure DecodeScalar(const k: TCryptoLibByteArray; kOff: Int32;
-      const n: TCryptoLibUInt32Array); static; inline;
-
-    class procedure Dom2(const d: IDigest; phflag: Byte;
-      const ctx: TCryptoLibCustomByteArrayBuffer); static; inline;
-
-    class procedure Encode24(n: UInt32; const bs: TCryptoLibByteArray;
-      off: Int32); static; inline;
-
-    class procedure Encode32(n: UInt32; const bs: TCryptoLibByteArray;
-      off: Int32); static; inline;
-
-    class procedure Encode56(n: UInt64; const bs: TCryptoLibByteArray;
-      off: Int32); static; inline;
-
-    class function EncodePoint(var p: TPointAccum; const r: TCryptoLibByteArray;
-      rOff: Int32): Int32; static;
-
-    class function GetWindow4(const X: TCryptoLibUInt32Array; n: Int32): Int32;
-      static; inline;
-
-    class function GetWnaf(const n: TCryptoLibUInt32Array; width: Int32)
-      : TCryptoLibShortIntArray; static;
-
-    class procedure ImplSign(const d: IDigest;
-      const h, s, pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-      const m: TCryptoLibByteArray; mOff, mLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload; static;
-
-    procedure ImplSign(const sk: TCryptoLibByteArray; skOff: Int32;
-      const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-      const m: TCryptoLibByteArray; mOff: Int32; mLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    procedure ImplSign(const sk: TCryptoLibByteArray; skOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-      const m: TCryptoLibByteArray; mOff: Int32; mLen: Int32;
-      const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-    function ImplVerify(const sig: TCryptoLibByteArray; sigOff: Int32;
-      const pk: TCryptoLibByteArray; pkOff: Int32;
-      const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-      const m: TCryptoLibByteArray; mOff, mLen: Int32): Boolean;
-
-    class procedure PointAdd(var p: TPointExt; var r: TPointAccum);
-      overload; static;
-
-    class procedure PointAdd(var p, r: TPointExt); overload; static;
-
-    class procedure PointAddVar(negate: Boolean; var p: TPointExt;
-      var r: TPointAccum); overload; static;
-
-    class procedure PointAddVar(negate: Boolean; var p, q, r: TPointExt);
-      overload; static;
-
-    class procedure PointAddPrecomp(var p: TPointPrecomp; var r: TPointAccum);
-      overload; static;
-
-    class function PointCopy(var p: TPointAffine): TPointExt; overload;
-      static; inline;
-
-    class function PointCopy(var p: TPointAccum): TPointExt; overload;
-      static; inline;
-
-    class function PointCopy(var p: TPointExt): TPointExt; overload;
-      static; inline;
-
-    class procedure PointCopy(var p: TPointAffine; var r: TPointAccum);
-      overload; static; inline;
-
-    class procedure PointCopy(var p, r: TPointExt); overload; static; inline;
-
-    class procedure PointDouble(var r: TPointAccum); static;
-
-    class procedure PointExtendXY(var p: TPointAccum); overload; static; inline;
-
-    class procedure PointExtendXY(var p: TPointExt); overload; static; inline;
-
-    class procedure PointLookup(block, index: Int32; var p: TPointPrecomp);
-      overload; static;
-
-    class procedure PointLookup(const X: TCryptoLibUInt32Array; n: Int32;
-      const table: TCryptoLibInt32Array; var r: TPointExt); overload; static;
-
-    class procedure PointLookup(const table: TCryptoLibInt32Array; index: Int32;
-      var r: TPointExt); overload; static;
-
-    class function PointPrecomp(var p: TPointAffine; count: Int32)
-      : TCryptoLibInt32Array; static;
-
-    class function PointPrecompVar(var p: TPointExt; count: Int32)
-      : TCryptoLibGenericArray<TPointExt>; static;
-
-    class procedure PointSetNeutral(var p: TPointAccum); overload;
-      static; inline;
-
-    class procedure PointSetNeutral(var p: TPointExt); overload; static; inline;
-
-    class procedure PruneScalar(const n: TCryptoLibByteArray; nOff: Int32;
-      const r: TCryptoLibByteArray); static; inline;
-
-    class function ReduceScalar(const n: TCryptoLibByteArray)
-      : TCryptoLibByteArray; static;
-
-    class procedure ScalarMultBase(const k: TCryptoLibByteArray;
-      var r: TPointAccum); static;
-
-    class procedure ScalarMultBaseEncoded(const k, r: TCryptoLibByteArray;
-      rOff: Int32); static; inline;
-
-    class procedure ScalarMultStrausVar(const nb, np: TCryptoLibUInt32Array;
-      var p: TPointAffine; var r: TPointAccum); static;
-
-    class function ValidateDigestOutputSize(const ADigest: IDigest)
-      : TCryptoLibByteArray; static; inline;
-
-    class function ConstructCustomByteArrayBufferContext
-      (const AData: TCryptoLibByteArray; AIsNil: Boolean; ALength: Int32)
-      : TCryptoLibCustomByteArrayBuffer; static; inline;
-
-    class function CheckPoint(const X, Y: TCryptoLibInt32Array): Int32;
-      overload; static;
-    class function CheckPoint(const X, Y, Z: TCryptoLibInt32Array): Int32;
-      overload; static;
-
-    class procedure Boot(); static;
-    class constructor CreateEd25519();
-    class destructor DestroyEd25519();
-
-  strict protected
-
-    function GetAlgorithmName: String; virtual;
-    function CreateDigest(): IDigest; virtual;
-
+    FPrecompBaseWnaf: TCryptoLibGenericArray<TPointPrecomp>;
+    FPrecompBase128Wnaf: TCryptoLibGenericArray<TPointPrecomp>;
+    FPrecompBaseComb: TCryptoLibInt32Array;
+  class procedure Boot; static;
+  class constructor Create;
+  class destructor Destroy;
+  class function CalculateS(const AR, AK, &AS: TCryptoLibByteArray): TCryptoLibByteArray; static;
+  class function CheckContextVar(ACtx: TCryptoLibByteArray; APhflag: Byte): Boolean; static;
+  class function CheckPoint(const AP: TPointAccum): Int32; overload; static;
+  class function CheckPoint(const AP: TPointAffine): Int32; overload; static;
+  class function CheckPointOrderVar(var AP: TPointAffine): Boolean; static;
+  class function CheckPointFullVar(const AP: TCryptoLibByteArray): Boolean; static;
+  class function CheckPointVar(const AP: TCryptoLibByteArray): Boolean; static;
+  class procedure CopyBytes(const ABuf: TCryptoLibByteArray; AOff: Int32; ALen: Int32; var AOut: TCryptoLibByteArray); static;
+  class function CreateDigest(): IDigest; static;
+  class function DecodePointVar(const AP: TCryptoLibByteArray; ANegate: Boolean; var AR: TPointAffine): Boolean; static;
+  class procedure Dom2(const AD: IDigest; APhflag: Byte; const ACtx: TCryptoLibByteArray); static;
+  class procedure EncodePoint(const AP: TPointAffine; AR: TCryptoLibByteArray; AROff: Int32); static;
+  class function EncodeResult(var AP: TPointAccum; AR: TCryptoLibByteArray; AROff: Int32): Int32; static;
+  class function GetWindow4(const AX: TCryptoLibUInt32Array; AN: Int32): UInt32; static;
+  class procedure GroupCombBits(AN: TCryptoLibUInt32Array); static;
+  class procedure ImplSign(const AD: IDigest; AH, &AS, APk: TCryptoLibByteArray; APkOff: Int32;
+    const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32;
+    ASig: TCryptoLibByteArray; ASigOff: Int32); overload; static;
+  class function ImplVerify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+    const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean; overload; static;
+  class procedure InitPointAccum(var AR: TPointAccum); static;
+  class procedure InitPointAffine(var AR: TPointAffine); static;
+  class procedure InitPointExtended(var AR: TPointExtended); static;
+  class procedure InitPointPrecomp(var AR: TPointPrecomp); static;
+  class procedure InitPointPrecompZ(var AR: TPointPrecompZ); static;
+  class procedure InitPointTemp(var AR: TPointTemp); static;
+  class procedure InvertDoubleZs(APoints: TCryptoLibGenericArray<TPointExtended>); static;
+  class function NormalizeToNeutralElementVar(var AP: TPointAccum): Boolean; static;
+  class procedure NormalizeToAffine(var AP: TPointAccum; var AR: TPointAffine); static;
+  class procedure PointAdd(const AP, AQ: TPointExtended; var AR: TPointExtended; var AT: TPointTemp); overload; static;
+  class procedure PointAdd(const AP: TPointPrecomp; var AR: TPointAccum; var AT: TPointTemp); overload; static;
+  class procedure PointAdd(const AP: TPointPrecompZ; var AR: TPointAccum; var AT: TPointTemp); overload; static;
+  class procedure PointAddVar(ANegate: Boolean; const AP: TPointPrecomp; var AR: TPointAccum; var AT: TPointTemp); overload; static;
+  class procedure PointAddVar(ANegate: Boolean; const AP: TPointPrecompZ; var AR: TPointAccum; var AT: TPointTemp); overload; static;
+  class procedure PointCopy(const AP: TPointAccum; var AR: TPointExtended); overload; static;
+  class procedure PointCopy(const AP: TPointAffine; var AR: TPointExtended); overload; static;
+  class procedure PointCopy(const AP: TPointExtended; var AR: TPointPrecompZ); overload; static;
+  class procedure PointDouble(var AR: TPointAccum); static;
+  class procedure PointLookup(ABlock, AIndex: Int32; var AP: TPointPrecomp); static;
+  class procedure PointLookupZ(const AX: TCryptoLibUInt32Array; AN: Int32; const ATable: TCryptoLibInt32Array; var AR: TPointPrecompZ); static;
+  class procedure PointPrecompute(const AP: TPointAffine; var APoints: TCryptoLibGenericArray<TPointExtended>; APointsOff, APointsLen: Int32; var AT: TPointTemp); static;
+  class function PointPrecomputeZ(const AP: TPointAffine; ACount: Int32; var AT: TPointTemp): TCryptoLibInt32Array; overload; static;
+  class procedure PointPrecomputeZ(const AP: TPointAffine; var APoints: TCryptoLibGenericArray<TPointPrecompZ>; ACount: Int32; var AT: TPointTemp); overload; static;
+  class procedure PointSetNeutral(var AP: TPointAccum); static;
+  class procedure PruneScalar(const AN: TCryptoLibByteArray; ANOff: Int32; AR: TCryptoLibByteArray); static;
+  class procedure ScalarMult(const AK: TCryptoLibByteArray; const AP: TPointAffine; var AR: TPointAccum); static;
+  class procedure ScalarMultBase(const AK: TCryptoLibByteArray; var AR: TPointAccum); static;
+  class procedure ScalarMultBaseEncoded(const AK: TCryptoLibByteArray; AR: TCryptoLibByteArray; AROff: Int32); static;
+  class procedure ScalarMultOrderVar(const AP: TPointAffine; var AR: TPointAccum); static;
+  class procedure ScalarMultStraus128Var(const ANb: TCryptoLibUInt32Array; const ANp: TCryptoLibUInt32Array; const AP: TPointAffine;
+    const ANq: TCryptoLibUInt32Array; const AQ: TPointAffine; var AR: TPointAccum); static;
+  class function ExportPoint(var AP: TPointAffine): IPublicPoint; static;
+  class function ImplVerify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+    const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean; overload; static;
+  class procedure ImplSign(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx: TCryptoLibByteArray; APhflag: Byte;
+    const AM: TCryptoLibByteArray; AMOff: Int32; AMLen: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32); overload; static;
+  class procedure ImplSign(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+    const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff: Int32; AMLen: Int32;
+    const ASig: TCryptoLibByteArray; ASigOff: Int32); overload; static;
   public
-
     const
-    PreHashSize = Int32(64);
-    PublicKeySize = Int32(PointBytes);
-    SecretKeySize = Int32(32);
-    SignatureSize = Int32(PointBytes + ScalarBytes);
-
-  type
-{$SCOPEDENUMS ON}
-    TEd25519Algorithm = (Ed25519 = 0, Ed25519ctx = 1, Ed25519ph = 2);
-{$SCOPEDENUMS OFF}
-  constructor Create();
-
-  function CreatePreHash(): IDigest; inline;
-
-  procedure GeneratePrivateKey(const random: ISecureRandom;
-    const k: TCryptoLibByteArray); inline;
-
-  procedure GeneratePublicKey(const sk: TCryptoLibByteArray; skOff: Int32;
-    pk: TCryptoLibByteArray; pkOff: Int32); virtual;
-
-  class procedure Precompute(); static;
-
-  // NOTE: Only for use by X25519
-  class procedure ScalarMultBaseYZ(const k: TCryptoLibByteArray; kOff: Int32;
-    const Y, Z: TCryptoLibInt32Array); static; inline;
-
-  procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-    const m: TCryptoLibByteArray; mOff, mLen: Int32;
-    const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32; const m: TCryptoLibByteArray;
-    mOff, mLen: Int32; const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-    const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32;
-    const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32;
-    const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32;
-    const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-    const ctx, ph: TCryptoLibByteArray; phOff: Int32;
-    const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32;
-    const ctx, ph: TCryptoLibByteArray; phOff: Int32;
-    const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-    const ctx: TCryptoLibByteArray; const ph: IDigest;
-    const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  procedure SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32; const ctx: TCryptoLibByteArray;
-    const ph: IDigest; const sig: TCryptoLibByteArray; sigOff: Int32); overload;
-
-  function Verify(const sig: TCryptoLibByteArray; sigOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32; const m: TCryptoLibByteArray;
-    mOff, mLen: Int32): Boolean; overload;
-
-  function Verify(const sig: TCryptoLibByteArray; sigOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32;
-    const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32): Boolean; overload;
-
-  function VerifyPreHash(const sig: TCryptoLibByteArray; sigOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32;
-    const ctx, ph: TCryptoLibByteArray; phOff: Int32): Boolean; overload;
-
-  function VerifyPreHash(const sig: TCryptoLibByteArray; sigOff: Int32;
-    const pk: TCryptoLibByteArray; pkOff: Int32; const ctx: TCryptoLibByteArray;
-    const ph: IDigest): Boolean; overload;
-
-  class procedure ScalarMult(const k: TCryptoLibByteArray; var p: TPointAffine;
-    var r: TPointAccum); static;
-
-  property AlgorithmName: String read GetAlgorithmName;
-
+    PrehashSize = 64;
+    PublicKeySize = PointBytes;
+    SecretKeySize = 32;
+    SignatureSize = PointBytes + ScalarBytes;
+
+    class procedure Precompute; static;
+    class procedure ScalarMultBaseYZ(const AK: TCryptoLibByteArray; AKOff: Int32; AY, AZ: TCryptoLibInt32Array); static;
+
+    class procedure EncodePublicPoint(const APublicPoint: IPublicPoint; APk: TCryptoLibByteArray; APkOff: Int32); static;
+    class function GeneratePublicKey(const &AS: TCryptoLibByteArray; ASOff: Int32): IPublicPoint; overload; static;
+    class function ValidatePublicKeyFull(const APk: TCryptoLibByteArray; APkOff: Int32): Boolean; static;
+    class function ValidatePublicKeyFullExport(const APk: TCryptoLibByteArray; APkOff: Int32): IPublicPoint; static;
+    class function ValidatePublicKeyPartial(const APk: TCryptoLibByteArray; APkOff: Int32): Boolean; static;
+    class function ValidatePublicKeyPartialExport(const APk: TCryptoLibByteArray; APkOff: Int32): IPublicPoint; static;
+    class function CreatePreHash(): IDigest; static;
+
+    function GetAlgorithmName: String;
+    procedure GeneratePrivateKey(const ARandom: ISecureRandom; const AK: TCryptoLibByteArray);
+    procedure GeneratePublicKey(const &AS: TCryptoLibByteArray; ASOff: Int32; APk: TCryptoLibByteArray; APkOff: Int32); overload;
+    procedure Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const AM: TCryptoLibByteArray; AMOff, AMLen: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx, APh: TCryptoLibByteArray; APhOff: Int32;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const ACtx, APh: TCryptoLibByteArray; APhOff: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx: TCryptoLibByteArray; const APh: IDigest;
+      const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    procedure SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const ACtx: TCryptoLibByteArray; const APh: IDigest; const ASig: TCryptoLibByteArray; ASigOff: Int32); overload;
+    function Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean; overload;
+    function Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean; overload;
+    function Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+      const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean; overload;
+    function Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+      const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean; overload;
+    function VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const ACtx, APh: TCryptoLibByteArray; APhOff: Int32): Boolean; overload;
+    function VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+      const ACtx: TCryptoLibByteArray; const APh: IDigest): Boolean; overload;
+    function VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+      const ACtx, APh: TCryptoLibByteArray; APhOff: Int32): Boolean; overload;
+    function VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+      const ACtx: TCryptoLibByteArray; const APh: IDigest): Boolean; overload;
   end;
 
 implementation
 
-{ TEd25519.TPointExt }
+{ TEd25519.TPublicPoint }
 
-class function TEd25519.TPointExt.CreatePointExt(): TPointExt;
+constructor TEd25519.TPublicPoint.Create(const AData: TCryptoLibInt32Array);
 begin
-  result := Default (TPointExt);
-  result.Fx := TX25519Field.Create();
-  result.Fy := TX25519Field.Create();
-  result.Fz := TX25519Field.Create();
-  result.Ft := TX25519Field.Create();
+  Inherited Create;
+  FData := AData;
 end;
 
-function TEd25519.TPointExt.GetT: TCryptoLibInt32Array;
+function TEd25519.TPublicPoint.GetData: TCryptoLibInt32Array;
 begin
-  result := Ft;
+  Result := FData;
 end;
 
-function TEd25519.TPointExt.GetX: TCryptoLibInt32Array;
-begin
-  result := Fx;
-end;
+{ TEd25519 }
 
-function TEd25519.TPointExt.GetY: TCryptoLibInt32Array;
+class constructor TEd25519.Create;
 begin
-  result := Fy;
+  Boot;
 end;
 
-function TEd25519.TPointExt.GetZ: TCryptoLibInt32Array;
+class procedure TEd25519.Boot;
 begin
-  result := Fz;
-end;
-
-procedure TEd25519.TPointExt.SetT(const value: TCryptoLibInt32Array);
+  FDom2Prefix := TCryptoLibByteArray.Create($53, $69, $67, $45, $64, $32, $35, $35, $31, $39, $20,
+    $6E, $6F, $20, $45, $64, $32, $35, $35, $31, $39, $20, $63, $6F, $6C, $6C, $69, $73, $69,
+    $6F, $6E, $73);
+  FP := TCryptoLibUInt32Array.Create($FFFFFFED, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
+    $FFFFFFFF, $FFFFFFFF, $7FFFFFFF);
+  FOrder8_y1 := TCryptoLibUInt32Array.Create($706A17C7, $4FD84D3D, $760B3CBA, $0F67100D, $FA53202A,
+    $C6CC392C, $77FDC74E, $7A03AC92);
+  FOrder8_y2 := TCryptoLibUInt32Array.Create($8F95E826, $B027B2C2, $89F4C345, $F098EFF2, $05ACDFD5,
+    $3933C6D3, $880238B1, $05FC536D);
+  FB_x := TCryptoLibInt32Array.Create($0325D51A, $018B5823, $007B2C95, $0304A92D, $00D2598E, $01D6DC5C,
+    $01388C7F, $013FEC0A, $029E6B72, $0042D26D);
+  FB_y := TCryptoLibInt32Array.Create($02666658, $01999999, $00666666, $03333333, $00CCCCCC, $02666666,
+    $01999999, $00666666, $03333333, $00CCCCCC);
+  FB128_x := TCryptoLibInt32Array.Create($00B7E824, $0011EB98, $003E5FC8, $024E1739, $0131CD0B, $014E29A0,
+    $034E6138, $0132C952, $03F9E22F, $00984F5F);
+  FB128_y := TCryptoLibInt32Array.Create($03F5A66B, $02AF4452, $0049E5BB, $00F28D26, $0121A17C, $02C29C3A,
+    $0047AD89, $0087D95F, $0332936E, $00BE5933);
+  FC_d := TCryptoLibInt32Array.Create($035978A3, $02D37284, $018AB75E, $026A0A0E, $0000E014, $0379E898,
+    $01D01E5D, $01E738CC, $03715B7F, $00A406D9);
+  FC_d2 := TCryptoLibInt32Array.Create($02B2F159, $01A6E509, $01156EBD, $00D4141D, $0001C029, $02F3D130,
+    $03A03CBB, $01CE7198, $02E2B6FF, $00480DB3);
+  FC_d4 := TCryptoLibInt32Array.Create($0165E2B2, $034DCA13, $002ADD7A, $01A8283B, $00038052, $01E7A260,
+    $03407977, $019CE331, $01C56DFF, $00901B67);
+  FPrecompLock := TCriticalSection.Create;
+end;
+
+class destructor TEd25519.Destroy;
 begin
-  Ft := value;
+  FPrecompLock.Free;
+  FPrecompLock := nil;
 end;
 
-procedure TEd25519.TPointExt.SetX(const value: TCryptoLibInt32Array);
+class function TEd25519.CalculateS(const AR, AK, &AS: TCryptoLibByteArray): TCryptoLibByteArray;
+var
+  LT: TCryptoLibUInt32Array;
+  LU, LV: TCryptoLibUInt32Array;
+  LResult: TCryptoLibByteArray;
 begin
-  Fx := value;
+  System.SetLength(LT, ScalarUints * 2);
+  System.SetLength(LU, ScalarUints);
+  System.SetLength(LV, ScalarUints);
+  TScalar25519.Decode(AR, LT);
+  TScalar25519.Decode(AK, LU);
+  TScalar25519.Decode(&AS, LV);
+  TNat256.MulAddTo(LU, LV, LT);
+  System.SetLength(LResult, ScalarBytes * 2);
+  TCodec.Encode32(LT, 0, System.Length(LT), LResult, 0);
+  Result := TScalar25519.Reduce512(LResult);
 end;
 
-procedure TEd25519.TPointExt.SetY(const value: TCryptoLibInt32Array);
+class function TEd25519.CheckContextVar(ACtx: TCryptoLibByteArray; APhflag: Byte): Boolean;
 begin
-  Fy := value;
+  Result := ((ACtx = nil) and (APhflag = $00)) or ((ACtx <> nil) and (System.Length(ACtx) < 256))
+    or ((APhflag = $01) and (ACtx = nil));
 end;
 
-procedure TEd25519.TPointExt.SetZ(const value: TCryptoLibInt32Array);
-begin
-  Fz := value;
+class function TEd25519.CheckPoint(const AP: TPointAccum): Int32;
+var
+  LT, LU, LV, LW: TCryptoLibInt32Array;
+begin
+  LT := TX25519Field.Create;
+  LU := TX25519Field.Create;
+  LV := TX25519Field.Create;
+  LW := TX25519Field.Create;
+  TX25519Field.Sqr(AP.X, LU);
+  TX25519Field.Sqr(AP.Y, LV);
+  TX25519Field.Sqr(AP.Z, LW);
+  TX25519Field.Mul(LU, LV, LT);
+  TX25519Field.Sub(LU, LV, LU);
+  TX25519Field.Mul(LU, LW, LU);
+  TX25519Field.Sqr(LW, LW);
+  TX25519Field.Mul(LT, FC_d, LT);
+  TX25519Field.Add(LT, LW, LT);
+  TX25519Field.Add(LT, LU, LT);
+  TX25519Field.Normalize(LT);
+  TX25519Field.Normalize(LV);
+  TX25519Field.Normalize(LW);
+  Result := TX25519Field.IsZero(LT) and (not TX25519Field.IsZero(LV)) and (not TX25519Field.IsZero(LW));
+end;
+
+class function TEd25519.CheckPoint(const AP: TPointAffine): Int32;
+var
+  LT, LU, LV: TCryptoLibInt32Array;
+begin
+  LT := TX25519Field.Create;
+  LU := TX25519Field.Create;
+  LV := TX25519Field.Create;
+  TX25519Field.Sqr(AP.X, LU);
+  TX25519Field.Sqr(AP.Y, LV);
+  TX25519Field.Mul(LU, LV, LT);
+  TX25519Field.Sub(LU, LV, LU);
+  TX25519Field.Mul(LT, FC_d, LT);
+  TX25519Field.AddOne(LT);
+  TX25519Field.Add(LT, LU, LT);
+  TX25519Field.Normalize(LT);
+  TX25519Field.Normalize(LV);
+  Result := TX25519Field.IsZero(LT) and (not TX25519Field.IsZero(LV));
+end;
+
+class function TEd25519.CheckPointFullVar(const AP: TCryptoLibByteArray): Boolean;
+var
+  LY7, LT0, LT1, LT2, LT3, LYI, LY0: UInt32;
+  LI: Int32;
+begin
+  LY7 := TCodec.Decode32(AP, 28) and $7FFFFFFF;
+  LT0 := LY7;
+  LT1 := LY7 xor FP[7];
+  LT2 := LY7 xor FOrder8_y1[7];
+  LT3 := LY7 xor FOrder8_y2[7];
+  LI := CoordUints - 2;
+  while LI > 0 do
+  begin
+    LYI := TCodec.Decode32(AP, LI * 4);
+    LT0 := LT0 or LYI;
+    LT1 := LT1 or (LYI xor FP[LI]);
+    LT2 := LT2 or (LYI xor FOrder8_y1[LI]);
+    LT3 := LT3 or (LYI xor FOrder8_y2[LI]);
+    System.Dec(LI);
+  end;
+  LY0 := TCodec.Decode32(AP, 0);
+  if (LT0 = 0) and (LY0 <= 1) then
+    Exit(False);
+  if (LT1 = 0) and (LY0 >= FP[0] - 1) then
+    Exit(False);
+  LT2 := LT2 or (LY0 xor FOrder8_y1[0]);
+  LT3 := LT3 or (LY0 xor FOrder8_y2[0]);
+  Result := (LT2 <> 0) and (LT3 <> 0);
 end;
 
-{ TEd25519.TPointAccum }
-
-class function TEd25519.TPointAccum.CreatePointAccum(): TPointAccum;
+class function TEd25519.CheckPointVar(const AP: TCryptoLibByteArray): Boolean;
+var
+  LI: Int32;
 begin
-  result := Default (TPointAccum);
-  result.Fx := TX25519Field.Create();
-  result.Fy := TX25519Field.Create();
-  result.Fz := TX25519Field.Create();
-  result.Fu := TX25519Field.Create();
-  result.Fv := TX25519Field.Create();
+  if (TCodec.Decode32(AP, 28) and $7FFFFFFF) < FP[7] then
+    Exit(True);
+  LI := CoordUints - 2;
+  while LI >= 0 do
+  begin
+    if TCodec.Decode32(AP, LI * 4) < FP[LI] then
+      Exit(True);
+    System.Dec(LI);
+  end;
+  Result := False;
 end;
 
-function TEd25519.TPointAccum.GetU: TCryptoLibInt32Array;
+class procedure TEd25519.CopyBytes(const ABuf: TCryptoLibByteArray; AOff: Int32; ALen: Int32; var AOut: TCryptoLibByteArray);
 begin
-  result := Fu;
+  System.SetLength(AOut, ALen);
+  if ALen > 0 then
+    System.Move(ABuf[AOff], AOut[0], ALen);
 end;
 
-function TEd25519.TPointAccum.GetV: TCryptoLibInt32Array;
+class function TEd25519.CreateDigest(): IDigest;
+var
+  LD: IDigest;
 begin
-  result := Fv;
+  LD := TDigestUtilities.GetDigest('SHA-512');
+  if LD.GetDigestSize() <> 64 then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SDigestSize);
+  Result := LD;
 end;
 
-function TEd25519.TPointAccum.GetX: TCryptoLibInt32Array;
-begin
-  result := Fx;
+class function TEd25519.DecodePointVar(const AP: TCryptoLibByteArray; ANegate: Boolean; var AR: TPointAffine): Boolean;
+var
+  LX0: Int32;
+  LU, LV: TCryptoLibInt32Array;
+begin
+  LX0 := TBitUtilities.Asr32(Int32(AP[PointBytes - 1] and $80), 7);
+  TX25519Field.Decode(AP, AR.Y);
+  LU := TX25519Field.Create;
+  LV := TX25519Field.Create;
+  TX25519Field.Sqr(AR.Y, LU);
+  TX25519Field.Mul(FC_d, LU, LV);
+  TX25519Field.SubOne(LU);
+  TX25519Field.AddOne(LV);
+  if not TX25519Field.SqrtRatioVar(LU, LV, AR.X) then
+    Exit(False);
+  TX25519Field.Normalize(AR.X);
+  if (LX0 = 1) and TX25519Field.IsZeroVar(AR.X) then
+    Exit(False);
+  if ANegate xor (LX0 <> (AR.X[0] and 1)) then
+  begin
+    TX25519Field.Negate(AR.X, AR.X);
+    TX25519Field.Normalize(AR.X);
+  end;
+  Result := True;
 end;
 
-function TEd25519.TPointAccum.GetY: TCryptoLibInt32Array;
+class procedure TEd25519.Dom2(const AD: IDigest; APhflag: Byte; const ACtx: TCryptoLibByteArray);
+var
+  LN, LCtxLen: Int32;
+  LT: TCryptoLibByteArray;
 begin
-  result := Fy;
+  LN := System.Length(FDom2Prefix);
+  if ACtx = nil then
+    LCtxLen := 0
+  else
+    LCtxLen := System.Length(ACtx);
+  System.SetLength(LT, LN + 2 + LCtxLen);
+  System.Move(FDom2Prefix[0], LT[0], LN);
+  LT[LN] := APhflag;
+  LT[LN + 1] := Byte(LCtxLen);
+  if LCtxLen > 0 then
+    System.Move(ACtx[0], LT[LN + 2], LCtxLen);
+  AD.BlockUpdate(LT, 0, System.Length(LT));
 end;
 
-function TEd25519.TPointAccum.GetZ: TCryptoLibInt32Array;
+class procedure TEd25519.EncodePoint(const AP: TPointAffine; AR: TCryptoLibByteArray; AROff: Int32);
 begin
-  result := Fz;
+  TX25519Field.Encode(AP.Y, AR, AROff);
+  AR[AROff + PointBytes - 1] := AR[AROff + PointBytes - 1] or Byte((AP.X[0] and 1) shl 7);
 end;
 
-procedure TEd25519.TPointAccum.SetU(const value: TCryptoLibInt32Array);
+class function TEd25519.EncodeResult(var AP: TPointAccum; AR: TCryptoLibByteArray; AROff: Int32): Int32;
+var
+  LQ: TPointAffine;
 begin
-  Fu := value;
+  InitPointAffine(LQ);
+  NormalizeToAffine(AP, LQ);
+  Result := CheckPoint(LQ);
+  EncodePoint(LQ, AR, AROff);
 end;
 
-procedure TEd25519.TPointAccum.SetV(const value: TCryptoLibInt32Array);
+class function TEd25519.GetWindow4(const AX: TCryptoLibUInt32Array; AN: Int32): UInt32;
+var
+  LW: Int32;
+  LB: Int32;
 begin
-  Fv := value;
+  LW := UInt32(AN) shr 3;
+  LB := (AN and 7) shl 2;
+  Result := (AX[LW] shr LB) and 15;
 end;
 
-procedure TEd25519.TPointAccum.SetX(const value: TCryptoLibInt32Array);
+class procedure TEd25519.GroupCombBits(AN: TCryptoLibUInt32Array);
+var
+  LI: Int32;
 begin
-  Fx := value;
+  LI := 0;
+  while LI < System.Length(AN) do
+  begin
+    AN[LI] := TInterleave.Shuffle2(AN[LI]);
+    System.Inc(LI);
+  end;
 end;
 
-procedure TEd25519.TPointAccum.SetY(const value: TCryptoLibInt32Array);
+class procedure TEd25519.InitPointAccum(var AR: TPointAccum);
 begin
-  Fy := value;
+  AR.X := TX25519Field.Create;
+  AR.Y := TX25519Field.Create;
+  AR.Z := TX25519Field.Create;
+  AR.U := TX25519Field.Create;
+  AR.V := TX25519Field.Create;
 end;
 
-procedure TEd25519.TPointAccum.SetZ(const value: TCryptoLibInt32Array);
+class procedure TEd25519.InitPointAffine(var AR: TPointAffine);
 begin
-  Fz := value;
+  AR.X := TX25519Field.Create;
+  AR.Y := TX25519Field.Create;
 end;
 
-{ TEd25519.TPointPrecomp }
-
-class function TEd25519.TPointPrecomp.CreatePointPrecomp(): TPointPrecomp;
+class procedure TEd25519.InitPointExtended(var AR: TPointExtended);
 begin
-  result := Default (TPointPrecomp);
-  result.Fypx_h := TX25519Field.Create();
-  result.Fymx_h := TX25519Field.Create();
-  result.Fxyd := TX25519Field.Create();
+  AR.X := TX25519Field.Create;
+  AR.Y := TX25519Field.Create;
+  AR.Z := TX25519Field.Create;
+  AR.T := TX25519Field.Create;
 end;
 
-function TEd25519.TPointPrecomp.GetXyd: TCryptoLibInt32Array;
+class procedure TEd25519.InitPointPrecomp(var AR: TPointPrecomp);
 begin
-  result := Fxyd;
+  AR.YmxH := TX25519Field.Create;
+  AR.YpxH := TX25519Field.Create;
+  AR.Xyd := TX25519Field.Create;
 end;
 
-function TEd25519.TPointPrecomp.GetYmx_h: TCryptoLibInt32Array;
+class procedure TEd25519.InitPointPrecompZ(var AR: TPointPrecompZ);
 begin
-  result := Fymx_h;
+  AR.YmxH := TX25519Field.Create;
+  AR.YpxH := TX25519Field.Create;
+  AR.Xyd := TX25519Field.Create;
+  AR.Z := TX25519Field.Create;
 end;
 
-function TEd25519.TPointPrecomp.GetYpx_h: TCryptoLibInt32Array;
+class procedure TEd25519.InitPointTemp(var AR: TPointTemp);
 begin
-  result := Fypx_h;
+  AR.R0 := TX25519Field.Create;
+  AR.R1 := TX25519Field.Create;
 end;
 
-procedure TEd25519.TPointPrecomp.SetXyd(const value: TCryptoLibInt32Array);
-begin
-  Fxyd := value;
+class procedure TEd25519.InvertDoubleZs(APoints: TCryptoLibGenericArray<TPointExtended>);
+var
+  LCount, LI, LJ: Int32;
+  LCs: TCryptoLibInt32Array;
+  LU, LT: TCryptoLibInt32Array;
+begin
+  LCount := System.Length(APoints);
+  LCs := TX25519Field.CreateTable(LCount);
+  LU := TX25519Field.Create;
+  TX25519Field.Copy(APoints[0].Z, 0, LU, 0);
+  TX25519Field.Copy(LU, 0, LCs, 0);
+  LI := 0;
+  System.Inc(LI);
+  while LI < LCount do
+  begin
+    TX25519Field.Mul(LU, APoints[LI].Z, LU);
+    TX25519Field.Copy(LU, 0, LCs, LI * TX25519Field.Size);
+    System.Inc(LI);
+  end;
+  TX25519Field.Add(LU, LU, LU);
+  TX25519Field.InvVar(LU, LU);
+  System.Dec(LI);
+  LT := TX25519Field.Create;
+  while LI > 0 do
+  begin
+    LJ := LI;
+    System.Dec(LI);
+    TX25519Field.Copy(LCs, LI * TX25519Field.Size, LT, 0);
+    TX25519Field.Mul(LT, LU, LT);
+    TX25519Field.Mul(LU, APoints[LJ].Z, LU);
+    TX25519Field.Copy(LT, 0, APoints[LJ].Z, 0);
+  end;
+  TX25519Field.Copy(LU, 0, APoints[0].Z, 0);
 end;
 
-procedure TEd25519.TPointPrecomp.SetYmx_h(const value: TCryptoLibInt32Array);
+class function TEd25519.NormalizeToNeutralElementVar(var AP: TPointAccum): Boolean;
 begin
-  Fymx_h := value;
+  TX25519Field.Normalize(AP.X);
+  TX25519Field.Normalize(AP.Y);
+  TX25519Field.Normalize(AP.Z);
+  Result := TX25519Field.IsZeroVar(AP.X) and (not TX25519Field.IsZeroVar(AP.Y)) and TX25519Field.AreEqualVar(AP.Y, AP.Z);
 end;
 
-procedure TEd25519.TPointPrecomp.SetYpx_h(const value: TCryptoLibInt32Array);
+class procedure TEd25519.NormalizeToAffine(var AP: TPointAccum; var AR: TPointAffine);
 begin
-  Fypx_h := value;
+  TX25519Field.Inv(AP.Z, AR.Y);
+  TX25519Field.Mul(AR.Y, AP.X, AR.X);
+  TX25519Field.Mul(AR.Y, AP.Y, AR.Y);
+  TX25519Field.Normalize(AR.X);
+  TX25519Field.Normalize(AR.Y);
 end;
 
-{ TEd25519 }
-
-class procedure TEd25519.Boot;
-begin
-  // 'SigEd25519 no Ed25519 collisions' as ByteArray using ASCII Encoding
-  FDom2Prefix := TCryptoLibByteArray.Create(83, 105, 103, 69, 100, 50, 53, 53,
-    49, 57, 32, 110, 111, 32, 69, 100, 50, 53, 53, 49, 57, 32, 99, 111, 108,
-    108, 105, 115, 105, 111, 110, 115);
-
-  FP := TCryptoLibUInt32Array.Create($FFFFFFED, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
-    $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $7FFFFFFF);
-  FL := TCryptoLibUInt32Array.Create($5CF5D3ED, $5812631A, $A2F79CD6, $14DEF9DE,
-    $00000000, $00000000, $00000000, $10000000);
-
-  FB_x := TCryptoLibInt32Array.Create($0325D51A, $018B5823, $007B2C95,
-    $0304A92D, $00D2598E, $01D6DC5C, $01388C7F, $013FEC0A, $029E6B72,
-    $0042D26D);
-  FB_y := TCryptoLibInt32Array.Create($02666658, $01999999, $00666666,
-    $03333333, $00CCCCCC, $02666666, $01999999, $00666666, $03333333,
-    $00CCCCCC);
-  FC_d := TCryptoLibInt32Array.Create($035978A3, $02D37284, $018AB75E,
-    $026A0A0E, $0000E014, $0379E898, $01D01E5D, $01E738CC, $03715B7F,
-    $00A406D9);
-  FC_d2 := TCryptoLibInt32Array.Create($02B2F159, $01A6E509, $01156EBD,
-    $00D4141D, $0001C029, $02F3D130, $03A03CBB, $01CE7198, $02E2B6FF,
-    $00480DB3);
-  FC_d4 := TCryptoLibInt32Array.Create($0165E2B2, $034DCA13, $002ADD7A,
-    $01A8283B, $00038052, $01E7A260, $03407977, $019CE331, $01C56DFF,
-    $00901B67);
-
-  if FPrecompLock = Nil then
+class procedure TEd25519.PointAdd(const AP, AQ: TPointExtended; var AR: TPointExtended; var AT: TPointTemp);
+var
+  LA, LB, LC, LD, LE, LF, LG, LH: TCryptoLibInt32Array;
+begin
+  LA := AR.X;
+  LB := AR.Y;
+  LC := AT.R0;
+  LD := AT.R1;
+  LE := LA;
+  LF := LC;
+  LG := LD;
+  LH := LB;
+  TX25519Field.Apm(AP.Y, AP.X, LB, LA);
+  TX25519Field.Apm(AQ.Y, AQ.X, LD, LC);
+  TX25519Field.Mul(LA, LC, LA);
+  TX25519Field.Mul(LB, LD, LB);
+  TX25519Field.Mul(AP.T, AQ.T, LC);
+  TX25519Field.Mul(LC, FC_d2, LC);
+  TX25519Field.Add(AP.Z, AP.Z, LD);
+  TX25519Field.Mul(LD, AQ.Z, LD);
+  TX25519Field.Apm(LB, LA, LH, LE);
+  TX25519Field.Apm(LD, LC, LG, LF);
+  TX25519Field.Mul(LE, LH, AR.T);
+  TX25519Field.Mul(LF, LG, AR.Z);
+  TX25519Field.Mul(LE, LF, AR.X);
+  TX25519Field.Mul(LH, LG, AR.Y);
+end;
+
+class procedure TEd25519.PointAdd(const AP: TPointPrecomp; var AR: TPointAccum; var AT: TPointTemp);
+var
+  LA, LB, LC, LE, LF, LG, LH: TCryptoLibInt32Array;
+begin
+  LA := AR.X;
+  LB := AR.Y;
+  LC := AT.R0;
+  LE := AR.U;
+  LF := LA;
+  LG := LB;
+  LH := AR.V;
+  TX25519Field.Apm(AR.Y, AR.X, LB, LA);
+  TX25519Field.Mul(LA, AP.YmxH, LA);
+  TX25519Field.Mul(LB, AP.YpxH, LB);
+  TX25519Field.Mul(AR.U, AR.V, LC);
+  TX25519Field.Mul(LC, AP.Xyd, LC);
+  TX25519Field.Apm(LB, LA, LH, LE);
+  TX25519Field.Apm(AR.Z, LC, LG, LF);
+  TX25519Field.Mul(LF, LG, AR.Z);
+  TX25519Field.Mul(LF, LE, AR.X);
+  TX25519Field.Mul(LG, LH, AR.Y);
+end;
+
+class procedure TEd25519.PointAdd(const AP: TPointPrecompZ; var AR: TPointAccum; var AT: TPointTemp);
+var
+  LA, LB, LC, LD, LE, LF, LG, LH: TCryptoLibInt32Array;
+begin
+  LA := AR.X;
+  LB := AR.Y;
+  LC := AT.R0;
+  LD := AR.Z;
+  LE := AR.U;
+  LF := LA;
+  LG := LB;
+  LH := AR.V;
+  TX25519Field.Apm(AR.Y, AR.X, LB, LA);
+  TX25519Field.Mul(LA, AP.YmxH, LA);
+  TX25519Field.Mul(LB, AP.YpxH, LB);
+  TX25519Field.Mul(AR.U, AR.V, LC);
+  TX25519Field.Mul(LC, AP.Xyd, LC);
+  TX25519Field.Mul(AR.Z, AP.Z, LD);
+  TX25519Field.Apm(LB, LA, LH, LE);
+  TX25519Field.Apm(LD, LC, LG, LF);
+  TX25519Field.Mul(LF, LG, AR.Z);
+  TX25519Field.Mul(LF, LE, AR.X);
+  TX25519Field.Mul(LG, LH, AR.Y);
+end;
+
+class procedure TEd25519.PointAddVar(ANegate: Boolean; const AP: TPointPrecomp; var AR: TPointAccum; var AT: TPointTemp);
+var
+  LNa, LNb, LNf, LNg: TCryptoLibInt32Array;
+  LA, LB, LC, LE, LF, LG, LH: TCryptoLibInt32Array;
+begin
+  LA := AR.X;
+  LB := AR.Y;
+  LC := AT.R0;
+  LE := AR.U;
+  LF := LA;
+  LG := LB;
+  LH := AR.V;
+  if ANegate then
+  begin
+    LNa := LB;
+    LNb := LA;
+  end
+  else
   begin
-    FPrecompLock := TCriticalSection.Create;
+    LNa := LA;
+    LNb := LB;
   end;
+  LNf := LNa;
+  LNg := LNb;
+  TX25519Field.Apm(AR.Y, AR.X, LB, LA);
+  TX25519Field.Mul(LNa, AP.YmxH, LNa);
+  TX25519Field.Mul(LNb, AP.YpxH, LNb);
+  TX25519Field.Mul(AR.U, AR.V, LC);
+  TX25519Field.Mul(LC, AP.Xyd, LC);
+  TX25519Field.Apm(LB, LA, LH, LE);
+  TX25519Field.Apm(AR.Z, LC, LNg, LNf);
+  TX25519Field.Mul(LF, LG, AR.Z);
+  TX25519Field.Mul(LF, LE, AR.X);
+  TX25519Field.Mul(LG, LH, AR.Y);
+end;
+
+class procedure TEd25519.PointAddVar(ANegate: Boolean; const AP: TPointPrecompZ; var AR: TPointAccum; var AT: TPointTemp);
+var
+  LNa, LNb, LNf, LNg: TCryptoLibInt32Array;
+  LA, LB, LC, LD, LE, LF, LG, LH: TCryptoLibInt32Array;
+begin
+  LA := AR.X;
+  LB := AR.Y;
+  LC := AT.R0;
+  LD := AT.R1;
+  LE := AR.U;
+  LF := LA;
+  LG := LB;
+  LH := AR.V;
+  if ANegate then
+  begin
+    LNa := LB;
+    LNb := LA;
+  end
+  else
+  begin
+    LNa := LA;
+    LNb := LB;
+  end;
+  LNf := LNa;
+  LNg := LNb;
+  TX25519Field.Apm(AR.Y, AR.X, LB, LA);
+  TX25519Field.Mul(LNa, AP.YmxH, LNa);
+  TX25519Field.Mul(LNb, AP.YpxH, LNb);
+  TX25519Field.Mul(AR.U, AR.V, LC);
+  TX25519Field.Mul(LC, AP.Xyd, LC);
+  TX25519Field.Mul(AR.Z, AP.Z, LD);
+  TX25519Field.Apm(LB, LA, LH, LE);
+  TX25519Field.Apm(LD, LC, LNg, LNf);
+  TX25519Field.Mul(LF, LG, AR.Z);
+  TX25519Field.Mul(LF, LE, AR.X);
+  TX25519Field.Mul(LG, LH, AR.Y);
 end;
 
-class function TEd25519.Decode32(const bs: TCryptoLibByteArray;
-  off: Int32): UInt32;
-begin
-  // UInt32 n := bs[off];
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 8);
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 16);
-  // System.Inc(off);
-  // n := n or (UInt32(bs[off]) shl 24);
-  // result := n;
-  result := TConverters.ReadBytesAsUInt32LE(PByte(bs), off);
-end;
-
-class procedure TEd25519.Decode32(const bs: TCryptoLibByteArray; bsOff: Int32;
-  const n: TCryptoLibUInt32Array; nOff, nLen: Int32);
-begin
-  // int32 i;
-  // for i := 0 to System.Pred(nLen) do
-  // begin
-  // n[nOff + i] := Decode32(bs, bsOff + (i * 4));
-  // end;
-  TConverters.le32_copy(PByte(bs), bsOff * System.SizeOf(Byte), PCardinal(n),
-    nOff * System.SizeOf(UInt32), nLen * System.SizeOf(UInt32));
-end;
-
-class procedure TEd25519.DecodeScalar(const k: TCryptoLibByteArray; kOff: Int32;
-  const n: TCryptoLibUInt32Array);
+class procedure TEd25519.PointCopy(const AP: TPointAccum; var AR: TPointExtended);
 begin
-  Decode32(k, kOff, n, 0, ScalarUints);
+  TX25519Field.Copy(AP.X, 0, AR.X, 0);
+  TX25519Field.Copy(AP.Y, 0, AR.Y, 0);
+  TX25519Field.Copy(AP.Z, 0, AR.Z, 0);
+  TX25519Field.Mul(AP.U, AP.V, AR.T);
 end;
 
-class procedure TEd25519.Encode24(n: UInt32; const bs: TCryptoLibByteArray;
-  off: Int32);
+class procedure TEd25519.PointCopy(const AP: TPointAffine; var AR: TPointExtended);
 begin
-  bs[off] := Byte(n);
-  System.Inc(off);
-  bs[off] := Byte(n shr 8);
-  System.Inc(off);
-  bs[off] := Byte(n shr 16);
+  TX25519Field.Copy(AP.X, 0, AR.X, 0);
+  TX25519Field.Copy(AP.Y, 0, AR.Y, 0);
+  TX25519Field.One(AR.Z);
+  TX25519Field.Mul(AP.X, AP.Y, AR.T);
 end;
 
-class procedure TEd25519.Encode32(n: UInt32; const bs: TCryptoLibByteArray;
-  off: Int32);
+class procedure TEd25519.PointCopy(const AP: TPointExtended; var AR: TPointPrecompZ);
 begin
-  // bs[  off] := Byte(n      );
-  // System.Inc(off);
-  // bs[off] := Byte(n shr  8);
-  // System.Inc(off);
-  // bs[off] := Byte(n shr  16);
-  // System.Inc(off);
-  // bs[off] := Byte(n shr  24);
-  TConverters.ReadUInt32AsBytesLE(n, bs, off);
+  TX25519Field.Apm(AP.Y, AP.X, AR.YpxH, AR.YmxH);
+  TX25519Field.Mul(AP.T, FC_d2, AR.Xyd);
+  TX25519Field.Add(AP.Z, AP.Z, AR.Z);
 end;
 
-class procedure TEd25519.Encode56(n: UInt64; const bs: TCryptoLibByteArray;
-  off: Int32);
-begin
-  Encode32(UInt32(n), bs, off);
-  Encode24(UInt32(n shr 32), bs, off + 4);
+class procedure TEd25519.PointDouble(var AR: TPointAccum);
+var
+  LA, LB, LC, LE, LF, LG, LH: TCryptoLibInt32Array;
+begin
+  LA := AR.X;
+  LB := AR.Y;
+  LC := AR.Z;
+  LE := AR.U;
+  LF := LA;
+  LG := LB;
+  LH := AR.V;
+  TX25519Field.Add(AR.X, AR.Y, LE);
+  TX25519Field.Sqr(AR.X, LA);
+  TX25519Field.Sqr(AR.Y, LB);
+  TX25519Field.Sqr(AR.Z, LC);
+  TX25519Field.Add(LC, LC, LC);
+  TX25519Field.Apm(LA, LB, LH, LG);
+  TX25519Field.Sqr(LE, LE);
+  TX25519Field.Sub(LH, LE, LE);
+  TX25519Field.Add(LC, LG, LF);
+  TX25519Field.Carry(LF);
+  TX25519Field.Mul(LF, LG, AR.Z);
+  TX25519Field.Mul(LF, LE, AR.X);
+  TX25519Field.Mul(LG, LH, AR.Y);
+end;
+
+class procedure TEd25519.PointLookup(ABlock, AIndex: Int32; var AP: TPointPrecomp);
+var
+  LOff: Int32;
+  LI: Int32;
+  LCond: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((0 <= ABlock) and (ABlock < PrecompBlocks));
+  System.Assert((0 <= AIndex) and (AIndex < PrecompPoints));
+  {$ENDIF}
+  LOff := ABlock * PrecompPoints * 3 * TX25519Field.Size;
+  LI := 0;
+  while LI < PrecompPoints do
+  begin
+    LCond := TBitUtilities.Asr32((LI xor AIndex) - 1, 31);
+    TX25519Field.CMov(LCond, FPrecompBaseComb, LOff, AP.YmxH, 0);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.CMov(LCond, FPrecompBaseComb, LOff, AP.YpxH, 0);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.CMov(LCond, FPrecompBaseComb, LOff, AP.Xyd, 0);
+    LOff := LOff + TX25519Field.Size;
+    System.Inc(LI);
+  end;
 end;
 
-class function TEd25519.CalculateS(const r, k, s: TCryptoLibByteArray)
-  : TCryptoLibByteArray;
+class procedure TEd25519.PointLookupZ(const AX: TCryptoLibUInt32Array; AN: Int32; const ATable: TCryptoLibInt32Array; var AR: TPointPrecompZ);
 var
-  T, U, V: TCryptoLibUInt32Array;
-  i: Int32;
-begin
-  System.SetLength(T, ScalarUints * 2);
-  DecodeScalar(r, 0, T);
-  System.SetLength(U, ScalarUints);
-  DecodeScalar(k, 0, U);
-  System.SetLength(V, ScalarUints);
-  DecodeScalar(s, 0, V);
-
-  TNat256.MulAddTo(U, V, T);
-
-  System.SetLength(result, ScalarBytes * 2);
-
-  for i := 0 to System.Pred(System.Length(T)) do
+  LW: UInt32;
+  LSign, LAbs: Int32;
+  LI: Int32;
+  LOff: Int32;
+  LCond: Int32;
+begin
+  LW := GetWindow4(AX, AN);
+  LSign := Int32(LW shr (4 - 1)) xor 1;
+  LAbs := (Int32(LW) xor -LSign) and 7;
+  {$IFDEF DEBUG}
+  System.Assert((LSign = 0) or (LSign = 1));
+  System.Assert((0 <= LAbs) and (LAbs < 8));
+  {$ENDIF}
+  LOff := 0;
+  LI := 0;
+  while LI < 8 do
   begin
-    Encode32(T[i], result, i * 4);
+    LCond := TBitUtilities.Asr32((LI xor LAbs) - 1, 31);
+    TX25519Field.CMov(LCond, ATable, LOff, AR.YmxH, 0);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.CMov(LCond, ATable, LOff, AR.YpxH, 0);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.CMov(LCond, ATable, LOff, AR.Xyd, 0);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.CMov(LCond, ATable, LOff, AR.Z, 0);
+    LOff := LOff + TX25519Field.Size;
+    System.Inc(LI);
   end;
-  result := ReduceScalar(result);
+  TX25519Field.CSwap(LSign, AR.YmxH, AR.YpxH);
+  TX25519Field.CNegate(LSign, AR.Xyd);
 end;
 
-class function TEd25519.CheckContextVar(const ctx
-  : TCryptoLibCustomByteArrayBuffer; phflag: Byte): Boolean;
-begin
-  result := ((ctx.IsNil) and (phflag = $00)) or
-    ((not ctx.IsNil) and (ctx.Length < 256));
+class procedure TEd25519.PointPrecompute(const AP: TPointAffine; var APoints: TCryptoLibGenericArray<TPointExtended>; APointsOff, APointsLen: Int32; var AT: TPointTemp);
+var
+  LInit: TPointExtended;
+  LD: TPointExtended;
+  LI: Int32;
+begin
+  InitPointExtended(APoints[APointsOff]);
+  PointCopy(AP, APoints[APointsOff]);
+  InitPointExtended(LD);
+  PointAdd(APoints[APointsOff], APoints[APointsOff], LD, AT);
+  LI := 1;
+  while LI < APointsLen do
+  begin
+    InitPointExtended(APoints[APointsOff + LI]);
+    PointAdd(APoints[APointsOff + LI - 1], LD, APoints[APointsOff + LI], AT);
+    System.Inc(LI);
+  end;
 end;
 
-class function TEd25519.CheckPoint(const X, Y: TCryptoLibInt32Array): Int32;
+class function TEd25519.PointPrecomputeZ(const AP: TPointAffine; ACount: Int32; var AT: TPointTemp): TCryptoLibInt32Array;
 var
-  T, U, V: TCryptoLibInt32Array;
-begin
-  T := TX25519Field.Create();
-  U := TX25519Field.Create();
-  V := TX25519Field.Create();
-
-  TX25519Field.Sqr(X, U);
-  TX25519Field.Sqr(Y, V);
-  TX25519Field.Mul(U, V, T);
-  TX25519Field.Sub(V, U, V);
-  TX25519Field.Mul(T, FC_d, T);
-  TX25519Field.AddOne(T);
-  TX25519Field.Sub(T, V, T);
-  TX25519Field.Normalize(T);
-
-  result := TX25519Field.IsZero(T);
+  LQ, LD: TPointExtended;
+  LR: TPointPrecompZ;
+  LOff, LI: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ACount > 0);
+  {$ENDIF}
+  InitPointExtended(LQ);
+  PointCopy(AP, LQ);
+  InitPointExtended(LD);
+  PointAdd(LQ, LQ, LD, AT);
+  InitPointPrecompZ(LR);
+  System.SetLength(Result, ACount * 4 * TX25519Field.Size);
+  LOff := 0;
+  LI := 0;
+  repeat
+    PointCopy(LQ, LR);
+    TX25519Field.Copy(LR.YmxH, 0, Result, LOff);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.Copy(LR.YpxH, 0, Result, LOff);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.Copy(LR.Xyd, 0, Result, LOff);
+    LOff := LOff + TX25519Field.Size;
+    TX25519Field.Copy(LR.Z, 0, Result, LOff);
+    LOff := LOff + TX25519Field.Size;
+    System.Inc(LI);
+    if LI = ACount then
+      break;
+    PointAdd(LQ, LD, LQ, AT);
+  until False;
 end;
 
-class function TEd25519.CheckPoint(const X, Y, Z: TCryptoLibInt32Array): Int32;
+class procedure TEd25519.PointPrecomputeZ(const AP: TPointAffine; var APoints: TCryptoLibGenericArray<TPointPrecompZ>; ACount: Int32; var AT: TPointTemp);
 var
-  T, U, V, W: TCryptoLibInt32Array;
-begin
-  T := TX25519Field.Create();
-  U := TX25519Field.Create();
-  V := TX25519Field.Create();
-  W := TX25519Field.Create();
-
-  TX25519Field.Sqr(X, U);
-  TX25519Field.Sqr(Y, V);
-  TX25519Field.Sqr(Z, W);
-  TX25519Field.Mul(U, V, T);
-  TX25519Field.Sub(V, U, V);
-  TX25519Field.Mul(V, W, V);
-  TX25519Field.Sqr(W, W);
-  TX25519Field.Mul(T, FC_d, T);
-  TX25519Field.Add(T, W, T);
-  TX25519Field.Sub(T, V, T);
-  TX25519Field.Normalize(T);
-
-  result := TX25519Field.IsZero(T);
+  LQ, LD: TPointExtended;
+  LI: Int32;
+begin
+  InitPointExtended(LQ);
+  PointCopy(AP, LQ);
+  InitPointExtended(LD);
+  PointAdd(LQ, LQ, LD, AT);
+  LI := 0;
+  repeat
+    InitPointPrecompZ(APoints[LI]);
+    PointCopy(LQ, APoints[LI]);
+    System.Inc(LI);
+    if LI = ACount then
+      break;
+    PointAdd(LQ, LD, LQ, AT);
+  until False;
 end;
 
-class function TEd25519.CheckPointVar(const p: TCryptoLibByteArray): Boolean;
-var
-  T: TCryptoLibUInt32Array;
+class procedure TEd25519.PointSetNeutral(var AP: TPointAccum);
 begin
-  System.SetLength(T, 8);
-  Decode32(p, 0, T, 0, 8);
-  T[7] := T[7] and $7FFFFFFF;
-  result := not(TNat256.Gte(T, FP));
+  TX25519Field.Zero(AP.X);
+  TX25519Field.One(AP.Y);
+  TX25519Field.One(AP.Z);
+  TX25519Field.Zero(AP.U);
+  TX25519Field.One(AP.V);
 end;
 
-class function TEd25519.CheckScalarVar(const s: TCryptoLibByteArray): Boolean;
-var
-  n: TCryptoLibUInt32Array;
+class procedure TEd25519.PruneScalar(const AN: TCryptoLibByteArray; ANOff: Int32; AR: TCryptoLibByteArray);
 begin
-  System.SetLength(n, ScalarUints);
-  DecodeScalar(s, 0, n);
-  result := not(TNat256.Gte(n, FL));
+  System.Move(AN[ANOff], AR[0], ScalarBytes);
+  AR[0] := AR[0] and $F8;
+  AR[ScalarBytes - 1] := AR[ScalarBytes - 1] and $7F;
+  AR[ScalarBytes - 1] := AR[ScalarBytes - 1] or $40;
 end;
 
-constructor TEd25519.Create;
-begin
-  Inherited Create();
+class procedure TEd25519.ScalarMult(const AK: TCryptoLibByteArray; const AP: TPointAffine; var AR: TPointAccum);
+var
+  LN: TCryptoLibUInt32Array;
+  LQ: TPointPrecompZ;
+  LT: TPointTemp;
+  LTable: TCryptoLibInt32Array;
+  LW, LJ: Int32;
+begin
+  System.SetLength(LN, ScalarUints);
+  TScalar25519.Decode(AK, LN);
+  TScalar25519.ToSignedDigits(256, LN);
+  InitPointPrecompZ(LQ);
+  InitPointTemp(LT);
+  LTable := PointPrecomputeZ(AP, 8, LT);
+  PointSetNeutral(AR);
+  LW := 63;
+  repeat
+    PointLookupZ(LN, LW, LTable, LQ);
+    PointAdd(LQ, AR, LT);
+    System.Dec(LW);
+    if LW < 0 then
+      break;
+    LJ := 0;
+    while LJ < 4 do
+    begin
+      PointDouble(AR);
+      System.Inc(LJ);
+    end;
+  until False;
 end;
 
-function TEd25519.CreateDigest: IDigest;
-begin
-  result := TDigestUtilities.GetDigest('SHA-512');
+class procedure TEd25519.ScalarMultBase(const AK: TCryptoLibByteArray; var AR: TPointAccum);
+var
+  LN: TCryptoLibUInt32Array;
+  LP: TPointPrecomp;
+  LT: TPointTemp;
+  LCOff: Int32;
+  LBlock: Int32;
+  LW: UInt32;
+  LSign, LAbs, LResultSign: Int32;
+begin
+  Precompute;
+  System.SetLength(LN, ScalarUints);
+  TScalar25519.Decode(AK, LN);
+  TScalar25519.ToSignedDigits(PrecompRange, LN);
+  GroupCombBits(LN);
+  InitPointPrecomp(LP);
+  InitPointTemp(LT);
+  PointSetNeutral(AR);
+  LResultSign := 0;
+  LCOff := (PrecompSpacing - 1) * PrecompTeeth;
+  repeat
+    LBlock := 0;
+    while LBlock < PrecompBlocks do
+    begin
+      LW := LN[LBlock] shr LCOff;
+      LSign := TBitUtilities.Asr32(Int32(LW), PrecompTeeth - 1) and 1;
+      LAbs := (Int32(LW) xor -LSign) and PrecompMask;
+      {$IFDEF DEBUG}
+      System.Assert((LSign = 0) or (LSign = 1));
+      System.Assert((0 <= LAbs) and (LAbs < PrecompPoints));
+      {$ENDIF}
+      PointLookup(LBlock, LAbs, LP);
+      TX25519Field.CNegate(LResultSign xor LSign, AR.X);
+      TX25519Field.CNegate(LResultSign xor LSign, AR.U);
+      LResultSign := LSign;
+      PointAdd(LP, AR, LT);
+      System.Inc(LBlock);
+    end;
+    LCOff := LCOff - PrecompTeeth;
+    if LCOff < 0 then
+      break;
+    PointDouble(AR);
+  until False;
+  TX25519Field.CNegate(LResultSign, AR.X);
+  TX25519Field.CNegate(LResultSign, AR.U);
 end;
 
-class constructor TEd25519.CreateEd25519;
+class procedure TEd25519.ScalarMultBaseEncoded(const AK: TCryptoLibByteArray; AR: TCryptoLibByteArray; AROff: Int32);
+var
+  LP: TPointAccum;
 begin
-  TEd25519.Boot();
+  InitPointAccum(LP);
+  ScalarMultBase(AK, LP);
+  if EncodeResult(LP, AR, AROff) = 0 then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidOp);
 end;
 
-function TEd25519.CreatePreHash: IDigest;
+class procedure TEd25519.ScalarMultBaseYZ(const AK: TCryptoLibByteArray; AKOff: Int32; AY, AZ: TCryptoLibInt32Array);
+var
+  LN: TCryptoLibByteArray;
+  LP: TPointAccum;
 begin
-  result := CreateDigest();
+  System.SetLength(LN, ScalarBytes);
+  PruneScalar(AK, AKOff, LN);
+  InitPointAccum(LP);
+  ScalarMultBase(LN, LP);
+  if CheckPoint(LP) = 0 then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidOp);
+  TX25519Field.Copy(LP.Y, 0, AY, 0);
+  TX25519Field.Copy(LP.Z, 0, AZ, 0);
 end;
 
-class function TEd25519.Decode24(const bs: TCryptoLibByteArray;
-  off: Int32): UInt32;
+class procedure TEd25519.ScalarMultOrderVar(const AP: TPointAffine; var AR: TPointAccum);
 var
-  n: UInt32;
-begin
-  n := bs[off];
-  System.Inc(off);
-  n := n or (UInt32(bs[off]) shl 8);
-  System.Inc(off);
-  n := n or (UInt32(bs[off]) shl 16);
-  result := n;
+  LWsP: TCryptoLibShortIntArray;
+  LCount: Int32;
+  LTp: TCryptoLibGenericArray<TPointPrecompZ>;
+  LT: TPointTemp;
+  LBit, LWP, LIndex: Int32;
+begin
+  System.SetLength(LWsP, 253);
+  TScalar25519.GetOrderWnafVar(WnafWidth128, LWsP);
+  LCount := 1 shl (WnafWidth128 - 2);
+  System.SetLength(LTp, LCount);
+  InitPointTemp(LT);
+  PointPrecomputeZ(AP, LTp, LCount, LT);
+  PointSetNeutral(AR);
+  LBit := 252;
+  repeat
+    LWP := LWsP[LBit];
+    if LWP <> 0 then
+    begin
+      LIndex := TBitUtilities.Asr32(LWP, 1) xor TBitUtilities.Asr32(LWP, 31);
+      PointAddVar(LWP < 0, LTp[LIndex], AR, LT);
+    end;
+    System.Dec(LBit);
+    if LBit < 0 then
+      break;
+    PointDouble(AR);
+  until False;
 end;
 
-class procedure TEd25519.PointExtendXY(var p: TPointAccum);
+class function TEd25519.CheckPointOrderVar(var AP: TPointAffine): Boolean;
+var
+  LR: TPointAccum;
 begin
-  TX25519Field.One(p.Z);
-  TX25519Field.Copy(p.X, 0, p.U, 0);
-  TX25519Field.Copy(p.Y, 0, p.V, 0);
+  InitPointAccum(LR);
+  ScalarMultOrderVar(AP, LR);
+  Result := NormalizeToNeutralElementVar(LR);
 end;
 
-class procedure TEd25519.PointExtendXY(var p: TPointExt);
+class function TEd25519.ExportPoint(var AP: TPointAffine): IPublicPoint;
+var
+  LData: TCryptoLibInt32Array;
 begin
-  TX25519Field.One(p.Z);
-  TX25519Field.Mul(p.X, p.Y, p.T);
+  System.SetLength(LData, TX25519Field.Size * 2);
+  TX25519Field.Copy(AP.X, 0, LData, 0);
+  TX25519Field.Copy(AP.Y, 0, LData, TX25519Field.Size);
+  Result := TPublicPoint.Create(LData);
 end;
 
-class procedure TEd25519.PointLookup(const table: TCryptoLibInt32Array;
-  index: Int32; var r: TPointExt);
+class procedure TEd25519.EncodePublicPoint(const APublicPoint: IPublicPoint; APk: TCryptoLibByteArray; APkOff: Int32);
 var
-  off: Int32;
+  LData: TCryptoLibInt32Array;
 begin
-  off := TX25519Field.SIZE * 4 * index;
-
-  TX25519Field.Copy(table, off, r.X, 0);
-  off := off + TX25519Field.SIZE;
-  TX25519Field.Copy(table, off, r.Y, 0);
-  off := off + TX25519Field.SIZE;
-  TX25519Field.Copy(table, off, r.Z, 0);
-  off := off + TX25519Field.SIZE;
-  TX25519Field.Copy(table, off, r.T, 0);
+  LData := APublicPoint.Data;
+  TX25519Field.Encode(LData, TX25519Field.Size, APk, APkOff);
+  APk[APkOff + PointBytes - 1] := APk[APkOff + PointBytes - 1] or Byte((LData[0] and 1) shl 7);
 end;
 
-function TEd25519.GetAlgorithmName: String;
+class function TEd25519.GeneratePublicKey(const &AS: TCryptoLibByteArray; ASOff: Int32): IPublicPoint;
+var
+  LD: IDigest;
+  LH, LS: TCryptoLibByteArray;
+  LP: TPointAccum;
+  LQ: TPointAffine;
+begin
+  LD := CreateDigest();
+  System.SetLength(LH, 64);
+  LD.BlockUpdate(&AS, ASOff, SecretKeySize);
+  LD.DoFinal(LH, 0);
+  System.SetLength(LS, ScalarBytes);
+  PruneScalar(LH, 0, LS);
+  InitPointAccum(LP);
+  ScalarMultBase(LS, LP);
+  InitPointAffine(LQ);
+  NormalizeToAffine(LP, LQ);
+  if CheckPoint(LQ) = 0 then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidOp);
+  Result := ExportPoint(LQ);
+end;
+
+class function TEd25519.ValidatePublicKeyFull(const APk: TCryptoLibByteArray; APkOff: Int32): Boolean;
+var
+  LA: TCryptoLibByteArray;
+  LPA: TPointAffine;
 begin
-  result := 'Ed25519';
+  System.SetLength(LA, PublicKeySize);
+  System.Move(APk[APkOff], LA[0], PublicKeySize);
+  if not CheckPointFullVar(LA) then
+    Exit(False);
+  InitPointAffine(LPA);
+  if not DecodePointVar(LA, False, LPA) then
+    Exit(False);
+  Result := CheckPointOrderVar(LPA);
 end;
 
-class function TEd25519.GetWindow4(const X: TCryptoLibUInt32Array;
-  n: Int32): Int32;
+class function TEd25519.ValidatePublicKeyFullExport(const APk: TCryptoLibByteArray; APkOff: Int32): IPublicPoint;
 var
-  W, b: Int32;
+  LA: TCryptoLibByteArray;
+  LPA: TPointAffine;
 begin
-  W := TBitUtilities.Asr32(n, 3);
-  b := (n and 7) shl 2;
-  result := (X[W] shr b) and 15;
+  Result := nil;
+  System.SetLength(LA, PublicKeySize);
+  System.Move(APk[APkOff], LA[0], PublicKeySize);
+  if not CheckPointFullVar(LA) then
+    Exit;
+  InitPointAffine(LPA);
+  if not DecodePointVar(LA, False, LPA) then
+    Exit;
+  if not CheckPointOrderVar(LPA) then
+    Exit;
+  Result := ExportPoint(LPA);
 end;
 
-class procedure TEd25519.PointLookup(const X: TCryptoLibUInt32Array; n: Int32;
-  const table: TCryptoLibInt32Array; var r: TPointExt);
+class function TEd25519.ValidatePublicKeyPartial(const APk: TCryptoLibByteArray; APkOff: Int32): Boolean;
 var
-  W, LSign, abs, i, off, cond: Int32;
+  LA: TCryptoLibByteArray;
+  LPA: TPointAffine;
 begin
-  W := GetWindow4(X, n);
-
-  LSign := (TBitUtilities.Asr32(W, (PrecompTeeth - 1))) xor 1;
-  abs := (W xor -LSign) and PrecompMask;
-
-{$IFDEF DEBUG}
-  System.Assert((LSign = 0) or (LSign = 1));
-  System.Assert((abs <= 0) and (abs < PrecompPoints));
-{$ENDIF DEBUG}
-  i := 0;
-  off := 0;
-
-  while i < PrecompPoints do
-  begin
-    cond := TBitUtilities.Asr32(((i xor abs) - 1), 31);
-    TX25519Field.CMov(cond, table, off, r.X, 0);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.CMov(cond, table, off, r.Y, 0);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.CMov(cond, table, off, r.Z, 0);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.CMov(cond, table, off, r.T, 0);
-    off := off + TX25519Field.SIZE;
-    System.Inc(i);
-  end;
-
-  TX25519Field.CNegate(LSign, r.X);
-  TX25519Field.CNegate(LSign, r.T);
+  System.SetLength(LA, PublicKeySize);
+  System.Move(APk[APkOff], LA[0], PublicKeySize);
+  if not CheckPointFullVar(LA) then
+    Exit(False);
+  InitPointAffine(LPA);
+  Result := DecodePointVar(LA, False, LPA);
 end;
 
-class function TEd25519.DecodePointVar(const p: TCryptoLibByteArray;
-  pOff: Int32; ANegate: Boolean; var r: TPointAffine): Boolean;
+class function TEd25519.ValidatePublicKeyPartialExport(const APk: TCryptoLibByteArray; APkOff: Int32): IPublicPoint;
 var
-  py: TCryptoLibByteArray;
-  U, V: TCryptoLibInt32Array;
-  x_0: Int32;
+  LA: TCryptoLibByteArray;
+  LPA: TPointAffine;
 begin
-  py := TArrayUtilities.CopyOfRange<Byte>(p, pOff, pOff + PointBytes);
-  if (not CheckPointVar(py)) then
-  begin
-    result := false;
+  Result := nil;
+  System.SetLength(LA, PublicKeySize);
+  System.Move(APk[APkOff], LA[0], PublicKeySize);
+  if not CheckPointFullVar(LA) then
     Exit;
-  end;
-
-  x_0 := (py[PointBytes - 1] and $80) shr 7;
-  py[PointBytes - 1] := py[PointBytes - 1] and $7F;
-
-  TX25519Field.Decode(py, 0, r.Y);
-
-  U := TX25519Field.Create();
-  V := TX25519Field.Create();
-
-  TX25519Field.Sqr(r.Y, U);
-  TX25519Field.Mul(FC_d, U, V);
-  TX25519Field.SubOne(U);
-  TX25519Field.AddOne(V);
-
-  if (not(TX25519Field.SqrtRatioVar(U, V, r.X))) then
-  begin
-    result := false;
+  InitPointAffine(LPA);
+  if not DecodePointVar(LA, False, LPA) then
     Exit;
-  end;
+  Result := ExportPoint(LPA);
+end;
 
-  TX25519Field.Normalize(r.X);
-  if ((x_0 = 1) and (TX25519Field.IsZeroVar(r.X))) then
+class procedure TEd25519.ScalarMultStraus128Var(const ANb: TCryptoLibUInt32Array; const ANp: TCryptoLibUInt32Array; const AP: TPointAffine;
+  const ANq: TCryptoLibUInt32Array; const AQ: TPointAffine; var AR: TPointAccum);
+var
+  LWsB: TCryptoLibShortIntArray;
+  LWsP, LWsQ: TCryptoLibShortIntArray;
+  LCount: Int32;
+  LTp, LTq: TCryptoLibGenericArray<TPointPrecompZ>;
+  LT: TPointTemp;
+  LBit, LWB, LWB128, LWP, LWQ, LIndex: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(System.Length(ANb) = ScalarUints);
+  System.Assert((ANb[ScalarUints - 1] shr 29) = 0);
+  System.Assert(System.Length(ANp) = 4);
+  System.Assert(System.Length(ANq) = 4);
+  {$ENDIF}
+  Precompute();
+  System.SetLength(LWsB, 256);
+  System.SetLength(LWsP, 128);
+  System.SetLength(LWsQ, 128);
+  TWnaf.GetSignedVar(ANb, WnafWidthBase, LWsB);
+  TWnaf.GetSignedVar(ANp, WnafWidth128, LWsP);
+  TWnaf.GetSignedVar(ANq, WnafWidth128, LWsQ);
+  LCount := 1 shl (WnafWidth128 - 2);
+  System.SetLength(LTp, LCount);
+  System.SetLength(LTq, LCount);
+  InitPointTemp(LT);
+  PointPrecomputeZ(AP, LTp, LCount, LT);
+  PointPrecomputeZ(AQ, LTq, LCount, LT);
+  PointSetNeutral(AR);
+  LBit := 128;
+  while LBit > 0 do
   begin
-    result := false;
-    Exit;
+    System.Dec(LBit);
+    if (Int32(LWsB[LBit]) or Int32(LWsB[128 + LBit]) or Int32(LWsP[LBit]) or Int32(LWsQ[LBit])) <> 0 then
+      break;
   end;
-
-  if (ANegate xor (x_0 <> (r.X[0] and 1))) then
+  while LBit >= 0 do
   begin
-    TX25519Field.negate(r.X, r.X);
+    LWB := LWsB[LBit];
+    if LWB <> 0 then
+    begin
+      LIndex := TBitUtilities.Asr32(LWB, 1) xor TBitUtilities.Asr32(LWB, 31);
+      PointAddVar(LWB < 0, FPrecompBaseWnaf[LIndex], AR, LT);
+    end;
+    LWB128 := LWsB[128 + LBit];
+    if LWB128 <> 0 then
+    begin
+      LIndex := TBitUtilities.Asr32(LWB128, 1) xor TBitUtilities.Asr32(LWB128, 31);
+      PointAddVar(LWB128 < 0, FPrecompBase128Wnaf[LIndex], AR, LT);
+    end;
+    LWP := LWsP[LBit];
+    if LWP <> 0 then
+    begin
+      LIndex := TBitUtilities.Asr32(LWP, 1) xor TBitUtilities.Asr32(LWP, 31);
+      PointAddVar(LWP < 0, LTp[LIndex], AR, LT);
+    end;
+    LWQ := LWsQ[LBit];
+    if LWQ <> 0 then
+    begin
+      LIndex := TBitUtilities.Asr32(LWQ, 1) xor TBitUtilities.Asr32(LWQ, 31);
+      PointAddVar(LWQ < 0, LTq[LIndex], AR, LT);
+    end;
+    PointDouble(AR);
+    System.Dec(LBit);
   end;
-
-  result := true;
-end;
-
-class destructor TEd25519.DestroyEd25519;
-begin
-  FPrecompLock.Free;
-end;
-
-class procedure TEd25519.Dom2(const d: IDigest; phflag: Byte;
-  const ctx: TCryptoLibCustomByteArrayBuffer);
-begin
-  if (not(ctx.IsNil)) then
-  begin
-    d.BlockUpdate(FDom2Prefix, 0, System.Length(FDom2Prefix));
-    d.Update(phflag);
-    d.Update(Byte(ctx.Length));
-    if ctx.Data <> Nil then
-    begin
-      d.BlockUpdate(ctx.Data, 0, ctx.Length);
-    end;
-  end;
-end;
-
-class function TEd25519.EncodePoint(var p: TPointAccum;
-  const r: TCryptoLibByteArray; rOff: Int32): Int32;
-var
-  X, Y: TCryptoLibInt32Array;
-begin
-  X := TX25519Field.Create();
-  Y := TX25519Field.Create();
-
-  TX25519Field.Inv(p.Z, Y);
-  TX25519Field.Mul(p.X, Y, X);
-  TX25519Field.Mul(p.Y, Y, Y);
-  TX25519Field.Normalize(X);
-  TX25519Field.Normalize(Y);
-
-  result := CheckPoint(X, Y);
-
-  TX25519Field.Encode(Y, r, rOff);
-  r[rOff + PointBytes - 1] := r[rOff + PointBytes - 1] or
-    Byte((X[0] and 1) shl 7);
-end;
-
-procedure TEd25519.GeneratePrivateKey(const random: ISecureRandom;
-  const k: TCryptoLibByteArray);
-begin
-  random.NextBytes(k);
-end;
-
-class procedure TEd25519.PruneScalar(const n: TCryptoLibByteArray; nOff: Int32;
-  const r: TCryptoLibByteArray);
-begin
-  System.Move(n[nOff], r[0], ScalarBytes * System.SizeOf(Byte));
-
-  r[0] := r[0] and $F8;
-  r[ScalarBytes - 1] := r[ScalarBytes - 1] and $7F;
-  r[ScalarBytes - 1] := r[ScalarBytes - 1] or $40;
-end;
-
-class procedure TEd25519.ScalarMultBaseEncoded(const k, r: TCryptoLibByteArray;
-  rOff: Int32);
-var
-  p: TPointAccum;
-begin
-  p := TPointAccum.CreatePointAccum();
-  ScalarMultBase(k, p);
-  if (EncodePoint(p, r, rOff) = 0) then
-  begin
-    raise EInvalidOperationCryptoLibException.Create('');
-  end;
-end;
-
-procedure TEd25519.GeneratePublicKey(const sk: TCryptoLibByteArray;
-  skOff: Int32; pk: TCryptoLibByteArray; pkOff: Int32);
-var
-  d: IDigest;
-  h, s: TCryptoLibByteArray;
-begin
-  d := CreateDigest();
-  System.SetLength(h, d.GetDigestSize());
-
-  d.BlockUpdate(sk, skOff, SecretKeySize);
-  d.DoFinal(h, 0);
-
-  System.SetLength(s, ScalarBytes);
-
-  PruneScalar(h, 0, s);
-
-  ScalarMultBaseEncoded(s, pk, pkOff);
-end;
-
-class function TEd25519.GetWnaf(const n: TCryptoLibUInt32Array; width: Int32)
-  : TCryptoLibShortIntArray;
-var
-  T: TCryptoLibUInt32Array;
-  ws: TCryptoLibShortIntArray;
-  i, tPos, j: Int32;
-  c, next, pow2, mask, LSign, carry, word, word16, bit, digit: UInt32;
-begin
-{$IFDEF DEBUG}
-  System.Assert((n[ScalarUints - 1] shr 28) = 0);
-{$ENDIF DEBUG}
-  System.SetLength(T, ScalarUints * 2);
-
-  c := 0;
-  tPos := System.Length(T);
-  i := ScalarUints;
-  System.Dec(i);
-  while (i >= 0) do
-  begin
-    next := n[i];
-    System.Dec(tPos);
-    T[tPos] := (next shr 16) or (c shl 16);
-    System.Dec(tPos);
-    c := next;
-    T[tPos] := c;
-    System.Dec(i);
-  end;
-
-  System.SetLength(ws, 253);
-
-  pow2 := UInt32(1) shl width;
-  mask := pow2 - UInt32(1);
-  LSign := pow2 shr 1;
-
-  carry := UInt32(0);
-  j := 0;
-
-  for i := 0 to System.Pred(System.Length(T)) do
-  begin
-    word := T[i];
-    while (j < 16) do
-    begin
-      word16 := word shr j;
-      bit := word16 and UInt32(1);
-
-      if (bit = carry) then
-      begin
-        System.Inc(j);
-        continue;
-      end;
-
-      digit := (word16 and mask) + carry;
-      carry := digit and LSign;
-      digit := digit - (carry shl 1);
-      carry := carry shr (width - 1);
-
-      ws[(i shl 4) + j] := ShortInt(digit);
-
-      j := j + width;
-    end;
-    System.Dec(j, 16);
-  end;
-
-{$IFDEF DEBUG}
-  System.Assert(carry = 0);
-{$ENDIF DEBUG}
-  result := ws;
-end;
-
-procedure TEd25519.ImplSign(const sk: TCryptoLibByteArray; skOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-  const m: TCryptoLibByteArray; mOff, mLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  d: IDigest;
-  h, s: TCryptoLibByteArray;
-begin
-  if (not CheckContextVar(ctx, phflag)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
-  end;
-
-  d := CreateDigest();
-  System.SetLength(h, d.GetDigestSize());
-
-  d.BlockUpdate(sk, skOff, SecretKeySize);
-  d.DoFinal(h, 0);
-
-  System.SetLength(s, ScalarBytes);
-  PruneScalar(h, 0, s);
-
-  ImplSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
-
-end;
-
-procedure TEd25519.ImplSign(const sk: TCryptoLibByteArray; skOff: Int32;
-  const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-  const m: TCryptoLibByteArray; mOff, mLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  d: IDigest;
-  h, s, pk: TCryptoLibByteArray;
-begin
-  if (not CheckContextVar(ctx, phflag)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
-  end;
-
-  d := CreateDigest();
-  System.SetLength(h, d.GetDigestSize());
-
-  d.BlockUpdate(sk, skOff, SecretKeySize);
-  d.DoFinal(h, 0);
-
-  System.SetLength(s, ScalarBytes);
-  PruneScalar(h, 0, s);
-
-  System.SetLength(pk, PointBytes);
-  ScalarMultBaseEncoded(s, pk, 0);
-
-  ImplSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff);
-end;
-
-class procedure TEd25519.ImplSign(const d: IDigest;
-  const h, s, pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-  const m: TCryptoLibByteArray; mOff, mLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  r, bigR, k, bigS: TCryptoLibByteArray;
-begin
-  Dom2(d, phflag, ctx);
-  d.BlockUpdate(h, ScalarBytes, ScalarBytes);
-  d.BlockUpdate(m, mOff, mLen);
-  d.DoFinal(h, 0);
-
-  r := ReduceScalar(h);
-  System.SetLength(bigR, PointBytes);
-  ScalarMultBaseEncoded(r, bigR, 0);
-
-  Dom2(d, phflag, ctx);
-  d.BlockUpdate(bigR, 0, PointBytes);
-  d.BlockUpdate(pk, pkOff, PointBytes);
-  d.BlockUpdate(m, mOff, mLen);
-  d.DoFinal(h, 0);
-
-  k := ReduceScalar(h);
-  bigS := CalculateS(r, k, s);
-
-  System.Move(bigR[0], sig[sigOff], PointBytes * System.SizeOf(Byte));
-  System.Move(bigS[0], sig[sigOff + PointBytes],
-    ScalarBytes * System.SizeOf(Byte));
-end;
-
-function TEd25519.ImplVerify(const sig: TCryptoLibByteArray; sigOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx: TCryptoLibCustomByteArrayBuffer; phflag: Byte;
-  const m: TCryptoLibByteArray; mOff, mLen: Int32): Boolean;
-var
-  r, s, h, k, check: TCryptoLibByteArray;
-  nS, nA: TCryptoLibUInt32Array;
-  pA: TPointAffine;
-  pR: TPointAccum;
-  d: IDigest;
-begin
-  if (not CheckContextVar(ctx, phflag)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
-  end;
-
-  r := TArrayUtilities.CopyOfRange<Byte>(sig, sigOff, sigOff + PointBytes);
-  s := TArrayUtilities.CopyOfRange<Byte>(sig, sigOff + PointBytes,
-    sigOff + SignatureSize);
-
-  if (not CheckPointVar(r)) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  if (not CheckScalarVar(s)) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  pA := TPointAffine.CreatePointAffine();
-  if (not DecodePointVar(pk, pkOff, true, pA)) then
-  begin
-    result := false;
-    Exit;
-  end;
-
-  d := CreateDigest();
-  System.SetLength(h, d.GetDigestSize());
-
-  Dom2(d, phflag, ctx);
-  d.BlockUpdate(r, 0, PointBytes);
-  d.BlockUpdate(pk, pkOff, PointBytes);
-  d.BlockUpdate(m, mOff, mLen);
-  d.DoFinal(h, 0);
-
-  k := ReduceScalar(h);
-
-  System.SetLength(nS, ScalarUints);
-  DecodeScalar(s, 0, nS);
-
-  System.SetLength(nA, ScalarUints);
-
-  DecodeScalar(k, 0, nA);
-
-  pR := TPointAccum.CreatePointAccum();
-  ScalarMultStrausVar(nS, nA, pA, pR);
-
-  System.SetLength(check, PointBytes);
-
-  EncodePoint(pR, check, 0);
-
-  result := (EncodePoint(pR, check, 0) <> 0) and
-    (TArrayUtilities.FixedTimeEquals(check, r));
-end;
-
-class procedure TEd25519.PointAddPrecomp(var p: TPointPrecomp;
-  var r: TPointAccum);
-var
-  bigA, bigB, bigC, bigD, bigE, bigF, bigG: TCryptoLibInt32Array;
-begin
-  bigA := TX25519Field.Create();
-  bigB := TX25519Field.Create();
-  bigC := TX25519Field.Create();
-  bigD := r.U;
-  bigE := TX25519Field.Create();
-  bigF := TX25519Field.Create();
-  bigG := r.V;
-
-  TX25519Field.Apm(r.Y, r.X, bigB, bigA);
-  TX25519Field.Mul(bigA, p.Ymx_h, bigA);
-  TX25519Field.Mul(bigB, p.Ypx_h, bigB);
-  TX25519Field.Mul(r.U, r.V, bigC);
-  TX25519Field.Mul(bigC, p.Xyd, bigC);
-  TX25519Field.Apm(bigB, bigA, bigG, bigD);
-  TX25519Field.Apm(r.Z, bigC, bigF, bigE);
-  TX25519Field.carry(bigF);
-  TX25519Field.Mul(bigD, bigE, r.X);
-  TX25519Field.Mul(bigF, bigG, r.Y);
-  TX25519Field.Mul(bigE, bigF, r.Z);
-end;
-
-class procedure TEd25519.PointAdd(var p: TPointExt; var r: TPointAccum);
-var
-  A, b, c, d, E, F, G, h: TCryptoLibInt32Array;
-begin
-  A := TX25519Field.Create();
-  b := TX25519Field.Create();
-  c := TX25519Field.Create();
-  d := TX25519Field.Create();
-  E := r.U;
-  F := TX25519Field.Create();
-  G := TX25519Field.Create();
-  h := r.V;
-
-  TX25519Field.Apm(r.Y, r.X, b, A);
-  TX25519Field.Apm(p.Y, p.X, d, c);
-  TX25519Field.Mul(A, c, A);
-  TX25519Field.Mul(b, d, b);
-  TX25519Field.Mul(r.U, r.V, c);
-  TX25519Field.Mul(c, p.T, c);
-  TX25519Field.Mul(c, FC_d2, c);
-  TX25519Field.Mul(r.Z, p.Z, d);
-  TX25519Field.Add(d, d, d);
-  TX25519Field.Apm(b, A, h, E);
-  TX25519Field.Apm(d, c, G, F);
-  TX25519Field.carry(G);
-  TX25519Field.Mul(E, F, r.X);
-  TX25519Field.Mul(G, h, r.Y);
-  TX25519Field.Mul(F, G, r.Z);
-end;
-
-class procedure TEd25519.PointAdd(var p, r: TPointExt);
-var
-  A, b, c, d, E, F, G, h: TCryptoLibInt32Array;
-begin
-  A := TX25519Field.Create();
-  b := TX25519Field.Create();
-  c := TX25519Field.Create();
-  d := TX25519Field.Create();
-  E := TX25519Field.Create();
-  F := TX25519Field.Create();
-  G := TX25519Field.Create();
-  h := TX25519Field.Create();
-
-  TX25519Field.Apm(p.Y, p.X, b, A);
-  TX25519Field.Apm(r.Y, r.X, d, c);
-  TX25519Field.Mul(A, c, A);
-  TX25519Field.Mul(b, d, b);
-  TX25519Field.Mul(p.T, r.T, c);
-  TX25519Field.Mul(c, FC_d2, c);
-  TX25519Field.Mul(p.Z, r.Z, d);
-  TX25519Field.Add(d, d, d);
-  TX25519Field.Apm(b, A, h, E);
-  TX25519Field.Apm(d, c, G, F);
-  TX25519Field.carry(G);
-  TX25519Field.Mul(E, F, r.X);
-  TX25519Field.Mul(G, h, r.Y);
-  TX25519Field.Mul(F, G, r.Z);
-  TX25519Field.Mul(E, h, r.T);
-end;
-
-class procedure TEd25519.PointAddVar(negate: Boolean; var p, q, r: TPointExt);
-var
-  bigA, bigB, bigC, bigD, bigE, bigF, bigG, bigH, c, d, F,
-    G: TCryptoLibInt32Array;
-begin
-  bigA := TX25519Field.Create();
-  bigB := TX25519Field.Create();
-  bigC := TX25519Field.Create();
-  bigD := TX25519Field.Create();
-  bigE := TX25519Field.Create();
-  bigF := TX25519Field.Create();
-  bigG := TX25519Field.Create();
-  bigH := TX25519Field.Create();
-
-  if (negate) then
-  begin
-    c := bigD;
-    d := bigC;
-    F := bigG;
-    G := bigF;
-  end
-  else
-  begin
-    c := bigC;
-    d := bigD;
-    F := bigF;
-    G := bigG;
-  end;
-
-  TX25519Field.Apm(p.Y, p.X, bigB, bigA);
-  TX25519Field.Apm(q.Y, q.X, d, c);
-  TX25519Field.Mul(bigA, bigC, bigA);
-  TX25519Field.Mul(bigB, bigD, bigB);
-  TX25519Field.Mul(p.T, q.T, bigC);
-  TX25519Field.Mul(bigC, FC_d2, bigC);
-  TX25519Field.Mul(p.Z, q.Z, bigD);
-  TX25519Field.Add(bigD, bigD, bigD);
-  TX25519Field.Apm(bigB, bigA, bigH, bigE);
-  TX25519Field.Apm(bigD, bigC, G, F);
-  TX25519Field.carry(G);
-  TX25519Field.Mul(bigE, bigF, r.X);
-  TX25519Field.Mul(bigG, bigH, r.Y);
-  TX25519Field.Mul(bigF, bigG, r.Z);
-  TX25519Field.Mul(bigE, bigH, r.T);
-end;
-
-class procedure TEd25519.PointAddVar(negate: Boolean; var p: TPointExt;
-  var r: TPointAccum);
-var
-  bigA, bigB, bigC, bigD, bigE, bigF, bigG, bigH, c, d, F,
-    G: TCryptoLibInt32Array;
-begin
-  bigA := TX25519Field.Create();
-  bigB := TX25519Field.Create();
-  bigC := TX25519Field.Create();
-  bigD := TX25519Field.Create();
-  bigE := r.U;
-  bigF := TX25519Field.Create();
-  bigG := TX25519Field.Create();
-  bigH := r.V;
-
-  if (negate) then
-  begin
-    c := bigD;
-    d := bigC;
-    F := bigG;
-    G := bigF;
-  end
-  else
-  begin
-    c := bigC;
-    d := bigD;
-    F := bigF;
-    G := bigG;
-  end;
-
-  TX25519Field.Apm(r.Y, r.X, bigB, bigA);
-  TX25519Field.Apm(p.Y, p.X, d, c);
-  TX25519Field.Mul(bigA, bigC, bigA);
-  TX25519Field.Mul(bigB, bigD, bigB);
-  TX25519Field.Mul(r.U, r.V, bigC);
-  TX25519Field.Mul(bigC, p.T, bigC);
-  TX25519Field.Mul(bigC, FC_d2, bigC);
-  TX25519Field.Mul(r.Z, p.Z, bigD);
-  TX25519Field.Add(bigD, bigD, bigD);
-  TX25519Field.Apm(bigB, bigA, bigH, bigE);
-  TX25519Field.Apm(bigD, bigC, G, F);
-  TX25519Field.carry(G);
-  TX25519Field.Mul(bigE, bigF, r.X);
-  TX25519Field.Mul(bigG, bigH, r.Y);
-  TX25519Field.Mul(bigF, bigG, r.Z);
-end;
-
-class function TEd25519.PointCopy(var p: TPointAffine): TPointExt;
-var
-  r: TPointExt;
-begin
-  r := TPointExt.CreatePointExt();
-  TX25519Field.Copy(p.X, 0, r.X, 0);
-  TX25519Field.Copy(p.Y, 0, r.Y, 0);
-  PointExtendXY(r);
-  result := r;
-end;
-
-class function TEd25519.PointCopy(var p: TPointAccum): TPointExt;
-var
-  r: TPointExt;
-begin
-  r := TPointExt.CreatePointExt();
-  TX25519Field.Copy(p.X, 0, r.X, 0);
-  TX25519Field.Copy(p.Y, 0, r.Y, 0);
-  TX25519Field.Copy(p.Z, 0, r.Z, 0);
-  TX25519Field.Mul(p.U, p.V, r.T);
-  result := r;
-end;
-
-class function TEd25519.PointCopy(var p: TPointExt): TPointExt;
-var
-  r: TPointExt;
-begin
-  r := TPointExt.CreatePointExt();
-  PointCopy(p, r);
-  result := r;
-end;
-
-class procedure TEd25519.PointDouble(var r: TPointAccum);
-var
-  bigA, bigB, bigC, bigD, bigE, bigF, bigG: TCryptoLibInt32Array;
-begin
-  bigA := TX25519Field.Create();
-  bigB := TX25519Field.Create();
-  bigC := TX25519Field.Create();
-  bigD := r.U;
-  bigE := TX25519Field.Create();
-  bigF := TX25519Field.Create();
-  bigG := r.V;
-
-  TX25519Field.Sqr(r.X, bigA);
-  TX25519Field.Sqr(r.Y, bigB);
-  TX25519Field.Sqr(r.Z, bigC);
-  TX25519Field.Add(bigC, bigC, bigC);
-  TX25519Field.Apm(bigA, bigB, bigG, bigF);
-  TX25519Field.Add(r.X, r.Y, bigD);
-  TX25519Field.Sqr(bigD, bigD);
-  TX25519Field.Sub(bigG, bigD, bigD);
-  TX25519Field.Add(bigC, bigF, bigE);
-  TX25519Field.carry(bigE);
-  TX25519Field.Mul(bigD, bigE, r.X);
-  TX25519Field.Mul(bigF, bigG, r.Y);
-  TX25519Field.Mul(bigE, bigF, r.Z);
-end;
-
-class procedure TEd25519.PointLookup(block, index: Int32; var p: TPointPrecomp);
-var
-  off, i, cond: Int32;
-begin
-{$IFDEF DEBUG}
-  System.Assert((0 <= block) and (block < PrecompBlocks));
-  System.Assert((0 <= index) and (index < PrecompPoints));
-{$ENDIF DEBUG}
-  off := block * PrecompPoints * 3 * TX25519Field.SIZE;
-
-  for i := 0 to System.Pred(PrecompPoints) do
-  begin
-    cond := TBitUtilities.Asr32(((i xor index) - 1), 31);
-    TX25519Field.CMov(cond, FPrecompBase, off, p.Ypx_h, 0);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.CMov(cond, FPrecompBase, off, p.Ymx_h, 0);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.CMov(cond, FPrecompBase, off, p.Xyd, 0);
-    off := off + TX25519Field.SIZE;
-  end;
-end;
-
-class function TEd25519.PointPrecomp(var p: TPointAffine; count: Int32)
-  : TCryptoLibInt32Array;
-var
-  q, d: TPointExt;
-  table: TCryptoLibInt32Array;
-  off, i: Int32;
-begin
-{$IFDEF DEBUG}
-  System.Assert(count > 0);
-{$ENDIF DEBUG}
-  q := PointCopy(p);
-  d := PointCopy(q);
-  PointAdd(q, d);
-
-  table := TX25519Field.createTable(count * 4);
-  off := 0;
-
-  i := 0;
-
-  while (true) do
-  begin
-    TX25519Field.Copy(q.X, 0, table, off);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.Copy(q.Y, 0, table, off);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.Copy(q.Z, 0, table, off);
-    off := off + TX25519Field.SIZE;
-    TX25519Field.Copy(q.T, 0, table, off);
-    off := off + TX25519Field.SIZE;
-
-    System.Inc(i);
-
-    if (i = count) then
-    begin
-      break;
-    end;
-
-    PointAdd(d, q);
-
-    System.Inc(i);
-  end;
-
-  result := table;
-end;
-
-class function TEd25519.PointPrecompVar(var p: TPointExt; count: Int32)
-  : TCryptoLibGenericArray<TPointExt>;
-var
-  d: TPointExt;
-  table: TCryptoLibGenericArray<TPointExt>;
-  i: Int32;
-begin
-{$IFDEF DEBUG}
-  System.Assert(count > 0);
-{$ENDIF DEBUG}
-  d := TPointExt.CreatePointExt();
-  PointAddVar(false, p, p, d);
-
-  System.SetLength(table, count);
-
-  table[0] := PointCopy(p);
-  for i := 1 to System.Pred(count) do
-  begin
-    table[i] := TPointExt.CreatePointExt();
-    PointAddVar(false, table[i - 1], d, table[i]);
-  end;
-  result := table;
-end;
-
-class procedure TEd25519.PointSetNeutral(var p: TPointAccum);
-begin
-  TX25519Field.Zero(p.X);
-  TX25519Field.One(p.Y);
-  TX25519Field.One(p.Z);
-  TX25519Field.Zero(p.U);
-  TX25519Field.One(p.V);
-end;
-
-class procedure TEd25519.PointSetNeutral(var p: TPointExt);
-begin
-  TX25519Field.Zero(p.X);
-  TX25519Field.One(p.Y);
-  TX25519Field.One(p.Z);
-  TX25519Field.Zero(p.T);
+  PointDouble(AR);
+  PointDouble(AR);
 end;
 
 class procedure TEd25519.Precompute;
 var
-  bigB: TPointExt;
-  p: TPointAccum;
-  X, Y: TCryptoLibInt32Array;
-  off, b, T, s, k, SIZE, j, i: Int32;
-  // ds, points: TCryptoLibGenericArray<TPointExt>;
-  ds: array [0 .. (PrecompTeeth - 1)] of TPointExt;
-  points: array [0 .. (PrecompPoints - 1)] of TPointExt;
-  sum, q: TPointExt;
-  r: TPointPrecomp;
-begin
-  FPrecompLock.Acquire;
+  LWnafPoints, LCombPoints, LTotalPoints: Int32;
+  LPoints: TCryptoLibGenericArray<TPointExtended>;
+  LT: TPointTemp;
+  LB, LB128: TPointAffine;
+  LP: TPointAccum;
+  LPointsIndex: Int32;
+  LToothPowers: TCryptoLibGenericArray<TPointExtended>;
+  LTooth, LBlock, LSpacing, LSize, LJ: Int32;
+  LU: TPointExtended;
+  LPointsIndex2: Int32;
+  LS: TPointPrecomp;
+  LOff: Int32;
+  LI: Int32;
+begin
+  FPrecompLock.Enter;
   try
-
-    if (FPrecompBase <> Nil) then
-    begin
+    if FPrecompBaseComb <> nil then
       Exit;
-    end;
-
-    // Precomputed table for the base point in verification ladder
-    bigB := TPointExt.CreatePointExt();
-    TX25519Field.Copy(FB_x, 0, bigB.X, 0);
-    TX25519Field.Copy(FB_y, 0, bigB.Y, 0);
-    PointExtendXY(bigB);
-
-    FPrecompBaseTable := PointPrecompVar(bigB, 1 shl (WnafWidthBase - 2));
-
-    p := TPointAccum.CreatePointAccum();
-    TX25519Field.Copy(FB_x, 0, p.X, 0);
-    TX25519Field.Copy(FB_y, 0, p.Y, 0);
-    PointExtendXY(p);
-
-    FPrecompBase := TX25519Field.createTable(PrecompBlocks * PrecompPoints * 3);
-
-    off := 0;
-    for b := 0 to System.Pred(PrecompBlocks) do
+    LWnafPoints := 1 shl (WnafWidthBase - 2);
+    LCombPoints := PrecompBlocks * PrecompPoints;
+    LTotalPoints := LWnafPoints * 2 + LCombPoints;
+    System.SetLength(LPoints, LTotalPoints);
+    InitPointTemp(LT);
+    InitPointAffine(LB);
+    TX25519Field.Copy(FB_x, 0, LB.X, 0);
+    TX25519Field.Copy(FB_y, 0, LB.Y, 0);
+    PointPrecompute(LB, LPoints, 0, LWnafPoints, LT);
+    InitPointAffine(LB128);
+    TX25519Field.Copy(FB128_x, 0, LB128.X, 0);
+    TX25519Field.Copy(FB128_y, 0, LB128.Y, 0);
+    PointPrecompute(LB128, LPoints, LWnafPoints, LWnafPoints, LT);
+    InitPointAccum(LP);
+    TX25519Field.Copy(FB_x, 0, LP.X, 0);
+    TX25519Field.Copy(FB_y, 0, LP.Y, 0);
+    TX25519Field.One(LP.Z);
+    TX25519Field.Copy(FB_x, 0, LP.U, 0);
+    TX25519Field.Copy(FB_y, 0, LP.V, 0);
+    LPointsIndex := LWnafPoints * 2;
+    System.SetLength(LToothPowers, PrecompTeeth);
+    for LTooth := 0 to PrecompTeeth - 1 do
+      InitPointExtended(LToothPowers[LTooth]);
+    InitPointExtended(LU);
+    for LBlock := 0 to PrecompBlocks - 1 do
     begin
-      // System.SetLength(ds, PrecompTeeth); // **
-
-      sum := TPointExt.CreatePointExt();
-      PointSetNeutral(sum);
-
-      for T := 0 to System.Pred(PrecompTeeth) do
+      InitPointExtended(LPoints[LPointsIndex]);
+      for LTooth := 0 to PrecompTeeth - 1 do
       begin
-        q := PointCopy(p);
-        PointAddVar(true, sum, q, sum);
-        PointDouble(p);
-
-        ds[T] := PointCopy(p);
-
-        if ((b + T) <> (PrecompBlocks + PrecompTeeth - 2)) then
+        if LTooth = 0 then
+          PointCopy(LP, LPoints[LPointsIndex])
+        else
         begin
-          s := 1;
-          while s < PrecompSpacing do
-          begin
-            PointDouble(p);
-            System.Inc(s);
-          end;
+          PointCopy(LP, LU);
+          PointAdd(LPoints[LPointsIndex], LU, LPoints[LPointsIndex], LT);
         end;
-      end;
-
-      // System.SetLength(points, PrecompPoints); // **
-
-      k := 0;
-      points[k] := sum;
-      System.Inc(k);
-
-      for T := 0 to System.Pred(PrecompTeeth - 1) do
-      begin
-        SIZE := 1 shl T;
-        j := 0;
-        while j < SIZE do
+        PointDouble(LP);
+        PointCopy(LP, LToothPowers[LTooth]);
+        if LBlock + LTooth <> PrecompBlocks + PrecompTeeth - 2 then
         begin
-          points[k] := TPointExt.CreatePointExt();
-          PointAddVar(false, points[k - SIZE], ds[T], points[k]);
-          System.Inc(k);
-          System.Inc(j);
+          for LSpacing := 1 to PrecompSpacing - 1 do
+            PointDouble(LP);
         end;
-
       end;
-{$IFDEF DEBUG}
-      System.Assert(k = PrecompPoints);
-{$ENDIF DEBUG}
-      for i := 0 to System.Pred(PrecompPoints) do
+      TX25519Field.Negate(LPoints[LPointsIndex].X, LPoints[LPointsIndex].X);
+      TX25519Field.Negate(LPoints[LPointsIndex].T, LPoints[LPointsIndex].T);
+      System.Inc(LPointsIndex);
+      for LTooth := 0 to PrecompTeeth - 2 do
       begin
-        q := points[i];
-
-        X := TX25519Field.Create();
-        Y := TX25519Field.Create();
-
-        TX25519Field.Add(q.Z, q.Z, X);
-        // TODO[ed25519] Batch inversion
-        TX25519Field.Inv(X, Y);
-        TX25519Field.Mul(q.X, Y, X);
-        TX25519Field.Mul(q.Y, Y, Y);
-
-        r := TPointPrecomp.CreatePointPrecomp();
-        TX25519Field.Apm(Y, X, r.Ypx_h, r.Ymx_h);
-        TX25519Field.Mul(X, Y, r.Xyd);
-        TX25519Field.Mul(r.Xyd, FC_d4, r.Xyd);
-
-        TX25519Field.Normalize(r.Ypx_h);
-        TX25519Field.Normalize(r.Ymx_h);
-        // TX25519Field.Normalize(r.xyd);
-
-        TX25519Field.Copy(r.Ypx_h, 0, FPrecompBase, off);
-        off := off + TX25519Field.SIZE;
-        TX25519Field.Copy(r.Ymx_h, 0, FPrecompBase, off);
-        off := off + TX25519Field.SIZE;
-        TX25519Field.Copy(r.Xyd, 0, FPrecompBase, off);
-        off := off + TX25519Field.SIZE;
+        LSize := 1 shl LTooth;
+        for LJ := 0 to LSize - 1 do
+        begin
+          InitPointExtended(LPoints[LPointsIndex]);
+          PointAdd(LPoints[LPointsIndex - LSize], LToothPowers[LTooth], LPoints[LPointsIndex], LT);
+          System.Inc(LPointsIndex);
+        end;
       end;
     end;
-
-{$IFDEF DEBUG}
-    System.Assert(off = System.Length(FPrecompBase));
-{$ENDIF DEBUG}
-  finally
-    FPrecompLock.Release;
-  end;
-end;
-
-class function TEd25519.ReduceScalar(const n: TCryptoLibByteArray)
-  : TCryptoLibByteArray;
-var
-  x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14,
-    x15, x16, x17, x18, T: Int64;
-begin
-  x00 := Decode32(n, 0) and Int64(M32L); // x00:32/--
-  x01 := (Decode24(n, 4) shl 4) and Int64(M32L); // x01:28/--
-  x02 := Decode32(n, 7) and Int64(M32L); // x02:32/--
-  x03 := (Decode24(n, 11) shl 4) and Int64(M32L); // x03:28/--
-  x04 := Decode32(n, 14) and Int64(M32L); // x04:32/--
-  x05 := (Decode24(n, 18) shl 4) and Int64(M32L); // x05:28/--
-  x06 := Decode32(n, 21) and Int64(M32L); // x06:32/--
-  x07 := (Decode24(n, 25) shl 4) and Int64(M32L); // x07:28/--
-  x08 := Decode32(n, 28) and Int64(M32L); // x08:32/--
-  x09 := (Decode24(n, 32) shl 4) and Int64(M32L); // x09:28/--
-  x10 := Decode32(n, 35) and Int64(M32L); // x10:32/--
-  x11 := (Decode24(n, 39) shl 4) and Int64(M32L); // x11:28/--
-  x12 := Decode32(n, 42) and Int64(M32L); // x12:32/--
-  x13 := (Decode24(n, 46) shl 4) and Int64(M32L); // x13:28/--
-  x14 := Decode32(n, 49) and Int64(M32L); // x14:32/--
-  x15 := (Decode24(n, 53) shl 4) and Int64(M32L); // x15:28/--
-  x16 := Decode32(n, 56) and Int64(M32L); // x16:32/--
-  x17 := (Decode24(n, 60) shl 4) and Int64(M32L); // x17:28/--
-  x18 := n[63] and Int64($FF); // x18:08/--
-
-  // x18 := x18 + (x17 shr  28); x17 := x17 and Int64(M28L);
-  x09 := x09 - (x18 * L0); // x09:34/28
-  x10 := x10 - (x18 * L1); // x10:33/30
-  x11 := x11 - (x18 * L2); // x11:35/28
-  x12 := x12 - (x18 * L3); // x12:32/31
-  x13 := x13 - (x18 * L4); // x13:28/21
-
-  x17 := x17 + TBitUtilities.Asr64(x16, 28); // x17:28/--
-  x16 := x16 and Int64(M28L); // x16:28/--
-  x08 := x08 - (x17 * L0); // x08:54/32
-  x09 := x09 - (x17 * L1); // x09:52/51
-  x10 := x10 - (x17 * L2); // x10:55/34
-  x11 := x11 - (x17 * L3); // x11:51/36
-  x12 := x12 - (x17 * L4); // x12:41/--
-
-  // x16 := x16 + (x15 shr  28); x15 := x15 and Int64(M28L);
-  x07 := x07 - (x16 * L0); // x07:54/28
-  x08 := x08 - (x16 * L1); // x08:54/53
-  x09 := x09 - (x16 * L2); // x09:55/53
-  x10 := x10 - (x16 * L3); // x10:55/52
-  x11 := x11 - (x16 * L4); // x11:51/41
-
-  x15 := x15 + TBitUtilities.Asr64(x14, 28); // x15:28/--
-  x14 := x14 and Int64(M28L); // x14:28/--
-  x06 := x06 - (x15 * L0); // x06:54/32
-  x07 := x07 - (x15 * L1); // x07:54/53
-  x08 := x08 - (x15 * L2); // x08:56/--
-  x09 := x09 - (x15 * L3); // x09:55/54
-  x10 := x10 - (x15 * L4); // x10:55/53
-
-  // x14 := x14 + (x13 shr  28); x13 := x13 and Int64(M28L);
-  x05 := x05 - (x14 * L0); // x05:54/28
-  x06 := x06 - (x14 * L1); // x06:54/53
-  x07 := x07 - (x14 * L2); // x07:56/--
-  x08 := x08 - (x14 * L3); // x08:56/51
-  x09 := x09 - (x14 * L4); // x09:56/--
-
-  x13 := x13 + TBitUtilities.Asr64(x12, 28); // x13:28/22
-  x12 := x12 and Int64(M28L); // x12:28/--
-  x04 := x04 - (x13 * L0); // x04:54/49
-  x05 := x05 - (x13 * L1); // x05:54/53
-  x06 := x06 - (x13 * L2); // x06:56/--
-  x07 := x07 - (x13 * L3); // x07:56/52
-  x08 := x08 - (x13 * L4); // x08:56/52
-
-  x12 := x12 + TBitUtilities.Asr64(x11, 28); // x12:28/24
-  x11 := x11 and Int64(M28L); // x11:28/--
-  x03 := x03 - (x12 * L0); // x03:54/49
-  x04 := x04 - (x12 * L1); // x04:54/51
-  x05 := x05 - (x12 * L2); // x05:56/--
-  x06 := x06 - (x12 * L3); // x06:56/52
-  x07 := x07 - (x12 * L4); // x07:56/53
-
-  x11 := x11 + TBitUtilities.Asr64(x10, 28); // x11:29/--
-  x10 := x10 and Int64(M28L); // x10:28/--
-  x02 := x02 - (x11 * L0); // x02:55/32
-  x03 := x03 - (x11 * L1); // x03:55/--
-  x04 := x04 - (x11 * L2); // x04:56/55
-  x05 := x05 - (x11 * L3); // x05:56/52
-  x06 := x06 - (x11 * L4); // x06:56/53
-
-  x10 := x10 + TBitUtilities.Asr64(x09, 28); // x10:29/--
-  x09 := x09 and Int64(M28L); // x09:28/--
-  x01 := x01 - (x10 * L0); // x01:55/28
-  x02 := x02 - (x10 * L1); // x02:55/54
-  x03 := x03 - (x10 * L2); // x03:56/55
-  x04 := x04 - (x10 * L3); // x04:57/--
-  x05 := x05 - (x10 * L4); // x05:56/53
-
-  x08 := x08 + TBitUtilities.Asr64(x07, 28); // x08:56/53
-  x07 := x07 and Int64(M28L); // x07:28/--
-  x09 := x09 + TBitUtilities.Asr64(x08, 28); // x09:29/25
-  x08 := x08 and Int64(M28L); // x08:28/--
-
-  T := TBitUtilities.Asr64(x08, 27) and Int64(1);
-  x09 := x09 + T; // x09:29/26
-
-  x00 := x00 - (x09 * L0); // x00:55/53
-  x01 := x01 - (x09 * L1); // x01:55/54
-  x02 := x02 - (x09 * L2); // x02:57/--
-  x03 := x03 - (x09 * L3); // x03:57/--
-  x04 := x04 - (x09 * L4); // x04:57/42
-
-  x01 := x01 + TBitUtilities.Asr64(x00, 28);
-  x00 := x00 and Int64(M28L);
-  x02 := x02 + TBitUtilities.Asr64(x01, 28);
-  x01 := x01 and Int64(M28L);
-  x03 := x03 + TBitUtilities.Asr64(x02, 28);
-  x02 := x02 and Int64(M28L);
-  x04 := x04 + TBitUtilities.Asr64(x03, 28);
-  x03 := x03 and Int64(M28L);
-  x05 := x05 + TBitUtilities.Asr64(x04, 28);
-  x04 := x04 and Int64(M28L);
-  x06 := x06 + TBitUtilities.Asr64(x05, 28);
-  x05 := x05 and Int64(M28L);
-  x07 := x07 + TBitUtilities.Asr64(x06, 28);
-  x06 := x06 and Int64(M28L);
-  x08 := x08 + TBitUtilities.Asr64(x07, 28);
-  x07 := x07 and Int64(M28L);
-  x09 := TBitUtilities.Asr64(x08, 28);
-  x08 := x08 and Int64(M28L);
-
-  x09 := x09 - T;
-
-{$IFDEF DEBUG}
-  System.Assert((x09 = Int64(0)) or (x09 = -Int64(1)));
-{$ENDIF DEBUG}
-  x00 := x00 + (x09 and L0);
-  x01 := x01 + (x09 and L1);
-  x02 := x02 + (x09 and L2);
-  x03 := x03 + (x09 and L3);
-  x04 := x04 + (x09 and L4);
-
-  x01 := x01 + TBitUtilities.Asr64(x00, 28);
-  x00 := x00 and Int64(M28L);
-  x02 := x02 + TBitUtilities.Asr64(x01, 28);
-  x01 := x01 and Int64(M28L);
-  x03 := x03 + TBitUtilities.Asr64(x02, 28);
-  x02 := x02 and Int64(M28L);
-  x04 := x04 + TBitUtilities.Asr64(x03, 28);
-  x03 := x03 and Int64(M28L);
-  x05 := x05 + TBitUtilities.Asr64(x04, 28);
-  x04 := x04 and Int64(M28L);
-  x06 := x06 + TBitUtilities.Asr64(x05, 28);
-  x05 := x05 and Int64(M28L);
-  x07 := x07 + TBitUtilities.Asr64(x06, 28);
-  x06 := x06 and Int64(M28L);
-  x08 := x08 + TBitUtilities.Asr64(x07, 28);
-  x07 := x07 and Int64(M28L);
-
-  System.SetLength(result, ScalarBytes);
-  Encode56(UInt64(x00 or (x01 shl 28)), result, 0);
-  Encode56(UInt64(x02 or (x03 shl 28)), result, 7);
-  Encode56(UInt64(x04 or (x05 shl 28)), result, 14);
-  Encode56(UInt64(x06 or (x07 shl 28)), result, 21);
-  Encode32(UInt32(x08), result, 28);
-end;
-
-class procedure TEd25519.ScalarMult(const k: TCryptoLibByteArray;
-  var p: TPointAffine; var r: TPointAccum);
-var
-  n: TCryptoLibUInt32Array;
-  table: TCryptoLibInt32Array;
-  q: TPointExt;
-  W, c1, c2: Int32;
-begin
-  Precompute();
-  System.SetLength(n, ScalarUints);
-
-  DecodeScalar(k, 0, n);
-
-{$IFDEF DEBUG}
-  System.Assert((n[0] and 7) = 0);
-  System.Assert((TBitUtilities.Asr32(n[ScalarUints - 1], 30)) = 1);
-{$ENDIF DEBUG}
-  TNat.ShiftDownBits(ScalarUints, n, 3, 1);
-
-  c1 := TNat.CAdd(ScalarUints, ((not n[0]) and 1), n, FL, n);
-{$IFOPT C+}
-  System.Assert(c1 = 0);
-{$ENDIF}
-  c2 := TNat.ShiftDownBit(ScalarUints, n, 0);
-{$IFOPT C+}
-  System.Assert(c2 = (1 shl 31));
-{$ENDIF}
-{$IFDEF DEBUG}
-  System.Assert((TBitUtilities.Asr32(n[ScalarUints - 1], 28)) = 1);
-{$ENDIF DEBUG}
-  PointCopy(p, r);
-
-  table := PointPrecomp(p, 8);
-
-  q := TPointExt.CreatePointExt();
-
-  // Replace first 4 doublings (2^4 * P) with 1 addition (P + 15 * P)
-  PointLookup(table, 7, q);
-  PointAdd(q, r);
-
-  W := 62;
-  while (true) do
-  begin
-    PointLookup(n, W, table, q);
-    PointAdd(q, r);
-
-    PointDouble(r);
-    PointDouble(r);
-    PointDouble(r);
-
-    System.Dec(W);
-    if (W < 0) then
+    {$IFDEF DEBUG}
+    System.Assert(LPointsIndex = LTotalPoints);
+    {$ENDIF}
+    InvertDoubleZs(LPoints);
+    System.SetLength(FPrecompBaseWnaf, LWnafPoints);
+    for LI := 0 to LWnafPoints - 1 do
     begin
-      break;
+      InitPointPrecomp(FPrecompBaseWnaf[LI]);
+      TX25519Field.Mul(LPoints[LI].X, LPoints[LI].Z, LPoints[LI].X);
+      TX25519Field.Mul(LPoints[LI].Y, LPoints[LI].Z, LPoints[LI].Y);
+      TX25519Field.Apm(LPoints[LI].Y, LPoints[LI].X, FPrecompBaseWnaf[LI].YpxH, FPrecompBaseWnaf[LI].YmxH);
+      TX25519Field.Mul(LPoints[LI].X, LPoints[LI].Y, FPrecompBaseWnaf[LI].Xyd);
+      TX25519Field.Mul(FPrecompBaseWnaf[LI].Xyd, FC_d4, FPrecompBaseWnaf[LI].Xyd);
+      TX25519Field.Normalize(FPrecompBaseWnaf[LI].YmxH);
+      TX25519Field.Normalize(FPrecompBaseWnaf[LI].YpxH);
+      TX25519Field.Normalize(FPrecompBaseWnaf[LI].Xyd);
     end;
-
-    PointDouble(r);
-  end;
-end;
-
-class procedure TEd25519.ScalarMultBase(const k: TCryptoLibByteArray;
-  var r: TPointAccum);
-var
-  n: TCryptoLibUInt32Array;
-  W, c1, c2: UInt32;
-  i, cOff, b, LSign, abs: Int32;
-  p: TPointPrecomp;
-begin
-  Precompute();
-
-  PointSetNeutral(r);
-  System.SetLength(n, ScalarUints);
-  DecodeScalar(k, 0, n);
-
-  // Recode the scalar into signed-digit form, then group comb bits in each block
-
-  c1 := TNat.CAdd(ScalarUints, not(Int32(n[0])) and 1, n, FL, n);
-{$IFOPT C+}
-  System.Assert(c1 = 0);
-{$ENDIF}
-  c2 := TNat.ShiftDownBit(ScalarUints, n, UInt32(1));
-{$IFOPT C+}
-  System.Assert(c2 = (UInt32(1) shl 31));
-{$ENDIF}
-  for i := 0 to System.Pred(ScalarUints) do
-  begin
-    n[i] := TInterleave.Shuffle2(n[i]);
-  end;
-
-  p := TPointPrecomp.CreatePointPrecomp();
-
-  cOff := (PrecompSpacing - 1) * PrecompTeeth;
-  while true do
-
-  begin
-    for b := 0 to System.Pred(PrecompBlocks) do
+    System.SetLength(FPrecompBase128Wnaf, LWnafPoints);
+    for LI := 0 to LWnafPoints - 1 do
     begin
-      W := n[b] shr cOff;
-      LSign := Int32(W shr (PrecompTeeth - 1)) and 1;
-      abs := (Int32(W) xor -LSign) and PrecompMask;
-
-{$IFDEF DEBUG}
-      System.Assert((LSign = 0) or (LSign = 1));
-      System.Assert((0 <= abs) and (abs < PrecompPoints));
-{$ENDIF DEBUG}
-      PointLookup(b, abs, p);
-
-      TX25519Field.CSwap(LSign, p.Ypx_h, p.Ymx_h);
-      TX25519Field.CNegate(LSign, p.Xyd);
-
-      PointAddPrecomp(p, r);
+      InitPointPrecomp(FPrecompBase128Wnaf[LI]);
+      LPointsIndex2 := LWnafPoints + LI;
+      TX25519Field.Mul(LPoints[LPointsIndex2].X, LPoints[LPointsIndex2].Z, LPoints[LPointsIndex2].X);
+      TX25519Field.Mul(LPoints[LPointsIndex2].Y, LPoints[LPointsIndex2].Z, LPoints[LPointsIndex2].Y);
+      TX25519Field.Apm(LPoints[LPointsIndex2].Y, LPoints[LPointsIndex2].X, FPrecompBase128Wnaf[LI].YpxH, FPrecompBase128Wnaf[LI].YmxH);
+      TX25519Field.Mul(LPoints[LPointsIndex2].X, LPoints[LPointsIndex2].Y, FPrecompBase128Wnaf[LI].Xyd);
+      TX25519Field.Mul(FPrecompBase128Wnaf[LI].Xyd, FC_d4, FPrecompBase128Wnaf[LI].Xyd);
+      TX25519Field.Normalize(FPrecompBase128Wnaf[LI].YmxH);
+      TX25519Field.Normalize(FPrecompBase128Wnaf[LI].YpxH);
+      TX25519Field.Normalize(FPrecompBase128Wnaf[LI].Xyd);
     end;
-    cOff := (cOff - PrecompTeeth);
-    if (cOff < 0) then
+    FPrecompBaseComb := TX25519Field.CreateTable(LCombPoints * 3);
+    InitPointPrecomp(LS);
+    LOff := 0;
+    for LI := LWnafPoints * 2 to LTotalPoints - 1 do
     begin
-      break;
+      TX25519Field.Mul(LPoints[LI].X, LPoints[LI].Z, LPoints[LI].X);
+      TX25519Field.Mul(LPoints[LI].Y, LPoints[LI].Z, LPoints[LI].Y);
+      TX25519Field.Apm(LPoints[LI].Y, LPoints[LI].X, LS.YpxH, LS.YmxH);
+      TX25519Field.Mul(LPoints[LI].X, LPoints[LI].Y, LS.Xyd);
+      TX25519Field.Mul(LS.Xyd, FC_d4, LS.Xyd);
+      TX25519Field.Normalize(LS.YmxH);
+      TX25519Field.Normalize(LS.YpxH);
+      TX25519Field.Normalize(LS.Xyd);
+      TX25519Field.Copy(LS.YmxH, 0, FPrecompBaseComb, LOff);
+      LOff := LOff + TX25519Field.Size;
+      TX25519Field.Copy(LS.YpxH, 0, FPrecompBaseComb, LOff);
+      LOff := LOff + TX25519Field.Size;
+      TX25519Field.Copy(LS.Xyd, 0, FPrecompBaseComb, LOff);
+      LOff := LOff + TX25519Field.Size;
     end;
-
-    PointDouble(r);
-  end;
-end;
-
-class procedure TEd25519.ScalarMultBaseYZ(const k: TCryptoLibByteArray;
-  kOff: Int32; const Y, Z: TCryptoLibInt32Array);
-var
-  n: TCryptoLibByteArray;
-  p: TPointAccum;
-begin
-  System.SetLength(n, ScalarBytes);
-  PruneScalar(k, kOff, n);
-
-  p := TPointAccum.CreatePointAccum();
-  ScalarMultBase(n, p);
-  if (CheckPoint(p.X, p.Y, p.Z) = 0) then
-  begin
-    raise EInvalidOperationCryptoLibException.Create('');
-  end;
-  TX25519Field.Copy(p.Y, 0, Y, 0);
-  TX25519Field.Copy(p.Z, 0, Z, 0);
-end;
-
-class procedure TEd25519.ScalarMultStrausVar(const nb,
-  np: TCryptoLibUInt32Array; var p: TPointAffine; var r: TPointAccum);
-var
-  width, bit, wb, wp, LSign, index: Int32;
-  ws_b, ws_p: TCryptoLibShortIntArray;
-  tp: TCryptoLibGenericArray<TPointExt>;
-  temp: TPointExt;
-begin
-  Precompute();
-
-  width := 5;
-
-  ws_b := GetWnaf(nb, WnafWidthBase);
-  ws_p := GetWnaf(np, width);
-
-  temp := PointCopy(p);
-  tp := PointPrecompVar(temp, 1 shl (width - 2));
-
-  PointSetNeutral(r);
-
-  bit := 252;
-
-  while (true) do
-  begin
-    wb := ws_b[bit];
-    if (wb <> 0) then
-    begin
-      LSign := TBitUtilities.Asr32(wb, 31);
-      index := TBitUtilities.Asr32((wb xor LSign), 1);
-
-      PointAddVar((LSign <> 0), FPrecompBaseTable[index], r);
-    end;
-
-    wp := ws_p[bit];
-    if (wp <> 0) then
-    begin
-      LSign := TBitUtilities.Asr32(wp, 31);
-      index := TBitUtilities.Asr32((wp xor LSign), 1);
-
-      PointAddVar((LSign <> 0), tp[index], r);
-    end;
-
-    System.Dec(bit);
-
-    if (bit < 0) then
-    begin
-      break;
-    end;
-
-    PointDouble(r);
+    {$IFDEF DEBUG}
+    System.Assert(LOff = System.Length(FPrecompBaseComb));
+    {$ENDIF}
+  finally
+    FPrecompLock.Leave;
   end;
 end;
 
-class function TEd25519.ValidateDigestOutputSize(const ADigest: IDigest)
-  : TCryptoLibByteArray;
+function TEd25519.GetAlgorithmName: String;
 begin
-  System.SetLength(result, PreHashSize);
-  if (PreHashSize <> ADigest.DoFinal(result, 0)) then
-  begin
-    raise EArgumentCryptoLibException.CreateRes(@SDigestError);
-  end;
+  Result := 'Ed25519';
 end;
 
-class function TEd25519.ConstructCustomByteArrayBufferContext
-  (const AData: TCryptoLibByteArray; AIsNil: Boolean; ALength: Int32)
-  : TCryptoLibCustomByteArrayBuffer;
+class function TEd25519.CreatePreHash(): IDigest;
 begin
-  result := Default (TCryptoLibCustomByteArrayBuffer);
-  result.Data := AData;
-  result.IsNil := AIsNil;
-  result.Length := ALength;
+  Result := CreateDigest();
 end;
 
-procedure TEd25519.Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-  const m: TCryptoLibByteArray; mOff, mLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  phflag: Byte;
+procedure TEd25519.GeneratePrivateKey(const ARandom: ISecureRandom; const AK: TCryptoLibByteArray);
 begin
-  phflag := $00;
-  ImplSign(sk, skOff, EmptyBytesNil, phflag, m, mOff, mLen, sig, sigOff);
+  ARandom.NextBytes(AK);
 end;
 
-procedure TEd25519.Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32; const m: TCryptoLibByteArray;
-  mOff, mLen: Int32; const sig: TCryptoLibByteArray; sigOff: Int32);
+procedure TEd25519.GeneratePublicKey(const &AS: TCryptoLibByteArray; ASOff: Int32; APk: TCryptoLibByteArray; APkOff: Int32);
 var
-  phflag: Byte;
+  LD: IDigest;
+  LH: TCryptoLibByteArray;
+  LS: TCryptoLibByteArray;
 begin
-  phflag := $00;
-  ImplSign(sk, skOff, pk, pkOff, EmptyBytesNil, phflag, m, mOff, mLen,
-    sig, sigOff);
+  LD := CreateDigest();
+  System.SetLength(LH, 64);
+  LD.BlockUpdate(&AS, ASOff, SecretKeySize);
+  LD.DoFinal(LH, 0);
+  System.SetLength(LS, ScalarBytes);
+  PruneScalar(LH, 0, LS);
+  ScalarMultBaseEncoded(LS, APk, APkOff);
 end;
 
-procedure TEd25519.Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-  const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
+procedure TEd25519.Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32);
 var
-  phflag: Byte;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+  LNullCtx: TCryptoLibByteArray;
 begin
-  phflag := $00;
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  ImplSign(sk, skOff, LCtx, phflag, m, mOff, mLen, sig, sigOff);
+  LNullCtx := nil;
+  ImplSign(&AS, ASOff, LNullCtx, Byte($00), AM, AMOff, AMLen, ASig, ASigOff);
 end;
 
-procedure TEd25519.Sign(const sk: TCryptoLibByteArray; skOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
+procedure TEd25519.Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const AM: TCryptoLibByteArray; AMOff, AMLen: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32);
 var
-  phflag: Byte;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+  LNullCtx: TCryptoLibByteArray;
 begin
-  phflag := $00;
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  ImplSign(sk, skOff, pk, pkOff, LCtx, phflag, m, mOff, mLen, sig, sigOff);
+  LNullCtx := nil;
+  ImplSign(&AS, ASOff, APk, APkOff, LNullCtx, Byte($00), AM, AMOff, AMLen, ASig, ASigOff);
 end;
 
-procedure TEd25519.SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-  const ctx, ph: TCryptoLibByteArray; phOff: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  phflag: Byte;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+procedure TEd25519.Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32);
 begin
-  phflag := $01;
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  ImplSign(sk, skOff, LCtx, phflag, ph, phOff, PreHashSize, sig, sigOff);
-end;
-
-procedure TEd25519.SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx, ph: TCryptoLibByteArray; phOff: Int32;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  phflag: Byte;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
-begin
-  phflag := $01;
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  ImplSign(sk, skOff, pk, pkOff, LCtx, phflag, ph, phOff, PreHashSize,
-    sig, sigOff);
+  if not CheckContextVar(ACtx, $00) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  ImplSign(&AS, ASOff, ACtx, $00, AM, AMOff, AMLen, ASig, ASigOff);
 end;
 
-procedure TEd25519.SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-  const ctx: TCryptoLibByteArray; const ph: IDigest;
-  const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  phflag: Byte;
-  m: TCryptoLibByteArray;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+procedure TEd25519.Sign(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32);
 begin
-  phflag := $01;
-  m := ValidateDigestOutputSize(ph);
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  ImplSign(sk, skOff, LCtx, phflag, m, 0, System.Length(m), sig, sigOff);
+  if not CheckContextVar(ACtx, $00) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  ImplSign(&AS, ASOff, APk, APkOff, ACtx, $00, AM, AMOff, AMLen, ASig, ASigOff);
 end;
 
-procedure TEd25519.SignPreHash(const sk: TCryptoLibByteArray; skOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32; const ctx: TCryptoLibByteArray;
-  const ph: IDigest; const sig: TCryptoLibByteArray; sigOff: Int32);
-var
-  phflag: Byte;
-  m: TCryptoLibByteArray;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+procedure TEd25519.SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx, APh: TCryptoLibByteArray; APhOff: Int32;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32);
 begin
-  phflag := $01;
-  m := ValidateDigestOutputSize(ph);
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  ImplSign(sk, skOff, pk, pkOff, LCtx, phflag, m, 0, System.Length(m),
-    sig, sigOff);
+  if not CheckContextVar(ACtx, $01) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  ImplSign(&AS, ASOff, ACtx, $01, APh, APhOff, PrehashSize, ASig, ASigOff);
 end;
 
-function TEd25519.Verify(const sig: TCryptoLibByteArray; sigOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32; const m: TCryptoLibByteArray;
-  mOff, mLen: Int32): Boolean;
-var
-  phflag: Byte;
+procedure TEd25519.SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx, APh: TCryptoLibByteArray; APhOff: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32);
 begin
-  phflag := $00;
-  result := ImplVerify(sig, sigOff, pk, pkOff, EmptyBytesNil, phflag, m,
-    mOff, mLen);
+  if not CheckContextVar(ACtx, $01) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  ImplSign(&AS, ASOff, APk, APkOff, ACtx, $01, APh, APhOff, PrehashSize, ASig, ASigOff);
 end;
 
-function TEd25519.Verify(const sig: TCryptoLibByteArray; sigOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx, m: TCryptoLibByteArray; mOff, mLen: Int32): Boolean;
+procedure TEd25519.SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx: TCryptoLibByteArray; const APh: IDigest;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32);
 var
-  phflag: Byte;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+  LM: TCryptoLibByteArray;
 begin
-  phflag := $00;
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  result := ImplVerify(sig, sigOff, pk, pkOff, LCtx, phflag, m, mOff, mLen);
+  System.SetLength(LM, PrehashSize);
+  if APh.DoFinal(LM, 0) <> PrehashSize then
+    raise EArgumentCryptoLibException.CreateRes(@SDigestSize);
+  SignPreHash(&AS, ASOff, ACtx, LM, 0, ASig, ASigOff);
 end;
 
-function TEd25519.VerifyPreHash(const sig: TCryptoLibByteArray; sigOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32;
-  const ctx, ph: TCryptoLibByteArray; phOff: Int32): Boolean;
+procedure TEd25519.SignPreHash(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx: TCryptoLibByteArray; const APh: IDigest; const ASig: TCryptoLibByteArray; ASigOff: Int32);
 var
-  phflag: Byte;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
+  LM: TCryptoLibByteArray;
 begin
-  phflag := $01;
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  result := ImplVerify(sig, sigOff, pk, pkOff, LCtx, phflag, ph, phOff,
-    PreHashSize);
+  System.SetLength(LM, PrehashSize);
+  if APh.DoFinal(LM, 0) <> PrehashSize then
+    raise EArgumentCryptoLibException.CreateRes(@SDigestSize);
+  SignPreHash(&AS, ASOff, APk, APkOff, ACtx, LM, 0, ASig, ASigOff);
 end;
 
-function TEd25519.VerifyPreHash(const sig: TCryptoLibByteArray; sigOff: Int32;
-  const pk: TCryptoLibByteArray; pkOff: Int32; const ctx: TCryptoLibByteArray;
-  const ph: IDigest): Boolean;
+class procedure TEd25519.ImplSign(const AD: IDigest; AH, &AS, APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32;
+  ASig: TCryptoLibByteArray; ASigOff: Int32);
 var
-  phflag: Byte;
-  m: TCryptoLibByteArray;
-  LCtx: TCryptoLibCustomByteArrayBuffer;
-begin
-  phflag := $01;
-  m := ValidateDigestOutputSize(ph);
-  LCtx := ConstructCustomByteArrayBufferContext(ctx, false, System.Length(ctx));
-  result := ImplVerify(sig, sigOff, pk, pkOff, LCtx, phflag, m, 0,
-    System.Length(m));
+  LR, LK, LS: TCryptoLibByteArray;
+  LRBytes: TCryptoLibByteArray;
+begin
+  if (ACtx <> nil) or (APhflag = $01) then
+    Dom2(AD, APhflag, ACtx);
+  AD.BlockUpdate(AH, ScalarBytes, ScalarBytes);
+  AD.BlockUpdate(AM, AMOff, AMLen);
+  AD.DoFinal(AH, 0);
+  LR := TScalar25519.Reduce512(AH);
+  System.SetLength(LRBytes, PointBytes);
+  ScalarMultBaseEncoded(LR, LRBytes, 0);
+  if (ACtx <> nil) or (APhflag = $01) then
+    Dom2(AD, APhflag, ACtx);
+  AD.BlockUpdate(LRBytes, 0, PointBytes);
+  AD.BlockUpdate(APk, APkOff, PointBytes);
+  AD.BlockUpdate(AM, AMOff, AMLen);
+  AD.DoFinal(AH, 0);
+  LK := TScalar25519.Reduce512(AH);
+  LS := CalculateS(LR, LK, &AS);
+  System.Move(LRBytes[0], ASig[ASigOff], PointBytes);
+  System.Move(LS[0], ASig[ASigOff + PointBytes], ScalarBytes);
+end;
+
+function TEd25519.Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean;
+begin
+  Result := ImplVerify(ASig, ASigOff, APk, APkOff, nil, $00, AM, AMOff, AMLen);
+end;
+
+function TEd25519.Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean;
+begin
+  if not CheckContextVar(ACtx, $00) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  Result := ImplVerify(ASig, ASigOff, APk, APkOff, ACtx, $00, AM, AMOff, AMLen);
 end;
 
-class procedure TEd25519.PointCopy(var p: TPointAffine; var r: TPointAccum);
+function TEd25519.Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+  const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean;
 begin
-  TX25519Field.Copy(p.X, 0, r.X, 0);
-  TX25519Field.Copy(p.Y, 0, r.Y, 0);
-  PointExtendXY(r);
+  Result := ImplVerify(ASig, ASigOff, APublicPoint, nil, $00, AM, AMOff, AMLen);
 end;
 
-class procedure TEd25519.PointCopy(var p, r: TPointExt);
+function TEd25519.Verify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+  const ACtx, AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean;
 begin
-  TX25519Field.Copy(p.X, 0, r.X, 0);
-  TX25519Field.Copy(p.Y, 0, r.Y, 0);
-  TX25519Field.Copy(p.Z, 0, r.Z, 0);
-  TX25519Field.Copy(p.T, 0, r.T, 0);
+  if not CheckContextVar(ACtx, $00) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  Result := ImplVerify(ASig, ASigOff, APublicPoint, ACtx, $00, AM, AMOff, AMLen);
 end;
 
-{ TEd25519.TPointAffine }
-
-function TEd25519.TPointAffine.GetX: TCryptoLibInt32Array;
+function TEd25519.VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx, APh: TCryptoLibByteArray; APhOff: Int32): Boolean;
 begin
-  result := Fx;
+  if not CheckContextVar(ACtx, $01) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  Result := ImplVerify(ASig, ASigOff, APk, APkOff, ACtx, $01, APh, APhOff, PrehashSize);
 end;
 
-function TEd25519.TPointAffine.GetY: TCryptoLibInt32Array;
+function TEd25519.VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx: TCryptoLibByteArray; const APh: IDigest): Boolean;
+var
+  LM: TCryptoLibByteArray;
 begin
-  result := Fy;
+  System.SetLength(LM, PrehashSize);
+  if APh.DoFinal(LM, 0) <> PrehashSize then
+    raise EArgumentCryptoLibException.CreateRes(@SDigestSize);
+  Result := VerifyPreHash(ASig, ASigOff, APk, APkOff, ACtx, LM, 0);
 end;
 
-procedure TEd25519.TPointAffine.SetX(const value: TCryptoLibInt32Array);
+function TEd25519.VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+  const ACtx, APh: TCryptoLibByteArray; APhOff: Int32): Boolean;
 begin
-  Fx := value;
+  if not CheckContextVar(ACtx, $01) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  Result := ImplVerify(ASig, ASigOff, APublicPoint, ACtx, $01, APh, APhOff, PrehashSize);
 end;
 
-procedure TEd25519.TPointAffine.SetY(const value: TCryptoLibInt32Array);
+function TEd25519.VerifyPreHash(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+  const ACtx: TCryptoLibByteArray; const APh: IDigest): Boolean;
+var
+  LM: TCryptoLibByteArray;
 begin
-  Fy := value;
+  System.SetLength(LM, PrehashSize);
+  if APh.DoFinal(LM, 0) <> PrehashSize then
+    raise EArgumentCryptoLibException.CreateRes(@SDigestSize);
+  Result := VerifyPreHash(ASig, ASigOff, APublicPoint, ACtx, LM, 0);
 end;
 
-class function TEd25519.TPointAffine.CreatePointAffine: TPointAffine;
-begin
-  result := Default (TPointAffine);
-  result.Fx := TX25519Field.Create();
-  result.Fy := TX25519Field.Create();
+class function TEd25519.ImplVerify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APublicPoint: IPublicPoint;
+  const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean;
+var
+  LR, LS, LA: TCryptoLibByteArray;
+  LNS: TCryptoLibUInt32Array;
+  LNA: TCryptoLibUInt32Array;
+  LV0, LV1: TCryptoLibUInt32Array;
+  LPR, LPA: TPointAffine;
+  LPZ: TPointAccum;
+  LD: IDigest;
+  LH: TCryptoLibByteArray;
+  LK: TCryptoLibByteArray;
+  LData: TCryptoLibInt32Array;
+begin
+  if not CheckContextVar(ACtx, APhflag) then
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidCtx);
+  CopyBytes(ASig, ASigOff, PointBytes, LR);
+  CopyBytes(ASig, ASigOff + PointBytes, ScalarBytes, LS);
+  System.SetLength(LA, PublicKeySize);
+  EncodePublicPoint(APublicPoint, LA, 0);
+  if not CheckPointVar(LR) then
+  begin
+    Exit(False);
+  end;
+  System.SetLength(LNS, ScalarUints);
+  if not TScalar25519.CheckVar(LS, LNS) then
+  begin
+    Exit(False);
+  end;
+  InitPointAffine(LPR);
+  if not DecodePointVar(LR, True, LPR) then
+  begin
+    Exit(False);
+  end;
+  InitPointAffine(LPA);
+  LData := APublicPoint.Data;
+  TX25519Field.Negate(LData, LPA.X);
+  TX25519Field.Copy(LData, TX25519Field.Size, LPA.Y, 0);
+  LD := CreateDigest();
+  System.SetLength(LH, 64);
+  if (ACtx <> nil) or (APhflag = $01) then
+    Dom2(LD, APhflag, ACtx);
+  LD.BlockUpdate(LR, 0, PointBytes);
+  LD.BlockUpdate(LA, 0, PointBytes);
+  LD.BlockUpdate(AM, AMOff, AMLen);
+  LD.DoFinal(LH, 0);
+  LK := TScalar25519.Reduce512(LH);
+  System.SetLength(LNA, ScalarUints);
+  TScalar25519.Decode(LK, LNA);
+  System.SetLength(LV0, 4);
+  System.SetLength(LV1, 4);
+  if not TScalar25519.ReduceBasisVar(LNA, LV0, LV1) then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidOp);
+  TScalar25519.Multiply128Var(LNS, LV1, LNS);
+  InitPointAccum(LPZ);
+  ScalarMultStraus128Var(LNS, LV0, LPA, LV1, LPR, LPZ);
+  Result := NormalizeToNeutralElementVar(LPZ);
+end;
+
+class function TEd25519.ImplVerify(const ASig: TCryptoLibByteArray; ASigOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff, AMLen: Int32): Boolean;
+var
+  LR, LS, LA: TCryptoLibByteArray;
+  LNS: TCryptoLibUInt32Array;
+  LNA: TCryptoLibUInt32Array;
+  LV0, LV1: TCryptoLibUInt32Array;
+  LPR, LPA: TPointAffine;
+  LPZ: TPointAccum;
+  LD: IDigest;
+  LH: TCryptoLibByteArray;
+  LK: TCryptoLibByteArray;
+begin
+  CopyBytes(ASig, ASigOff, PointBytes, LR);
+  CopyBytes(ASig, ASigOff + PointBytes, ScalarBytes, LS);
+  CopyBytes(APk, APkOff, PublicKeySize, LA);
+  if not CheckPointVar(LR) then
+  begin
+    Exit(False);
+  end;
+  System.SetLength(LNS, ScalarUints);
+  if not TScalar25519.CheckVar(LS, LNS) then
+  begin
+    Exit(False);
+  end;
+  if not CheckPointFullVar(LA) then
+  begin
+    Exit(False);
+  end;
+  InitPointAffine(LPR);
+  if not DecodePointVar(LR, True, LPR) then
+  begin
+    Exit(False);
+  end;
+  InitPointAffine(LPA);
+  if not DecodePointVar(LA, True, LPA) then
+  begin
+    Exit(False);
+  end;
+  LD := CreateDigest();
+  System.SetLength(LH, 64);
+  if (ACtx <> nil) or (APhflag = $01) then
+    Dom2(LD, APhflag, ACtx);
+  LD.BlockUpdate(LR, 0, PointBytes);
+  LD.BlockUpdate(LA, 0, PointBytes);
+  LD.BlockUpdate(AM, AMOff, AMLen);
+  LD.DoFinal(LH, 0);
+  LK := TScalar25519.Reduce512(LH);
+  System.SetLength(LNA, ScalarUints);
+  TScalar25519.Decode(LK, LNA);
+  System.SetLength(LV0, 4);
+  System.SetLength(LV1, 4);
+  if not TScalar25519.ReduceBasisVar(LNA, LV0, LV1) then
+    raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidOp);
+  TScalar25519.Multiply128Var(LNS, LV1, LNS);
+  InitPointAccum(LPZ);
+  ScalarMultStraus128Var(LNS, LV0, LPA, LV1, LPR, LPZ);
+  Result := NormalizeToNeutralElementVar(LPZ);
+end;
+
+class procedure TEd25519.ImplSign(const &AS: TCryptoLibByteArray; ASOff: Int32; const ACtx: TCryptoLibByteArray; APhflag: Byte;
+  const AM: TCryptoLibByteArray; AMOff: Int32; AMLen: Int32; const ASig: TCryptoLibByteArray; ASigOff: Int32);
+var
+  LD: IDigest;
+  LH, LS, LPk: TCryptoLibByteArray;
+begin
+  LD := CreateDigest();
+  System.SetLength(LH, 64);
+  LD.BlockUpdate(&AS, ASOff, SecretKeySize);
+  LD.DoFinal(LH, 0);
+  System.SetLength(LS, ScalarBytes);
+  PruneScalar(LH, 0, LS);
+  System.SetLength(LPk, PointBytes);
+  ScalarMultBaseEncoded(LS, LPk, 0);
+  ImplSign(LD, LH, LS, LPk, 0, ACtx, APhflag, AM, AMOff, AMLen, ASig, ASigOff);
+end;
+
+class procedure TEd25519.ImplSign(const &AS: TCryptoLibByteArray; ASOff: Int32; const APk: TCryptoLibByteArray; APkOff: Int32;
+  const ACtx: TCryptoLibByteArray; APhflag: Byte; const AM: TCryptoLibByteArray; AMOff: Int32; AMLen: Int32;
+  const ASig: TCryptoLibByteArray; ASigOff: Int32);
+var
+  LD: IDigest;
+  LH, LS: TCryptoLibByteArray;
+begin
+  LD := CreateDigest();
+  System.SetLength(LH, 64);
+  LD.BlockUpdate(&AS, ASOff, SecretKeySize);
+  LD.DoFinal(LH, 0);
+  System.SetLength(LS, ScalarBytes);
+  PruneScalar(LH, 0, LS);
+  ImplSign(LD, LH, LS, APk, APkOff, ACtx, APhflag, AM, AMOff, AMLen, ASig, ASigOff);
 end;
 
 end.

+ 453 - 0
CryptoLib/src/Math/EC/Rfc8032/ClpScalar25519.pas

@@ -0,0 +1,453 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpScalar25519;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBitUtilities,
+  ClpCodec,
+  ClpWnaf,
+  ClpNat256,
+  ClpNat,
+  ClpScalarUtilities,
+  ClpCryptoLibTypes;
+
+type
+  TScalar25519 = class sealed
+  strict private
+  const
+    Size = 8;
+    ScalarBytes = Size * 4;
+    M28L = $0FFFFFFF;
+    TargetLength = 254;
+    L0 = -$030A2C13;
+    L1 = $012631A6;
+    L2 = $079CD658;
+    L3 = -$006215D1;
+    L4 = $000014DF;
+  class var
+    FL, FLsq: TCryptoLibUInt32Array;
+  class procedure Boot; static;
+  class constructor Create;
+  public
+    class function CheckVar(const &AS: TCryptoLibByteArray; AN: TCryptoLibUInt32Array): Boolean; static;
+    class procedure Decode(const AK: TCryptoLibByteArray; AN: TCryptoLibUInt32Array); static;
+    class procedure GetOrderWnafVar(AWidth: Int32; const AWs: TCryptoLibShortIntArray); static;
+    class procedure Multiply128Var(const AX: TCryptoLibUInt32Array; const AY128: TCryptoLibUInt32Array;
+      AZ: TCryptoLibUInt32Array); static;
+    class function Reduce384(const AN: TCryptoLibByteArray): TCryptoLibByteArray; overload; static;
+    class procedure Reduce384(const AN: TCryptoLibByteArray; const AR: TCryptoLibByteArray); overload; static;
+    class function Reduce512(const AN: TCryptoLibByteArray): TCryptoLibByteArray; overload; static;
+    class procedure Reduce512(const AN: TCryptoLibByteArray; const AR: TCryptoLibByteArray); overload; static;
+    class function ReduceBasisVar(const AK: TCryptoLibUInt32Array; AZ0: TCryptoLibUInt32Array;
+      AZ1: TCryptoLibUInt32Array): Boolean; static;
+    class procedure ToSignedDigits(ABits: Int32; AZ: TCryptoLibUInt32Array); static;
+  end;
+
+implementation
+
+class constructor TScalar25519.Create;
+begin
+  Boot;
+end;
+
+class procedure TScalar25519.Boot;
+begin
+  FL := TCryptoLibUInt32Array.Create($5CF5D3ED, $5812631A, $A2F79CD6, $14DEF9DE,
+    $00000000, $00000000, $00000000, $10000000);
+  FLsq := TCryptoLibUInt32Array.Create($AB128969, $E2EDF685, $2298A31D, $68039276,
+    $D217F5BE, $3DCEEC73, $1B7C309A, $A1B39941, $4B9EBA7D, $CB024C63, $D45EF39A,
+    $029BDF3B, $00000000, $00000000, $00000000, $01000000);
+end;
+
+class function TScalar25519.CheckVar(const &AS: TCryptoLibByteArray; AN: TCryptoLibUInt32Array): Boolean;
+begin
+  Decode(&AS, AN);
+  Result := not TNat256.Gte(AN, FL);
+end;
+
+class procedure TScalar25519.Decode(const AK: TCryptoLibByteArray; AN: TCryptoLibUInt32Array);
+begin
+  TCodec.Decode32(AK, 0, AN, 0, Size);
+end;
+
+class procedure TScalar25519.GetOrderWnafVar(AWidth: Int32; const AWs: TCryptoLibShortIntArray);
+begin
+  TWnaf.GetSignedVar(FL, AWidth, AWs);
+end;
+
+class procedure TScalar25519.Multiply128Var(const AX: TCryptoLibUInt32Array; const AY128: TCryptoLibUInt32Array;
+  AZ: TCryptoLibUInt32Array);
+var
+  LTt: TCryptoLibUInt32Array;
+  LBytes: TCryptoLibByteArray;
+  LR: TCryptoLibByteArray;
+begin
+  System.SetLength(LTt, 12);
+  TNat256.Mul128(AX, AY128, LTt);
+  if Int32(AY128[3]) < 0 then
+  begin
+    TNat256.AddTo(FL, 0, LTt, 4, 0);
+    TNat256.SubFrom(AX, 0, LTt, 4, 0);
+  end;
+  System.SetLength(LBytes, 48);
+  TCodec.Encode32(LTt, 0, 12, LBytes, 0);
+  LR := Reduce384(LBytes);
+  TCodec.Decode32(LR, 0, AZ, 0, Size);
+end;
+
+class function TScalar25519.Reduce384(const AN: TCryptoLibByteArray): TCryptoLibByteArray;
+begin
+  System.SetLength(Result, ScalarBytes);
+  Reduce384(AN, Result);
+end;
+
+class procedure TScalar25519.Reduce384(const AN: TCryptoLibByteArray; const AR: TCryptoLibByteArray);
+var
+  Lx00, Lx01, Lx02, Lx03, Lx04, Lx05, Lx06, Lx07, Lx08, Lx09, Lx10, Lx11, Lx12, Lx13, Lt: Int64;
+begin
+  Lx00 := Int64(TCodec.Decode32(AN, 0));
+  Lx01 := Int64(TCodec.Decode24(AN, 4)) shl 4;
+  Lx02 := Int64(TCodec.Decode32(AN, 7));
+  Lx03 := Int64(TCodec.Decode24(AN, 11)) shl 4;
+  Lx04 := Int64(TCodec.Decode32(AN, 14));
+  Lx05 := Int64(TCodec.Decode24(AN, 18)) shl 4;
+  Lx06 := Int64(TCodec.Decode32(AN, 21));
+  Lx07 := Int64(TCodec.Decode24(AN, 25)) shl 4;
+  Lx08 := Int64(TCodec.Decode32(AN, 28));
+  Lx09 := Int64(TCodec.Decode24(AN, 32)) shl 4;
+  Lx10 := Int64(TCodec.Decode32(AN, 35));
+  Lx11 := Int64(TCodec.Decode24(AN, 39)) shl 4;
+  Lx12 := Int64(TCodec.Decode32(AN, 42));
+  Lx13 := Int64(TCodec.Decode16(AN, 46)) shl 4;
+  Lx13 := Lx13 + TBitUtilities.Asr64(Lx12, 28);
+  Lx12 := Lx12 and M28L;
+  Lx04 := Lx04 - Lx13 * L0;
+  Lx05 := Lx05 - Lx13 * L1;
+  Lx06 := Lx06 - Lx13 * L2;
+  Lx07 := Lx07 - Lx13 * L3;
+  Lx08 := Lx08 - Lx13 * L4;
+  Lx12 := Lx12 + TBitUtilities.Asr64(Lx11, 28);
+  Lx11 := Lx11 and M28L;
+  Lx03 := Lx03 - Lx12 * L0;
+  Lx04 := Lx04 - Lx12 * L1;
+  Lx05 := Lx05 - Lx12 * L2;
+  Lx06 := Lx06 - Lx12 * L3;
+  Lx07 := Lx07 - Lx12 * L4;
+  Lx11 := Lx11 + TBitUtilities.Asr64(Lx10, 28);
+  Lx10 := Lx10 and M28L;
+  Lx02 := Lx02 - Lx11 * L0;
+  Lx03 := Lx03 - Lx11 * L1;
+  Lx04 := Lx04 - Lx11 * L2;
+  Lx05 := Lx05 - Lx11 * L3;
+  Lx06 := Lx06 - Lx11 * L4;
+  Lx10 := Lx10 + TBitUtilities.Asr64(Lx09, 28);
+  Lx09 := Lx09 and M28L;
+  Lx01 := Lx01 - Lx10 * L0;
+  Lx02 := Lx02 - Lx10 * L1;
+  Lx03 := Lx03 - Lx10 * L2;
+  Lx04 := Lx04 - Lx10 * L3;
+  Lx05 := Lx05 - Lx10 * L4;
+  Lx08 := Lx08 + TBitUtilities.Asr64(Lx07, 28);
+  Lx07 := Lx07 and M28L;
+  Lx09 := Lx09 + TBitUtilities.Asr64(Lx08, 28);
+  Lx08 := Lx08 and M28L;
+  Lt := TBitUtilities.Asr64(Lx08, 27) and 1;
+  Lx09 := Lx09 + Lt;
+  Lx00 := Lx00 - Lx09 * L0;
+  Lx01 := Lx01 - Lx09 * L1;
+  Lx02 := Lx02 - Lx09 * L2;
+  Lx03 := Lx03 - Lx09 * L3;
+  Lx04 := Lx04 - Lx09 * L4;
+  Lx01 := Lx01 + TBitUtilities.Asr64(Lx00, 28);
+  Lx00 := Lx00 and M28L;
+  Lx02 := Lx02 + TBitUtilities.Asr64(Lx01, 28);
+  Lx01 := Lx01 and M28L;
+  Lx03 := Lx03 + TBitUtilities.Asr64(Lx02, 28);
+  Lx02 := Lx02 and M28L;
+  Lx04 := Lx04 + TBitUtilities.Asr64(Lx03, 28);
+  Lx03 := Lx03 and M28L;
+  Lx05 := Lx05 + TBitUtilities.Asr64(Lx04, 28);
+  Lx04 := Lx04 and M28L;
+  Lx06 := Lx06 + TBitUtilities.Asr64(Lx05, 28);
+  Lx05 := Lx05 and M28L;
+  Lx07 := Lx07 + TBitUtilities.Asr64(Lx06, 28);
+  Lx06 := Lx06 and M28L;
+  Lx08 := Lx08 + TBitUtilities.Asr64(Lx07, 28);
+  Lx07 := Lx07 and M28L;
+  Lx09 := TBitUtilities.Asr64(Lx08, 28);
+  Lx08 := Lx08 and M28L;
+  Lx09 := Lx09 - Lt;
+  {$IFDEF DEBUG}
+  System.Assert((Lx09 = 0) or (Lx09 = -1));
+  {$ENDIF}
+  Lx00 := Lx00 + (Lx09 and Int64(L0));
+  Lx01 := Lx01 + (Lx09 and Int64(L1));
+  Lx02 := Lx02 + (Lx09 and Int64(L2));
+  Lx03 := Lx03 + (Lx09 and Int64(L3));
+  Lx04 := Lx04 + (Lx09 and Int64(L4));
+  Lx01 := Lx01 + TBitUtilities.Asr64(Lx00, 28);
+  Lx00 := Lx00 and M28L;
+  Lx02 := Lx02 + TBitUtilities.Asr64(Lx01, 28);
+  Lx01 := Lx01 and M28L;
+  Lx03 := Lx03 + TBitUtilities.Asr64(Lx02, 28);
+  Lx02 := Lx02 and M28L;
+  Lx04 := Lx04 + TBitUtilities.Asr64(Lx03, 28);
+  Lx03 := Lx03 and M28L;
+  Lx05 := Lx05 + TBitUtilities.Asr64(Lx04, 28);
+  Lx04 := Lx04 and M28L;
+  Lx06 := Lx06 + TBitUtilities.Asr64(Lx05, 28);
+  Lx05 := Lx05 and M28L;
+  Lx07 := Lx07 + TBitUtilities.Asr64(Lx06, 28);
+  Lx06 := Lx06 and M28L;
+  Lx08 := Lx08 + TBitUtilities.Asr64(Lx07, 28);
+  Lx07 := Lx07 and M28L;
+  TCodec.Encode56(UInt64(Lx00 or (Lx01 shl 28)), AR, 0);
+  TCodec.Encode56(UInt64(Lx02 or (Lx03 shl 28)), AR, 7);
+  TCodec.Encode56(UInt64(Lx04 or (Lx05 shl 28)), AR, 14);
+  TCodec.Encode56(UInt64(Lx06 or (Lx07 shl 28)), AR, 21);
+  TCodec.Encode32(UInt32(Lx08), AR, 28);
+end;
+
+class function TScalar25519.Reduce512(const AN: TCryptoLibByteArray): TCryptoLibByteArray;
+begin
+  System.SetLength(Result, ScalarBytes);
+  Reduce512(AN, Result);
+end;
+
+class procedure TScalar25519.Reduce512(const AN: TCryptoLibByteArray; const AR: TCryptoLibByteArray);
+var
+  Lx00, Lx01, Lx02, Lx03, Lx04, Lx05, Lx06, Lx07, Lx08, Lx09, Lx10, Lx11, Lx12, Lx13, Lx14, Lx15, Lx16, Lx17, Lx18, Lt: Int64;
+begin
+  Lx00 := Int64(TCodec.Decode32(AN, 0));
+  Lx01 := Int64(TCodec.Decode24(AN, 4)) shl 4;
+  Lx02 := Int64(TCodec.Decode32(AN, 7));
+  Lx03 := Int64(TCodec.Decode24(AN, 11)) shl 4;
+  Lx04 := Int64(TCodec.Decode32(AN, 14));
+  Lx05 := Int64(TCodec.Decode24(AN, 18)) shl 4;
+  Lx06 := Int64(TCodec.Decode32(AN, 21));
+  Lx07 := Int64(TCodec.Decode24(AN, 25)) shl 4;
+  Lx08 := Int64(TCodec.Decode32(AN, 28));
+  Lx09 := Int64(TCodec.Decode24(AN, 32)) shl 4;
+  Lx10 := Int64(TCodec.Decode32(AN, 35));
+  Lx11 := Int64(TCodec.Decode24(AN, 39)) shl 4;
+  Lx12 := Int64(TCodec.Decode32(AN, 42));
+  Lx13 := Int64(TCodec.Decode24(AN, 46)) shl 4;
+  Lx14 := Int64(TCodec.Decode32(AN, 49));
+  Lx15 := Int64(TCodec.Decode24(AN, 53)) shl 4;
+  Lx16 := Int64(TCodec.Decode32(AN, 56));
+  Lx17 := Int64(TCodec.Decode24(AN, 60)) shl 4;
+  Lx18 := Int64(AN[63]);
+  Lx09 := Lx09 - Lx18 * L0;
+  Lx10 := Lx10 - Lx18 * L1;
+  Lx11 := Lx11 - Lx18 * L2;
+  Lx12 := Lx12 - Lx18 * L3;
+  Lx13 := Lx13 - Lx18 * L4;
+  Lx17 := Lx17 + TBitUtilities.Asr64(Lx16, 28);
+  Lx16 := Lx16 and M28L;
+  Lx08 := Lx08 - Lx17 * L0;
+  Lx09 := Lx09 - Lx17 * L1;
+  Lx10 := Lx10 - Lx17 * L2;
+  Lx11 := Lx11 - Lx17 * L3;
+  Lx12 := Lx12 - Lx17 * L4;
+  Lx07 := Lx07 - Lx16 * L0;
+  Lx08 := Lx08 - Lx16 * L1;
+  Lx09 := Lx09 - Lx16 * L2;
+  Lx10 := Lx10 - Lx16 * L3;
+  Lx11 := Lx11 - Lx16 * L4;
+  Lx15 := Lx15 + TBitUtilities.Asr64(Lx14, 28);
+  Lx14 := Lx14 and M28L;
+  Lx06 := Lx06 - Lx15 * L0;
+  Lx07 := Lx07 - Lx15 * L1;
+  Lx08 := Lx08 - Lx15 * L2;
+  Lx09 := Lx09 - Lx15 * L3;
+  Lx10 := Lx10 - Lx15 * L4;
+  Lx05 := Lx05 - Lx14 * L0;
+  Lx06 := Lx06 - Lx14 * L1;
+  Lx07 := Lx07 - Lx14 * L2;
+  Lx08 := Lx08 - Lx14 * L3;
+  Lx09 := Lx09 - Lx14 * L4;
+  Lx13 := Lx13 + TBitUtilities.Asr64(Lx12, 28);
+  Lx12 := Lx12 and M28L;
+  Lx04 := Lx04 - Lx13 * L0;
+  Lx05 := Lx05 - Lx13 * L1;
+  Lx06 := Lx06 - Lx13 * L2;
+  Lx07 := Lx07 - Lx13 * L3;
+  Lx08 := Lx08 - Lx13 * L4;
+  Lx12 := Lx12 + TBitUtilities.Asr64(Lx11, 28);
+  Lx11 := Lx11 and M28L;
+  Lx03 := Lx03 - Lx12 * L0;
+  Lx04 := Lx04 - Lx12 * L1;
+  Lx05 := Lx05 - Lx12 * L2;
+  Lx06 := Lx06 - Lx12 * L3;
+  Lx07 := Lx07 - Lx12 * L4;
+  Lx11 := Lx11 + TBitUtilities.Asr64(Lx10, 28);
+  Lx10 := Lx10 and M28L;
+  Lx02 := Lx02 - Lx11 * L0;
+  Lx03 := Lx03 - Lx11 * L1;
+  Lx04 := Lx04 - Lx11 * L2;
+  Lx05 := Lx05 - Lx11 * L3;
+  Lx06 := Lx06 - Lx11 * L4;
+  Lx10 := Lx10 + TBitUtilities.Asr64(Lx09, 28);
+  Lx09 := Lx09 and M28L;
+  Lx01 := Lx01 - Lx10 * L0;
+  Lx02 := Lx02 - Lx10 * L1;
+  Lx03 := Lx03 - Lx10 * L2;
+  Lx04 := Lx04 - Lx10 * L3;
+  Lx05 := Lx05 - Lx10 * L4;
+  Lx08 := Lx08 + TBitUtilities.Asr64(Lx07, 28);
+  Lx07 := Lx07 and M28L;
+  Lx09 := Lx09 + TBitUtilities.Asr64(Lx08, 28);
+  Lx08 := Lx08 and M28L;
+  Lt := TBitUtilities.Asr64(Lx08, 27) and 1;
+  Lx09 := Lx09 + Lt;
+  Lx00 := Lx00 - Lx09 * L0;
+  Lx01 := Lx01 - Lx09 * L1;
+  Lx02 := Lx02 - Lx09 * L2;
+  Lx03 := Lx03 - Lx09 * L3;
+  Lx04 := Lx04 - Lx09 * L4;
+  Lx01 := Lx01 + TBitUtilities.Asr64(Lx00, 28);
+  Lx00 := Lx00 and M28L;
+  Lx02 := Lx02 + TBitUtilities.Asr64(Lx01, 28);
+  Lx01 := Lx01 and M28L;
+  Lx03 := Lx03 + TBitUtilities.Asr64(Lx02, 28);
+  Lx02 := Lx02 and M28L;
+  Lx04 := Lx04 + TBitUtilities.Asr64(Lx03, 28);
+  Lx03 := Lx03 and M28L;
+  Lx05 := Lx05 + TBitUtilities.Asr64(Lx04, 28);
+  Lx04 := Lx04 and M28L;
+  Lx06 := Lx06 + TBitUtilities.Asr64(Lx05, 28);
+  Lx05 := Lx05 and M28L;
+  Lx07 := Lx07 + TBitUtilities.Asr64(Lx06, 28);
+  Lx06 := Lx06 and M28L;
+  Lx08 := Lx08 + TBitUtilities.Asr64(Lx07, 28);
+  Lx07 := Lx07 and M28L;
+  Lx09 := TBitUtilities.Asr64(Lx08, 28);
+  Lx08 := Lx08 and M28L;
+  Lx09 := Lx09 - Lt;
+  {$IFDEF DEBUG}
+  System.Assert((Lx09 = 0) or (Lx09 = -1));
+  {$ENDIF}
+  Lx00 := Lx00 + (Lx09 and Int64(L0));
+  Lx01 := Lx01 + (Lx09 and Int64(L1));
+  Lx02 := Lx02 + (Lx09 and Int64(L2));
+  Lx03 := Lx03 + (Lx09 and Int64(L3));
+  Lx04 := Lx04 + (Lx09 and Int64(L4));
+  Lx01 := Lx01 + TBitUtilities.Asr64(Lx00, 28);
+  Lx00 := Lx00 and M28L;
+  Lx02 := Lx02 + TBitUtilities.Asr64(Lx01, 28);
+  Lx01 := Lx01 and M28L;
+  Lx03 := Lx03 + TBitUtilities.Asr64(Lx02, 28);
+  Lx02 := Lx02 and M28L;
+  Lx04 := Lx04 + TBitUtilities.Asr64(Lx03, 28);
+  Lx03 := Lx03 and M28L;
+  Lx05 := Lx05 + TBitUtilities.Asr64(Lx04, 28);
+  Lx04 := Lx04 and M28L;
+  Lx06 := Lx06 + TBitUtilities.Asr64(Lx05, 28);
+  Lx05 := Lx05 and M28L;
+  Lx07 := Lx07 + TBitUtilities.Asr64(Lx06, 28);
+  Lx06 := Lx06 and M28L;
+  Lx08 := Lx08 + TBitUtilities.Asr64(Lx07, 28);
+  Lx07 := Lx07 and M28L;
+  TCodec.Encode56(UInt64(Lx00 or (Lx01 shl 28)), AR, 0);
+  TCodec.Encode56(UInt64(Lx02 or (Lx03 shl 28)), AR, 7);
+  TCodec.Encode56(UInt64(Lx04 or (Lx05 shl 28)), AR, 14);
+  TCodec.Encode56(UInt64(Lx06 or (Lx07 shl 28)), AR, 21);
+  TCodec.Encode32(UInt32(Lx08), AR, 28);
+end;
+
+class function TScalar25519.ReduceBasisVar(const AK: TCryptoLibUInt32Array; AZ0: TCryptoLibUInt32Array;
+  AZ1: TCryptoLibUInt32Array): Boolean;
+var
+  LNu, LNv, Lp, Lt: TCryptoLibUInt32Array;
+  Lu0, Lu1, Lv0, Lv1: TCryptoLibUInt32Array;
+  LIterations, LLast, LLenNv, LLenP, LS: Int32;
+begin
+  System.SetLength(LNu, 16);
+  System.SetLength(LNv, 16);
+  System.SetLength(Lp, 16);
+  System.SetLength(Lt, 16);
+  System.SetLength(Lu0, 4);
+  System.SetLength(Lu1, 4);
+  System.SetLength(Lv0, 4);
+  System.SetLength(Lv1, 4);
+  System.Move(FLsq[0], LNu[0], 16 * System.SizeOf(UInt32));
+  TNat256.Square(AK, LNv);
+  LNv[0] := LNv[0] + 1;
+  TNat256.Mul(FL, AK, Lp);
+  System.Move(FL[0], Lu0[0], 4 * System.SizeOf(UInt32));
+  Lv0[0] := AK[0];
+  Lv0[1] := AK[1];
+  Lv0[2] := AK[2];
+  Lv0[3] := AK[3];
+  Lv1[0] := 1;
+  LIterations := TargetLength * 4;
+  LLast := 15;
+  LLenNv := TScalarUtilities.GetBitLengthPositive(LLast, LNv);
+  while LLenNv > TargetLength do
+  begin
+    System.Dec(LIterations);
+    if LIterations < 0 then
+      Exit(False);
+    LLenP := TScalarUtilities.GetBitLength(LLast, Lp);
+    LS := LLenP - LLenNv;
+    LS := LS and (not TBitUtilities.Asr32(LS, 31));
+    if Int32(Lp[LLast]) < 0 then
+    begin
+      TScalarUtilities.AddShifted_NP(LLast, LS, LNu, LNv, Lp, Lt);
+      TScalarUtilities.AddShifted_UV(3, LS, Lu0, Lu1, Lv0, Lv1);
+    end
+    else
+    begin
+      TScalarUtilities.SubShifted_NP(LLast, LS, LNu, LNv, Lp, Lt);
+      TScalarUtilities.SubShifted_UV(3, LS, Lu0, Lu1, Lv0, Lv1);
+    end;
+    if TScalarUtilities.LessThan(LLast, LNu, LNv) then
+    begin
+      TScalarUtilities.Swap(Lu0, Lv0);
+      TScalarUtilities.Swap(Lu1, Lv1);
+      TScalarUtilities.Swap(LNu, LNv);
+      LLast := TBitUtilities.Asr32(LLenNv, 5);
+      LLenNv := TScalarUtilities.GetBitLengthPositive(LLast, LNv);
+    end;
+  end;
+  System.Move(Lv0[0], AZ0[0], 4 * System.SizeOf(UInt32));
+  System.Move(Lv1[0], AZ1[0], 4 * System.SizeOf(UInt32));
+  Result := True;
+end;
+
+class procedure TScalar25519.ToSignedDigits(ABits: Int32; AZ: TCryptoLibUInt32Array);
+var
+  LC1, LC2: UInt32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert(ABits = 256);
+  System.Assert(System.Length(AZ) >= Size);
+  {$ENDIF}
+  LC1 := TNat.CAddTo(Size, (not Int32(AZ[0])) and 1, FL, AZ);
+  LC2 := TNat.ShiftDownBit(Size, AZ, 1);
+  {$IFDEF DEBUG}
+  System.Assert(LC1 = 0);
+  System.Assert(LC2 = UInt32(1 shl 31));
+  {$ENDIF}
+end;
+
+end.

+ 426 - 0
CryptoLib/src/Math/EC/Rfc8032/ClpScalarUtilities.pas

@@ -0,0 +1,426 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpScalarUtilities;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBitUtilities,
+  ClpCryptoLibTypes;
+
+type
+  TScalarUtilities = class sealed
+  public
+    class procedure AddShifted_NP(ALast: Int32; AShift: Int32; const ANu, ANv, AP, AT: TCryptoLibUInt32Array); static;
+    class procedure AddShifted_UV(ALast: Int32; AShift: Int32; const AU0, AU1, AV0, AV1: TCryptoLibUInt32Array); static;
+    class function GetBitLength(ALast: Int32; const AX: TCryptoLibUInt32Array): Int32; static;
+    class function GetBitLengthPositive(ALast: Int32; const AX: TCryptoLibUInt32Array): Int32; static;
+    class function LessThan(ALast: Int32; const AX, AY: TCryptoLibUInt32Array): Boolean; static;
+    class procedure SubShifted_NP(ALast: Int32; AShift: Int32; const ANu, ANv, AP, AT: TCryptoLibUInt32Array); static;
+    class procedure SubShifted_UV(ALast: Int32; AShift: Int32; const AU0, AU1, AV0, AV1: TCryptoLibUInt32Array); static;
+    class procedure Swap(var AX: TCryptoLibUInt32Array; var AY: TCryptoLibUInt32Array); static;
+  end;
+
+implementation
+
+{ TScalarUtilities }
+
+class procedure TScalarUtilities.AddShifted_NP(ALast: Int32; AShift: Int32; const ANu, ANv, AP, AT: TCryptoLibUInt32Array);
+var
+  Lcc_p, Lcc_Nu: UInt64;
+  LI, LsWords, LsBits: Int32;
+  Lp_i, Lp_s, Lnext_v, Lv_s, Lq_s: UInt32;
+  Lprev_p, Lprev_q, Lprev_v, Lprev_t, Lnext_t, Lt_s, Lnext_q: UInt32;
+begin
+  Lcc_p := 0;
+  Lcc_Nu := 0;
+
+  if AShift = 0 then
+  begin
+    LI := 0;
+    while LI <= ALast do
+    begin
+      Lp_i := AP[LI];
+      Lcc_Nu := Lcc_Nu + ANu[LI];
+      Lcc_Nu := Lcc_Nu + Lp_i;
+      Lcc_p := Lcc_p + Lp_i;
+      Lcc_p := Lcc_p + ANv[LI];
+      Lp_i := UInt32(Lcc_p);
+      Lcc_p := Lcc_p shr 32;
+      AP[LI] := Lp_i;
+      Lcc_Nu := Lcc_Nu + Lp_i;
+      ANu[LI] := UInt32(Lcc_Nu);
+      Lcc_Nu := Lcc_Nu shr 32;
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  if AShift < 32 then
+  begin
+    Lprev_p := 0;
+    Lprev_q := 0;
+    Lprev_v := 0;
+    LI := 0;
+    while LI <= ALast do
+    begin
+      Lp_i := AP[LI];
+      Lp_s := (Lp_i shl AShift) or TBitUtilities.NegativeRightShift32(Lprev_p, -AShift);
+      Lprev_p := Lp_i;
+      Lcc_Nu := Lcc_Nu + ANu[LI];
+      Lcc_Nu := Lcc_Nu + Lp_s;
+      Lnext_v := ANv[LI];
+      Lv_s := (Lnext_v shl AShift) or TBitUtilities.NegativeRightShift32(Lprev_v, -AShift);
+      Lprev_v := Lnext_v;
+      Lcc_p := Lcc_p + Lp_i;
+      Lcc_p := Lcc_p + Lv_s;
+      Lp_i := UInt32(Lcc_p);
+      Lcc_p := Lcc_p shr 32;
+      AP[LI] := Lp_i;
+      Lq_s := (Lp_i shl AShift) or TBitUtilities.NegativeRightShift32(Lprev_q, -AShift);
+      Lprev_q := Lp_i;
+      Lcc_Nu := Lcc_Nu + Lq_s;
+      ANu[LI] := UInt32(Lcc_Nu);
+      Lcc_Nu := Lcc_Nu shr 32;
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  // Copy the low limbs of the original p
+  System.Move(AP[0], AT[0], ALast * System.SizeOf(UInt32));
+
+  LsWords := TBitUtilities.Asr32(AShift, 5);
+  LsBits := AShift and 31;
+
+  if LsBits = 0 then
+  begin
+    LI := LsWords;
+    while LI <= ALast do
+    begin
+      Lcc_Nu := Lcc_Nu + ANu[LI];
+      Lcc_Nu := Lcc_Nu + AT[LI - LsWords];
+      Lcc_p := Lcc_p + AP[LI];
+      Lcc_p := Lcc_p + ANv[LI - LsWords];
+      AP[LI] := UInt32(Lcc_p);
+      Lcc_p := Lcc_p shr 32;
+      Lcc_Nu := Lcc_Nu + AP[LI - LsWords];
+      ANu[LI] := UInt32(Lcc_Nu);
+      Lcc_Nu := Lcc_Nu shr 32;
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  Lprev_t := 0;
+  Lprev_q := 0;
+  Lprev_v := 0;
+  LI := LsWords;
+  while LI <= ALast do
+  begin
+    Lnext_t := AT[LI - LsWords];
+    Lt_s := (Lnext_t shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_t, -LsBits);
+    Lprev_t := Lnext_t;
+    Lcc_Nu := Lcc_Nu + ANu[LI];
+    Lcc_Nu := Lcc_Nu + Lt_s;
+    Lnext_v := ANv[LI - LsWords];
+    Lv_s := (Lnext_v shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_v, -LsBits);
+    Lprev_v := Lnext_v;
+    Lcc_p := Lcc_p + AP[LI];
+    Lcc_p := Lcc_p + Lv_s;
+    AP[LI] := UInt32(Lcc_p);
+    Lcc_p := Lcc_p shr 32;
+    Lnext_q := AP[LI - LsWords];
+    Lq_s := (Lnext_q shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_q, -LsBits);
+    Lprev_q := Lnext_q;
+    Lcc_Nu := Lcc_Nu + Lq_s;
+    ANu[LI] := UInt32(Lcc_Nu);
+    Lcc_Nu := Lcc_Nu shr 32;
+    System.Inc(LI);
+  end;
+end;
+
+class procedure TScalarUtilities.AddShifted_UV(ALast: Int32; AShift: Int32; const AU0, AU1, AV0, AV1: TCryptoLibUInt32Array);
+var
+  LsWords, LsBits, LI: Int32;
+  Lcc_u0, Lcc_u1: UInt64;
+  Lnext_v0, Lnext_v1, Lv0_s, Lv1_s: UInt32;
+  Lprev_v0, Lprev_v1: UInt32;
+begin
+  LsWords := TBitUtilities.Asr32(AShift, 5);
+  LsBits := AShift and 31;
+  Lcc_u0 := 0;
+  Lcc_u1 := 0;
+
+  if LsBits = 0 then
+  begin
+    LI := LsWords;
+    while LI <= ALast do
+    begin
+      Lcc_u0 := Lcc_u0 + AU0[LI];
+      Lcc_u1 := Lcc_u1 + AU1[LI];
+      Lcc_u0 := Lcc_u0 + AV0[LI - LsWords];
+      Lcc_u1 := Lcc_u1 + AV1[LI - LsWords];
+      AU0[LI] := UInt32(Lcc_u0);
+      Lcc_u0 := Lcc_u0 shr 32;
+      AU1[LI] := UInt32(Lcc_u1);
+      Lcc_u1 := Lcc_u1 shr 32;
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  Lprev_v0 := 0;
+  Lprev_v1 := 0;
+  LI := LsWords;
+  while LI <= ALast do
+  begin
+    Lnext_v0 := AV0[LI - LsWords];
+    Lnext_v1 := AV1[LI - LsWords];
+    Lv0_s := (Lnext_v0 shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_v0, -LsBits);
+    Lv1_s := (Lnext_v1 shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_v1, -LsBits);
+    Lprev_v0 := Lnext_v0;
+    Lprev_v1 := Lnext_v1;
+    Lcc_u0 := Lcc_u0 + AU0[LI];
+    Lcc_u1 := Lcc_u1 + AU1[LI];
+    Lcc_u0 := Lcc_u0 + Lv0_s;
+    Lcc_u1 := Lcc_u1 + Lv1_s;
+    AU0[LI] := UInt32(Lcc_u0);
+    Lcc_u0 := Lcc_u0 shr 32;
+    AU1[LI] := UInt32(Lcc_u1);
+    Lcc_u1 := Lcc_u1 shr 32;
+    System.Inc(LI);
+  end;
+end;
+
+class function TScalarUtilities.GetBitLength(ALast: Int32; const AX: TCryptoLibUInt32Array): Int32;
+var
+  LI: Int32;
+  LSign: UInt32;
+begin
+  LI := ALast;
+  LSign := UInt32(TBitUtilities.Asr32(Int32(AX[LI]), 31));
+  while (LI > 0) and (AX[LI] = LSign) do
+    System.Dec(LI);
+  Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros(UInt32(Int32(AX[LI]) xor Int32(LSign)));
+end;
+
+class function TScalarUtilities.GetBitLengthPositive(ALast: Int32; const AX: TCryptoLibUInt32Array): Int32;
+var
+  LI: Int32;
+begin
+  LI := ALast;
+  while (LI > 0) and (AX[LI] = 0) do
+    System.Dec(LI);
+  Result := LI * 32 + 32 - TBitUtilities.NumberOfLeadingZeros(UInt32(AX[LI]));
+end;
+
+class function TScalarUtilities.LessThan(ALast: Int32; const AX: TCryptoLibUInt32Array;
+  const AY: TCryptoLibUInt32Array): Boolean;
+var
+  LI: Int32;
+begin
+  LI := ALast;
+  repeat
+    if AX[LI] < AY[LI] then
+      Exit(True);
+    if AX[LI] > AY[LI] then
+      Exit(False);
+    System.Dec(LI);
+  until LI < 0;
+  Result := False;
+end;
+
+class procedure TScalarUtilities.SubShifted_NP(ALast: Int32; AShift: Int32; const ANu, ANv, AP, AT: TCryptoLibUInt32Array);
+var
+  Lcc_p, Lcc_Nu: Int64;
+  LI, LsWords, LsBits: Int32;
+  Lp_i, Lp_s, Lnext_v, Lv_s, Lq_s: UInt32;
+  Lprev_p, Lprev_q, Lprev_v, Lprev_t, Lnext_t, Lt_s, Lnext_q: UInt32;
+begin
+  Lcc_p := 0;
+  Lcc_Nu := 0;
+
+  if AShift = 0 then
+    begin
+    LI := 0;
+    while LI <= ALast do
+    begin
+      Lp_i := AP[LI];
+      Lcc_Nu := Lcc_Nu + Int64(ANu[LI]);
+      Lcc_Nu := Lcc_Nu - Lp_i;
+      Lcc_p := Lcc_p + Lp_i;
+      Lcc_p := Lcc_p - Int64(ANv[LI]);
+      Lp_i := UInt32(Lcc_p);
+      Lcc_p := TBitUtilities.Asr64(Lcc_p, 32);
+      AP[LI] := Lp_i;
+      Lcc_Nu := Lcc_Nu - Int64(Lp_i);
+      ANu[LI] := UInt32(Lcc_Nu);
+      Lcc_Nu := TBitUtilities.Asr64(Lcc_Nu, 32);
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  if AShift < 32 then
+  begin
+    Lprev_p := 0;
+    Lprev_q := 0;
+    Lprev_v := 0;
+    LI := 0;
+    while LI <= ALast do
+    begin
+      Lp_i := AP[LI];
+      Lp_s := (Lp_i shl AShift) or TBitUtilities.NegativeRightShift32(Lprev_p, -AShift);
+      Lprev_p := Lp_i;
+      Lcc_Nu := Lcc_Nu + Int64(ANu[LI]);
+      Lcc_Nu := Lcc_Nu - Int64(Lp_s);
+      Lnext_v := ANv[LI];
+      Lv_s := (Lnext_v shl AShift) or TBitUtilities.NegativeRightShift32(Lprev_v, -AShift);
+      Lprev_v := Lnext_v;
+      Lcc_p := Lcc_p + Lp_i;
+      Lcc_p := Lcc_p - Int64(Lv_s);
+      Lp_i := UInt32(Lcc_p);
+      Lcc_p := TBitUtilities.Asr64(Lcc_p, 32);
+      AP[LI] := Lp_i;
+      Lq_s := (Lp_i shl AShift) or TBitUtilities.NegativeRightShift32(Lprev_q, -AShift);
+      Lprev_q := Lp_i;
+      Lcc_Nu := Lcc_Nu - Int64(Lq_s);
+      ANu[LI] := UInt32(Lcc_Nu);
+      Lcc_Nu := TBitUtilities.Asr64(Lcc_Nu, 32);
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  System.Move(AP[0], AT[0], ALast * System.SizeOf(UInt32));
+  LsWords := TBitUtilities.Asr32(AShift, 5);
+  LsBits := AShift and 31;
+
+  if LsBits = 0 then
+  begin
+    LI := LsWords;
+    while LI <= ALast do
+    begin
+      Lcc_Nu := Lcc_Nu + Int64(ANu[LI]);
+      Lcc_Nu := Lcc_Nu - Int64(AT[LI - LsWords]);
+      Lcc_p := Lcc_p + Int64(AP[LI]);
+      Lcc_p := Lcc_p - Int64(ANv[LI - LsWords]);
+      AP[LI] := UInt32(Lcc_p);
+      Lcc_p := TBitUtilities.Asr64(Lcc_p, 32);
+      Lcc_Nu := Lcc_Nu - Int64(AP[LI - LsWords]);
+      ANu[LI] := UInt32(Lcc_Nu);
+      Lcc_Nu := TBitUtilities.Asr64(Lcc_Nu, 32);
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  Lprev_t := 0;
+  Lprev_q := 0;
+  Lprev_v := 0;
+  LI := LsWords;
+  while LI <= ALast do
+  begin
+    Lnext_t := AT[LI - LsWords];
+    Lt_s := (Lnext_t shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_t, -LsBits);
+    Lprev_t := Lnext_t;
+    Lcc_Nu := Lcc_Nu + Int64(ANu[LI]);
+    Lcc_Nu := Lcc_Nu - Int64(Lt_s);
+    Lnext_v := ANv[LI - LsWords];
+    Lv_s := (Lnext_v shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_v, -LsBits);
+    Lprev_v := Lnext_v;
+    Lcc_p := Lcc_p + Int64(AP[LI]);
+    Lcc_p := Lcc_p - Int64(Lv_s);
+    AP[LI] := UInt32(Lcc_p);
+    Lcc_p := TBitUtilities.Asr64(Lcc_p, 32);
+    Lnext_q := AP[LI - LsWords];
+    Lq_s := (Lnext_q shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_q, -LsBits);
+    Lprev_q := Lnext_q;
+    Lcc_Nu := Lcc_Nu - Int64(Lq_s);
+    ANu[LI] := UInt32(Lcc_Nu);
+    Lcc_Nu := TBitUtilities.Asr64(Lcc_Nu, 32);
+    System.Inc(LI);
+  end;
+end;
+
+class procedure TScalarUtilities.SubShifted_UV(ALast: Int32; AShift: Int32; const AU0, AU1, AV0, AV1: TCryptoLibUInt32Array);
+var
+  LsWords, LsBits, LI: Int32;
+  Lcc_u0, Lcc_u1: Int64;
+  Lnext_v0, Lnext_v1, Lv0_s, Lv1_s: UInt32;
+  Lprev_v0, Lprev_v1: UInt32;
+begin
+  LsWords := TBitUtilities.Asr32(AShift, 5);
+  LsBits := AShift and 31;
+  Lcc_u0 := 0;
+  Lcc_u1 := 0;
+
+  if LsBits = 0 then
+  begin
+    LI := LsWords;
+    while LI <= ALast do
+    begin
+      Lcc_u0 := Lcc_u0 + AU0[LI];
+      Lcc_u1 := Lcc_u1 + AU1[LI];
+      Lcc_u0 := Lcc_u0 - AV0[LI - LsWords];
+      Lcc_u1 := Lcc_u1 - AV1[LI - LsWords];
+      AU0[LI] := UInt32(Lcc_u0);
+      Lcc_u0 := TBitUtilities.Asr64(Lcc_u0, 32);
+      AU1[LI] := UInt32(Lcc_u1);
+      Lcc_u1 := TBitUtilities.Asr64(Lcc_u1, 32);
+      System.Inc(LI);
+    end;
+    Exit;
+  end;
+
+  Lprev_v0 := 0;
+  Lprev_v1 := 0;
+  LI := LsWords;
+  while LI <= ALast do
+  begin
+    Lnext_v0 := AV0[LI - LsWords];
+    Lnext_v1 := AV1[LI - LsWords];
+    Lv0_s := (Lnext_v0 shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_v0, -LsBits);
+    Lv1_s := (Lnext_v1 shl LsBits) or TBitUtilities.NegativeRightShift32(Lprev_v1, -LsBits);
+    Lprev_v0 := Lnext_v0;
+    Lprev_v1 := Lnext_v1;
+    Lcc_u0 := Lcc_u0 + AU0[LI];
+    Lcc_u1 := Lcc_u1 + AU1[LI];
+    Lcc_u0 := Lcc_u0 - Int64(Lv0_s);
+    Lcc_u1 := Lcc_u1 - Int64(Lv1_s);
+    AU0[LI] := UInt32(Lcc_u0);
+    Lcc_u0 := TBitUtilities.Asr64(Lcc_u0, 32);
+    AU1[LI] := UInt32(Lcc_u1);
+    Lcc_u1 := TBitUtilities.Asr64(Lcc_u1, 32);
+    System.Inc(LI);
+  end;
+end;
+
+class procedure TScalarUtilities.Swap(var AX: TCryptoLibUInt32Array; var AY: TCryptoLibUInt32Array);
+var
+  LT: TCryptoLibUInt32Array;
+begin
+  LT := AX;
+  AX := AY;
+  AY := LT;
+end;
+
+end.

+ 99 - 0
CryptoLib/src/Math/EC/Rfc8032/ClpWnaf.pas

@@ -0,0 +1,99 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpWnaf;
+
+{$I ..\..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  ClpBitUtilities,
+  ClpCryptoLibTypes;
+
+type
+  TWnaf = class sealed
+  public
+    class procedure GetSignedVar(const AN: TCryptoLibUInt32Array; AWidth: Int32;
+      AWs: TCryptoLibShortIntArray); static;
+  end;
+
+implementation
+
+{ TWnaf }
+
+class procedure TWnaf.GetSignedVar(const AN: TCryptoLibUInt32Array; AWidth: Int32;
+  AWs: TCryptoLibShortIntArray);
+var
+  LT: TCryptoLibUInt32Array;
+  Lc, LNext, LWord: UInt32;
+  LtPos, LI, LJ, LLead, LSign, LWord16, LSkip, LDigit: Int32;
+begin
+  {$IFDEF DEBUG}
+  System.Assert((2 <= AWidth) and (AWidth <= 8));
+  {$ENDIF}
+  System.SetLength(LT, System.Length(AN) * 2);
+
+  if (AN[System.High(AN)] shr 31) <> 0 then
+    Lc := $FFFFFFFF
+  else
+    Lc := 0;
+
+  LtPos := System.Length(LT);
+  LI := System.Length(AN);
+  while LI > 0 do
+  begin
+    System.Dec(LI);
+    LNext := AN[LI];
+    System.Dec(LtPos);
+    LT[LtPos] := (LNext shr 16) or (Lc shl 16);
+    Lc := LNext;
+    System.Dec(LtPos);
+    LT[LtPos] := Lc;
+  end;
+
+  LJ := 0;
+  LLead := 32 - AWidth;
+  LSign := 0;
+
+  LI := 0;
+  while LI < System.Length(LT) do
+  begin
+    LWord := LT[LI];
+    while LJ < 16 do
+    begin
+      LWord16 := Int32(UInt32(LWord) shr (UInt32(LJ) and 31));
+      LSkip := TBitUtilities.NumberOfTrailingZeros(UInt32((LSign xor LWord16) or (1 shl 16)));
+      if LSkip > 0 then
+      begin
+        LJ := LJ + LSkip;
+        continue;
+      end;
+      LDigit := (LWord16 or 1) shl LLead;
+      LSign := TBitUtilities.Asr32(LDigit, 31);
+      AWs[(LI shl 4) + LJ] := ShortInt(TBitUtilities.Asr32(LDigit, LLead));
+      LJ := LJ + AWidth;
+    end;
+    LJ := LJ - 16;
+    System.Inc(LI);
+  end;
+  {$IFDEF DEBUG}
+  System.Assert(LSign = TBitUtilities.Asr32(Int32(AN[System.High(AN)]), 31));
+  {$ENDIF}
+end;
+
+end.

+ 5 - 5
CryptoLib/src/Math/Raw/ClpNat.pas

@@ -528,7 +528,7 @@ var
   LC: UInt64;
   LI: Int32;
 begin
-  LMASK := UInt32(-(AMask ) and 1);
+  LMASK := UInt32(-(AMask and 1));
   LC := 0;
   for LI := 0 to ALen - 1 do
   begin
@@ -545,7 +545,7 @@ var
   LC: UInt64;
   LI: Int32;
 begin
-  LMASK := UInt32(-(AMask ) and 1);
+  LMASK := UInt32(-(AMask and 1));
   LC := 0;
   for LI := 0 to ALen - 1 do
   begin
@@ -563,7 +563,7 @@ var
   LZI: UInt32;
   LDiff: UInt32;
 begin
-  LMASK := UInt32(-(AMask ) and 1);
+  LMASK := UInt32(-(AMask and 1));
   LZI := AZ[AZOff + LI];
   LDiff := LZI xor AX[AXOff + LI];
   for LI := 0 to ALen - 1 do
@@ -677,7 +677,7 @@ var
   LC: Int64;
   LI: Int32;
 begin
-  LMASK := UInt32(-(AMask ) and 1);
+  LMASK := UInt32(-(AMask and 1));
   LC := 0;
   for LI := 0 to ALen - 1 do
   begin
@@ -694,7 +694,7 @@ var
   LC: Int64;
   LI: Int32;
 begin
-  LMASK := UInt32(-(AMask ) and 1);
+  LMASK := UInt32(-(AMask and 1));
   LC := 0;
   for LI := 0 to ALen - 1 do
   begin