summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2018-09-21 15:17:56 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2018-09-21 15:17:56 +0700
commitfbae27fb1edcea6b0924dba977a6d94f0a3655db (patch)
treeffea8216ac6125b574dcd05bed38fccd0fe10ba5
parentRefactoring (diff)
downloadBouncyCastle.NET-ed25519-fbae27fb1edcea6b0924dba977a6d94f0a3655db.tar.xz
Higher-level API support for Ed25519/Ed448/X25519/X448
-rw-r--r--crypto/BouncyCastle.Android.csproj25
-rw-r--r--crypto/BouncyCastle.csproj25
-rw-r--r--crypto/BouncyCastle.iOS.csproj25
-rw-r--r--crypto/crypto.csproj150
-rw-r--r--crypto/src/asn1/edec/EdECObjectIdentifiers.cs17
-rw-r--r--crypto/src/crypto/IRawAgreement.cs13
-rw-r--r--crypto/src/crypto/agreement/X25519Agreement.cs27
-rw-r--r--crypto/src/crypto/agreement/X448Agreement.cs27
-rw-r--r--crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs25
-rw-r--r--crypto/src/crypto/generators/Ed448KeyPairGenerator.cs25
-rw-r--r--crypto/src/crypto/generators/X25519KeyPairGenerator.cs25
-rw-r--r--crypto/src/crypto/generators/X448KeyPairGenerator.cs25
-rw-r--r--crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs15
-rw-r--r--crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs98
-rw-r--r--crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs40
-rw-r--r--crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs15
-rw-r--r--crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs90
-rw-r--r--crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs40
-rw-r--r--crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs15
-rw-r--r--crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs62
-rw-r--r--crypto/src/crypto/parameters/X25519PublicKeyParameters.cs40
-rw-r--r--crypto/src/crypto/parameters/X448KeyGenerationParameters.cs15
-rw-r--r--crypto/src/crypto/parameters/X448PrivateKeyParameters.cs62
-rw-r--r--crypto/src/crypto/parameters/X448PublicKeyParameters.cs40
-rw-r--r--crypto/src/crypto/signers/Ed25519Signer.cs128
-rw-r--r--crypto/src/crypto/signers/Ed25519ctxSigner.cs130
-rw-r--r--crypto/src/crypto/signers/Ed25519phSigner.cs89
-rw-r--r--crypto/src/crypto/signers/Ed448Signer.cs130
-rw-r--r--crypto/src/crypto/signers/Ed448phSigner.cs89
-rw-r--r--crypto/src/math/ec/rfc8032/Ed25519.cs7
-rw-r--r--crypto/src/math/ec/rfc8032/Ed448.cs6
-rw-r--r--crypto/src/pkcs/PrivateKeyInfoFactory.cs116
-rw-r--r--crypto/src/security/AgreementUtilities.cs55
-rw-r--r--crypto/src/security/GeneratorUtilities.cs34
-rw-r--r--crypto/src/security/PrivateKeyFactory.cs28
-rw-r--r--crypto/src/security/PublicKeyFactory.cs32
-rw-r--r--crypto/src/security/SignerUtilities.cs36
-rw-r--r--crypto/src/x509/SubjectPublicKeyInfoFactory.cs67
-rw-r--r--crypto/test/UnitTests.csproj5
-rw-r--r--crypto/test/src/asn1/test/PrivateKeyInfoTest.cs60
-rw-r--r--crypto/test/src/asn1/test/RegressionTest.cs1
-rw-r--r--crypto/test/src/crypto/test/Ed25519Test.cs111
-rw-r--r--crypto/test/src/crypto/test/Ed448Test.cs107
-rw-r--r--crypto/test/src/crypto/test/RegressionTest.cs4
-rw-r--r--crypto/test/src/crypto/test/X25519Test.cs69
-rw-r--r--crypto/test/src/crypto/test/X448Test.cs69
-rw-r--r--crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs10
-rw-r--r--crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs8
-rw-r--r--crypto/test/src/security/test/TestSignerUtil.cs18
49 files changed, 2259 insertions, 91 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index 3c34c5e1b..c5eb8e6f5 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -258,6 +258,7 @@
     <Compile Include="src\asn1\cryptopro\GOST3410ParamSetParameters.cs" />
     <Compile Include="src\asn1\cryptopro\GOST3410PublicKeyAlgParameters.cs" />
     <Compile Include="src\asn1\eac\EACObjectIdentifiers.cs" />
+    <Compile Include="src\asn1\edec\EdECObjectIdentifiers.cs" />
     <Compile Include="src\asn1\esf\CertificateValues.cs" />
     <Compile Include="src\asn1\esf\CommitmentTypeIdentifier.cs" />
     <Compile Include="src\asn1\esf\CommitmentTypeIndication.cs" />
@@ -659,6 +660,7 @@
     <Compile Include="src\crypto\IEntropySource.cs" />
     <Compile Include="src\crypto\IEntropySourceProvider.cs" />
     <Compile Include="src\crypto\IMac.cs" />
+    <Compile Include="src\crypto\IRawAgreement.cs" />
     <Compile Include="src\crypto\ISignatureFactory.cs" />
     <Compile Include="src\crypto\IStreamCalculator.cs" />
     <Compile Include="src\crypto\ISigner.cs" />
@@ -699,6 +701,8 @@
     <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs" />
     <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs" />
     <Compile Include="src\crypto\agreement\SM2KeyExchange.cs" />
+    <Compile Include="src\crypto\agreement\X25519Agreement.cs" />
+    <Compile Include="src\crypto\agreement\X448Agreement.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakeParticipant.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroup.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroups.cs" />
@@ -815,6 +819,8 @@
     <Compile Include="src\crypto\generators\DsaKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\DsaParametersGenerator.cs" />
     <Compile Include="src\crypto\generators\ECKeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\Ed25519KeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\Ed448KeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\ElGamalKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\ElGamalParametersGenerator.cs" />
     <Compile Include="src\crypto\generators\GOST3410KeyPairGenerator.cs" />
@@ -831,6 +837,8 @@
     <Compile Include="src\crypto\generators\RSABlindingFactorGenerator.cs" />
     <Compile Include="src\crypto\generators\RsaKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\SCrypt.cs" />
+    <Compile Include="src\crypto\generators\X25519KeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\X448KeyPairGenerator.cs" />
     <Compile Include="src\crypto\io\CipherStream.cs" />
     <Compile Include="src\crypto\io\DigestStream.cs" />
     <Compile Include="src\crypto\io\MacStream.cs" />
@@ -901,6 +909,12 @@
     <Compile Include="src\crypto\parameters\ECKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ECPrivateKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ECPublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519PublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448PublicKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalKeyGenerationParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalParameters.cs" />
@@ -939,6 +953,12 @@
     <Compile Include="src\crypto\parameters\SM2KeyExchangePublicParameters.cs" />
     <Compile Include="src\crypto\parameters\Srp6GroupParameters.cs" />
     <Compile Include="src\crypto\parameters\TweakableBlockCipherParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519PublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448PublicKeyParameters.cs" />
     <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs" />
     <Compile Include="src\crypto\prng\DigestRandomGenerator.cs" />
     <Compile Include="src\crypto\prng\IRandomGenerator.cs" />
@@ -950,6 +970,11 @@
     <Compile Include="src\crypto\signers\ECDsaSigner.cs" />
     <Compile Include="src\crypto\signers\ECGOST3410Signer.cs" />
     <Compile Include="src\crypto\signers\ECNRSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519ctxSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519phSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519Signer.cs" />
+    <Compile Include="src\crypto\signers\Ed448phSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed448Signer.cs" />
     <Compile Include="src\crypto\signers\GOST3410DigestSigner.cs" />
     <Compile Include="src\crypto\signers\GOST3410Signer.cs" />
     <Compile Include="src\crypto\signers\GenericSigner.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index 95d42bc8b..76da30095 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -252,6 +252,7 @@
     <Compile Include="src\asn1\cryptopro\GOST3410ParamSetParameters.cs" />
     <Compile Include="src\asn1\cryptopro\GOST3410PublicKeyAlgParameters.cs" />
     <Compile Include="src\asn1\eac\EACObjectIdentifiers.cs" />
+    <Compile Include="src\asn1\edec\EdECObjectIdentifiers.cs" />
     <Compile Include="src\asn1\esf\CertificateValues.cs" />
     <Compile Include="src\asn1\esf\CommitmentTypeIdentifier.cs" />
     <Compile Include="src\asn1\esf\CommitmentTypeIndication.cs" />
@@ -653,6 +654,7 @@
     <Compile Include="src\crypto\IEntropySource.cs" />
     <Compile Include="src\crypto\IEntropySourceProvider.cs" />
     <Compile Include="src\crypto\IMac.cs" />
+    <Compile Include="src\crypto\IRawAgreement.cs" />
     <Compile Include="src\crypto\ISignatureFactory.cs" />
     <Compile Include="src\crypto\IStreamCalculator.cs" />
     <Compile Include="src\crypto\ISigner.cs" />
@@ -693,6 +695,8 @@
     <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs" />
     <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs" />
     <Compile Include="src\crypto\agreement\SM2KeyExchange.cs" />
+    <Compile Include="src\crypto\agreement\X25519Agreement.cs" />
+    <Compile Include="src\crypto\agreement\X448Agreement.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakeParticipant.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroup.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroups.cs" />
@@ -809,6 +813,8 @@
     <Compile Include="src\crypto\generators\DsaKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\DsaParametersGenerator.cs" />
     <Compile Include="src\crypto\generators\ECKeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\Ed25519KeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\Ed448KeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\ElGamalKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\ElGamalParametersGenerator.cs" />
     <Compile Include="src\crypto\generators\GOST3410KeyPairGenerator.cs" />
@@ -825,6 +831,8 @@
     <Compile Include="src\crypto\generators\RSABlindingFactorGenerator.cs" />
     <Compile Include="src\crypto\generators\RsaKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\SCrypt.cs" />
+    <Compile Include="src\crypto\generators\X25519KeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\X448KeyPairGenerator.cs" />
     <Compile Include="src\crypto\io\CipherStream.cs" />
     <Compile Include="src\crypto\io\DigestStream.cs" />
     <Compile Include="src\crypto\io\MacStream.cs" />
@@ -895,6 +903,12 @@
     <Compile Include="src\crypto\parameters\ECKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ECPrivateKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ECPublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519PublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448PublicKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalKeyGenerationParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalParameters.cs" />
@@ -933,6 +947,12 @@
     <Compile Include="src\crypto\parameters\SM2KeyExchangePublicParameters.cs" />
     <Compile Include="src\crypto\parameters\Srp6GroupParameters.cs" />
     <Compile Include="src\crypto\parameters\TweakableBlockCipherParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519PublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448PublicKeyParameters.cs" />
     <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs" />
     <Compile Include="src\crypto\prng\DigestRandomGenerator.cs" />
     <Compile Include="src\crypto\prng\IRandomGenerator.cs" />
@@ -944,6 +964,11 @@
     <Compile Include="src\crypto\signers\ECDsaSigner.cs" />
     <Compile Include="src\crypto\signers\ECGOST3410Signer.cs" />
     <Compile Include="src\crypto\signers\ECNRSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519ctxSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519phSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519Signer.cs" />
+    <Compile Include="src\crypto\signers\Ed448phSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed448Signer.cs" />
     <Compile Include="src\crypto\signers\GOST3410DigestSigner.cs" />
     <Compile Include="src\crypto\signers\GOST3410Signer.cs" />
     <Compile Include="src\crypto\signers\GenericSigner.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index f9cebdc86..52dae0f4f 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -253,6 +253,7 @@
     <Compile Include="src\asn1\cryptopro\GOST3410ParamSetParameters.cs" />
     <Compile Include="src\asn1\cryptopro\GOST3410PublicKeyAlgParameters.cs" />
     <Compile Include="src\asn1\eac\EACObjectIdentifiers.cs" />
+    <Compile Include="src\asn1\edec\EdECObjectIdentifiers.cs" />
     <Compile Include="src\asn1\esf\CertificateValues.cs" />
     <Compile Include="src\asn1\esf\CommitmentTypeIdentifier.cs" />
     <Compile Include="src\asn1\esf\CommitmentTypeIndication.cs" />
@@ -654,6 +655,7 @@
     <Compile Include="src\crypto\IEntropySource.cs" />
     <Compile Include="src\crypto\IEntropySourceProvider.cs" />
     <Compile Include="src\crypto\IMac.cs" />
+    <Compile Include="src\crypto\IRawAgreement.cs" />
     <Compile Include="src\crypto\ISignatureFactory.cs" />
     <Compile Include="src\crypto\IStreamCalculator.cs" />
     <Compile Include="src\crypto\ISigner.cs" />
@@ -694,6 +696,8 @@
     <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs" />
     <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs" />
     <Compile Include="src\crypto\agreement\SM2KeyExchange.cs" />
+    <Compile Include="src\crypto\agreement\X25519Agreement.cs" />
+    <Compile Include="src\crypto\agreement\X448Agreement.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakeParticipant.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroup.cs" />
     <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroups.cs" />
@@ -810,6 +814,8 @@
     <Compile Include="src\crypto\generators\DsaKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\DsaParametersGenerator.cs" />
     <Compile Include="src\crypto\generators\ECKeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\Ed25519KeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\Ed448KeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\ElGamalKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\ElGamalParametersGenerator.cs" />
     <Compile Include="src\crypto\generators\GOST3410KeyPairGenerator.cs" />
@@ -826,6 +832,8 @@
     <Compile Include="src\crypto\generators\RSABlindingFactorGenerator.cs" />
     <Compile Include="src\crypto\generators\RsaKeyPairGenerator.cs" />
     <Compile Include="src\crypto\generators\SCrypt.cs" />
+    <Compile Include="src\crypto\generators\X25519KeyPairGenerator.cs" />
+    <Compile Include="src\crypto\generators\X448KeyPairGenerator.cs" />
     <Compile Include="src\crypto\io\CipherStream.cs" />
     <Compile Include="src\crypto\io\DigestStream.cs" />
     <Compile Include="src\crypto\io\MacStream.cs" />
@@ -896,6 +904,12 @@
     <Compile Include="src\crypto\parameters\ECKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ECPrivateKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ECPublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed25519PublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\Ed448PublicKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalKeyGenerationParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalKeyParameters.cs" />
     <Compile Include="src\crypto\parameters\ElGamalParameters.cs" />
@@ -934,6 +948,12 @@
     <Compile Include="src\crypto\parameters\SM2KeyExchangePublicParameters.cs" />
     <Compile Include="src\crypto\parameters\Srp6GroupParameters.cs" />
     <Compile Include="src\crypto\parameters\TweakableBlockCipherParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X25519PublicKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448KeyGenerationParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448PrivateKeyParameters.cs" />
+    <Compile Include="src\crypto\parameters\X448PublicKeyParameters.cs" />
     <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs" />
     <Compile Include="src\crypto\prng\DigestRandomGenerator.cs" />
     <Compile Include="src\crypto\prng\IRandomGenerator.cs" />
@@ -945,6 +965,11 @@
     <Compile Include="src\crypto\signers\ECDsaSigner.cs" />
     <Compile Include="src\crypto\signers\ECGOST3410Signer.cs" />
     <Compile Include="src\crypto\signers\ECNRSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519ctxSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519phSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed25519Signer.cs" />
+    <Compile Include="src\crypto\signers\Ed448phSigner.cs" />
+    <Compile Include="src\crypto\signers\Ed448Signer.cs" />
     <Compile Include="src\crypto\signers\GOST3410DigestSigner.cs" />
     <Compile Include="src\crypto\signers\GOST3410Signer.cs" />
     <Compile Include="src\crypto\signers\GenericSigner.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index b6dfb3963..2ffb66d8c 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -1149,6 +1149,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\asn1\edec\EdECObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\asn1\esf\CertificateValues.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3129,6 +3134,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\IRawAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\ISignatureFactory.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3249,6 +3259,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\agreement\X25519Agreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\X448Agreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\agreement\jpake\JPakeParticipant.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3849,6 +3869,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\generators\Ed25519KeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\Ed448KeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\generators\ElGamalKeyPairGenerator.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3939,6 +3969,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\generators\X25519KeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\X448KeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\io\CipherStream.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4289,6 +4329,36 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\parameters\Ed25519KeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\Ed25519PrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\Ed25519PublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\Ed448KeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\Ed448PrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\Ed448PublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\parameters\ElGamalKeyGenerationParameters.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4484,6 +4554,36 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\parameters\X25519KeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\X25519PrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\X25519PublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\X448KeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\X448PrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\X448PublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\prng\BasicEntropySourceProvider.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4609,6 +4709,31 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\signers\Ed25519ctxSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\Ed25519phSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\Ed25519Signer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\Ed448phSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\Ed448Signer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\signers\GenericSigner.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11230,6 +11355,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\asn1\test\PrivateKeyInfoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\asn1\test\PKCS10Test.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11670,6 +11800,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\Ed25519Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Ed448Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\ElGamalTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -12160,6 +12300,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\X25519Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\X448Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\X931SignerTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/edec/EdECObjectIdentifiers.cs b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs
new file mode 100644
index 000000000..f8c5713d8
--- /dev/null
+++ b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.EdEC
+{
+    /**
+     * Edwards Elliptic Curve Object Identifiers (RFC 8410)
+     */
+    public abstract class EdECObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier id_edwards_curve_algs = new DerObjectIdentifier("1.3.101");
+
+        public static readonly DerObjectIdentifier id_X25519 = id_edwards_curve_algs.Branch("110");
+        public static readonly DerObjectIdentifier id_X448 = id_edwards_curve_algs.Branch("111");
+        public static readonly DerObjectIdentifier id_Ed25519 = id_edwards_curve_algs.Branch("112");
+        public static readonly DerObjectIdentifier id_Ed448 = id_edwards_curve_algs.Branch("113");
+    }
+}
diff --git a/crypto/src/crypto/IRawAgreement.cs b/crypto/src/crypto/IRawAgreement.cs
new file mode 100644
index 000000000..63e664888
--- /dev/null
+++ b/crypto/src/crypto/IRawAgreement.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    public interface IRawAgreement
+    {
+        void Init(ICipherParameters parameters);
+
+        int AgreementSize { get; }
+
+        void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off);
+    }
+}
diff --git a/crypto/src/crypto/agreement/X25519Agreement.cs b/crypto/src/crypto/agreement/X25519Agreement.cs
new file mode 100644
index 000000000..7e5890c16
--- /dev/null
+++ b/crypto/src/crypto/agreement/X25519Agreement.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+    public sealed class X25519Agreement
+        : IRawAgreement
+    {
+        private X25519PrivateKeyParameters privateKey;
+
+        public void Init(ICipherParameters parameters)
+        {
+            this.privateKey = (X25519PrivateKeyParameters)parameters;
+        }
+
+        public int AgreementSize
+        {
+            get { return X25519PrivateKeyParameters.SecretSize; }
+        }
+
+        public void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off)
+        {
+            privateKey.GenerateSecret((X25519PublicKeyParameters)publicKey, buf, off);
+        }
+    }
+}
diff --git a/crypto/src/crypto/agreement/X448Agreement.cs b/crypto/src/crypto/agreement/X448Agreement.cs
new file mode 100644
index 000000000..26f608c26
--- /dev/null
+++ b/crypto/src/crypto/agreement/X448Agreement.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+    public sealed class X448Agreement
+        : IRawAgreement
+    {
+        private X448PrivateKeyParameters privateKey;
+
+        public void Init(ICipherParameters parameters)
+        {
+            this.privateKey = (X448PrivateKeyParameters)parameters;
+        }
+
+        public int AgreementSize
+        {
+            get { return X448PrivateKeyParameters.SecretSize; }
+        }
+
+        public void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off)
+        {
+            privateKey.GenerateSecret((X448PublicKeyParameters)publicKey, buf, off);
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs b/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs
new file mode 100644
index 000000000..266d111cf
--- /dev/null
+++ b/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class Ed25519KeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
+    {
+        private SecureRandom random;
+
+        public virtual void Init(KeyGenerationParameters parameters)
+        {
+            this.random = parameters.Random;
+        }
+
+        public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(random);
+            Ed25519PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+            return new AsymmetricCipherKeyPair(publicKey, privateKey);
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs b/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs
new file mode 100644
index 000000000..50aee631e
--- /dev/null
+++ b/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class Ed448KeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
+    {
+        private SecureRandom random;
+
+        public virtual void Init(KeyGenerationParameters parameters)
+        {
+            this.random = parameters.Random;
+        }
+
+        public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            Ed448PrivateKeyParameters privateKey = new Ed448PrivateKeyParameters(random);
+            Ed448PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+            return new AsymmetricCipherKeyPair(publicKey, privateKey);
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/X25519KeyPairGenerator.cs b/crypto/src/crypto/generators/X25519KeyPairGenerator.cs
new file mode 100644
index 000000000..94378448b
--- /dev/null
+++ b/crypto/src/crypto/generators/X25519KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class X25519KeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
+    {
+        private SecureRandom random;
+
+        public virtual void Init(KeyGenerationParameters parameters)
+        {
+            this.random = parameters.Random;
+        }
+
+        public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            X25519PrivateKeyParameters privateKey = new X25519PrivateKeyParameters(random);
+            X25519PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+            return new AsymmetricCipherKeyPair(publicKey, privateKey);
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/X448KeyPairGenerator.cs b/crypto/src/crypto/generators/X448KeyPairGenerator.cs
new file mode 100644
index 000000000..4a203e4f1
--- /dev/null
+++ b/crypto/src/crypto/generators/X448KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class X448KeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
+    {
+        private SecureRandom random;
+
+        public virtual void Init(KeyGenerationParameters parameters)
+        {
+            this.random = parameters.Random;
+        }
+
+        public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            X448PrivateKeyParameters privateKey = new X448PrivateKeyParameters(random);
+            X448PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+            return new AsymmetricCipherKeyPair(publicKey, privateKey);
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs b/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs
new file mode 100644
index 000000000..daf3856c3
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class Ed25519KeyGenerationParameters
+        : KeyGenerationParameters
+    {
+        public Ed25519KeyGenerationParameters(SecureRandom random)
+            : base(random, 256)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
new file mode 100644
index 000000000..97902e093
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
@@ -0,0 +1,98 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class Ed25519PrivateKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = Ed25519.SecretKeySize;
+        public static readonly int SignatureSize = Ed25519.SignatureSize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public Ed25519PrivateKeyParameters(SecureRandom random)
+            : base(true)
+        {
+            random.NextBytes(data);
+        }
+
+        public Ed25519PrivateKeyParameters(byte[] buf, int off)
+            : base(true)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public Ed25519PrivateKeyParameters(Stream input)
+            : base(true)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of Ed25519 private key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+
+        public Ed25519PublicKeyParameters GeneratePublicKey()
+        {
+            byte[] publicKey = new byte[Ed25519.PublicKeySize];
+            Ed25519.GeneratePublicKey(data, 0, publicKey, 0);
+            return new Ed25519PublicKeyParameters(publicKey, 0);
+        }
+
+        public void Sign(Ed25519.Algorithm algorithm, Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen,
+            byte[] sig, int sigOff)
+        {
+            byte[] pk = new byte[Ed25519.PublicKeySize];
+            if (null == publicKey)
+            {
+                Ed25519.GeneratePublicKey(data, 0, pk, 0);
+            }
+            else
+            {
+                publicKey.Encode(pk, 0);
+            }
+
+            switch (algorithm)
+            {
+            case Ed25519.Algorithm.Ed25519:
+            {
+                if (null != ctx)
+                    throw new ArgumentException("ctx");
+
+                Ed25519.Sign(data, 0, pk, 0, msg, msgOff, msgLen, sig, sigOff);
+                break;
+            }
+            case Ed25519.Algorithm.Ed25519ctx:
+            {
+                Ed25519.Sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
+                break;
+            }
+            case Ed25519.Algorithm.Ed25519ph:
+            {
+                if (Ed25519.PrehashSize != msgLen)
+                    throw new ArgumentException("msgLen");
+
+                Ed25519.SignPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff);
+                break;
+            }
+            default:
+            {
+                throw new ArgumentException("algorithm");
+            }
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
new file mode 100644
index 000000000..96e9ec21f
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class Ed25519PublicKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = Ed25519.PublicKeySize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public Ed25519PublicKeyParameters(byte[] buf, int off)
+            : base(false)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public Ed25519PublicKeyParameters(Stream input)
+            : base(false)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of Ed25519 public key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs b/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
new file mode 100644
index 000000000..830d15a04
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class Ed448KeyGenerationParameters
+        : KeyGenerationParameters
+    {
+        public Ed448KeyGenerationParameters(SecureRandom random)
+            : base(random, 448)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
new file mode 100644
index 000000000..74b5d63f3
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class Ed448PrivateKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = Ed448.SecretKeySize;
+        public static readonly int SignatureSize = Ed448.SignatureSize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public Ed448PrivateKeyParameters(SecureRandom random)
+            : base(true)
+        {
+            random.NextBytes(data);
+        }
+
+        public Ed448PrivateKeyParameters(byte[] buf, int off)
+            : base(true)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public Ed448PrivateKeyParameters(Stream input)
+            : base(true)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of Ed448 private key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+
+        public Ed448PublicKeyParameters GeneratePublicKey()
+        {
+            byte[] publicKey = new byte[Ed448.PublicKeySize];
+            Ed448.GeneratePublicKey(data, 0, publicKey, 0);
+            return new Ed448PublicKeyParameters(publicKey, 0);
+        }
+
+        public void Sign(Ed448.Algorithm algorithm, Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen,
+            byte[] sig, int sigOff)
+        {
+            byte[] pk = new byte[Ed448.PublicKeySize];
+            if (null == publicKey)
+            {
+                Ed448.GeneratePublicKey(data, 0, pk, 0);
+            }
+            else
+            {
+                publicKey.Encode(pk, 0);
+            }
+
+            switch (algorithm)
+            {
+            case Ed448.Algorithm.Ed448:
+            {
+                Ed448.Sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
+                break;
+            }
+            case Ed448.Algorithm.Ed448ph:
+            {
+                if (Ed448.PrehashSize != msgLen)
+                    throw new ArgumentException("msgLen");
+
+                Ed448.SignPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff);
+                break;
+            }
+            default:
+            {
+                throw new ArgumentException("algorithm");
+            }
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs
new file mode 100644
index 000000000..d7faac246
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class Ed448PublicKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = Ed448.PublicKeySize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public Ed448PublicKeyParameters(byte[] buf, int off)
+            : base(false)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public Ed448PublicKeyParameters(Stream input)
+            : base(false)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of Ed448 public key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs b/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs
new file mode 100644
index 000000000..09972c7a2
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class X25519KeyGenerationParameters
+        : KeyGenerationParameters
+    {
+        public X25519KeyGenerationParameters(SecureRandom random)
+            : base(random, 256)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
new file mode 100644
index 000000000..c25ab9364
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class X25519PrivateKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = X25519.ScalarSize;
+        public static readonly int SecretSize = X25519.PointSize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public X25519PrivateKeyParameters(SecureRandom random)
+            : base(true)
+        {
+            random.NextBytes(data);
+        }
+
+        public X25519PrivateKeyParameters(byte[] buf, int off)
+            : base(true)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public X25519PrivateKeyParameters(Stream input)
+            : base(true)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of X25519 private key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+
+        public X25519PublicKeyParameters GeneratePublicKey()
+        {
+            byte[] publicKey = new byte[X25519.PointSize];
+            X25519.ScalarMultBase(data, 0, publicKey, 0);
+            return new X25519PublicKeyParameters(publicKey, 0);
+        }
+
+        public void GenerateSecret(X25519PublicKeyParameters publicKey, byte[] buf, int off)
+        {
+            byte[] encoded = new byte[X25519.PointSize];
+            publicKey.Encode(encoded, 0);
+            X25519.ScalarMult(data, 0, encoded, 0, buf, off);
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
new file mode 100644
index 000000000..7df5f624d
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class X25519PublicKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = X25519.PointSize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public X25519PublicKeyParameters(byte[] buf, int off)
+            : base(false)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public X25519PublicKeyParameters(Stream input)
+            : base(false)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of X25519 public key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs b/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs
new file mode 100644
index 000000000..a7cb55844
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class X448KeyGenerationParameters
+        : KeyGenerationParameters
+    {
+        public X448KeyGenerationParameters(SecureRandom random)
+            : base(random, 448)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
new file mode 100644
index 000000000..291eac10f
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class X448PrivateKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = X448.ScalarSize;
+        public static readonly int SecretSize = X448.PointSize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public X448PrivateKeyParameters(SecureRandom random)
+            : base(true)
+        {
+            random.NextBytes(data);
+        }
+
+        public X448PrivateKeyParameters(byte[] buf, int off)
+            : base(true)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public X448PrivateKeyParameters(Stream input)
+            : base(true)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of X448 private key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+
+        public X448PublicKeyParameters GeneratePublicKey()
+        {
+            byte[] publicKey = new byte[X448.PointSize];
+            X448.ScalarMultBase(data, 0, publicKey, 0);
+            return new X448PublicKeyParameters(publicKey, 0);
+        }
+
+        public void GenerateSecret(X448PublicKeyParameters publicKey, byte[] buf, int off)
+        {
+            byte[] encoded = new byte[X448.PointSize];
+            publicKey.Encode(encoded, 0);
+            X448.ScalarMult(data, 0, encoded, 0, buf, off);
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/X448PublicKeyParameters.cs b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
new file mode 100644
index 000000000..6c566ddf2
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public sealed class X448PublicKeyParameters
+        : AsymmetricKeyParameter
+    {
+        public static readonly int KeySize = X448.PointSize;
+
+        private readonly byte[] data = new byte[KeySize];
+
+        public X448PublicKeyParameters(byte[] buf, int off)
+            : base(false)
+        {
+            Array.Copy(buf, off, data, 0, KeySize);
+        }
+
+        public X448PublicKeyParameters(Stream input)
+            : base(false)
+        {
+            if (KeySize != Streams.ReadFully(input, data))
+                throw new EndOfStreamException("EOF encountered in middle of X448 public key");
+        }
+
+        public void Encode(byte[] buf, int off)
+        {
+            Array.Copy(data, 0, buf, off, KeySize);
+        }
+
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(data);
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/Ed25519Signer.cs b/crypto/src/crypto/signers/Ed25519Signer.cs
new file mode 100644
index 000000000..904450ed1
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519Signer.cs
@@ -0,0 +1,128 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class Ed25519Signer
+        : ISigner
+    {
+        private readonly Buffer buffer = new Buffer();
+
+        private bool forSigning;
+        private Ed25519PrivateKeyParameters privateKey;
+        private Ed25519PublicKeyParameters publicKey;
+
+        public Ed25519Signer()
+        {
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Ed25519"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+
+            if (forSigning)
+            {
+                // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+                this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+                this.publicKey = privateKey.GeneratePublicKey();
+            }
+            else
+            {
+                this.privateKey = null;
+                this.publicKey = (Ed25519PublicKeyParameters)parameters;
+            }
+
+            Reset();
+        }
+
+        public virtual void Update(byte b)
+        {
+            buffer.WriteByte(b);
+        }
+
+        public virtual void BlockUpdate(byte[] buf, int off, int len)
+        {
+            buffer.Write(buf, off, len);
+        }
+
+        public virtual byte[] GenerateSignature()
+        {
+            if (!forSigning)
+                throw new InvalidOperationException("Ed25519Signer not initialised for signature generation.");
+
+            return buffer.GenerateSignature(privateKey, publicKey);
+        }
+
+        public virtual bool VerifySignature(byte[] signature)
+        {
+            if (forSigning)
+                throw new InvalidOperationException("Ed25519Signer not initialised for verification");
+
+            return buffer.VerifySignature(publicKey, signature);
+        }
+
+        public virtual void Reset()
+        {
+            buffer.Reset();
+        }
+
+        private class Buffer : MemoryStream
+        {
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal byte[] GenerateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey)
+            {
+#if PORTABLE
+                byte[] buf = ToArray();
+                int count = buf.Length;
+#else
+                byte[] buf = GetBuffer();
+                int count = (int)Position;
+#endif
+                byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+                privateKey.Sign(Ed25519.Algorithm.Ed25519, publicKey, null, buf, 0, count, signature, 0);
+                Reset();
+                return signature;
+            }
+
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal bool VerifySignature(Ed25519PublicKeyParameters publicKey, byte[] signature)
+            {
+#if PORTABLE
+                byte[] buf = ToArray();
+                int count = buf.Length;
+#else
+                byte[] buf = GetBuffer();
+                int count = (int)Position;
+#endif
+                byte[] pk = publicKey.GetEncoded();
+                bool result = Ed25519.Verify(signature, 0, pk, 0, buf, 0, count);
+                Reset();
+                return result;
+            }
+
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal void Reset()
+            {
+#if PORTABLE
+                this.Position = 0L;
+
+                // TODO Clear using Write method
+#else
+                Array.Clear(GetBuffer(), 0, (int)Position);
+#endif
+                this.Position = 0L;
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/Ed25519ctxSigner.cs b/crypto/src/crypto/signers/Ed25519ctxSigner.cs
new file mode 100644
index 000000000..e9c2eca44
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519ctxSigner.cs
@@ -0,0 +1,130 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class Ed25519ctxSigner
+        : ISigner
+    {
+        private readonly Buffer buffer = new Buffer();
+        private readonly byte[] context;
+
+        private bool forSigning;
+        private Ed25519PrivateKeyParameters privateKey;
+        private Ed25519PublicKeyParameters publicKey;
+
+        public Ed25519ctxSigner(byte[] context)
+        {
+            this.context = Arrays.Clone(context);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Ed25519ctx"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+
+            if (forSigning)
+            {
+                // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+                this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+                this.publicKey = privateKey.GeneratePublicKey();
+            }
+            else
+            {
+                this.privateKey = null;
+                this.publicKey = (Ed25519PublicKeyParameters)parameters;
+            }
+
+            Reset();
+        }
+
+        public virtual void Update(byte b)
+        {
+            buffer.WriteByte(b);
+        }
+
+        public virtual void BlockUpdate(byte[] buf, int off, int len)
+        {
+            buffer.Write(buf, off, len);
+        }
+
+        public virtual byte[] GenerateSignature()
+        {
+            if (!forSigning)
+                throw new InvalidOperationException("Ed25519ctxSigner not initialised for signature generation.");
+
+            return buffer.GenerateSignature(privateKey, publicKey, context);
+        }
+
+        public virtual bool VerifySignature(byte[] signature)
+        {
+            if (forSigning)
+                throw new InvalidOperationException("Ed25519ctxSigner not initialised for verification");
+
+            return buffer.VerifySignature(publicKey, context, signature);
+        }
+
+        public virtual void Reset()
+        {
+            buffer.Reset();
+        }
+
+        private class Buffer : MemoryStream
+        {
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal byte[] GenerateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey, byte[] ctx)
+            {
+#if PORTABLE
+                byte[] buf = ToArray();
+                int count = buf.Length;
+#else
+                byte[] buf = GetBuffer();
+                int count = (int)Position;
+#endif
+                byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+                privateKey.Sign(Ed25519.Algorithm.Ed25519ctx, publicKey, ctx, buf, 0, count, signature, 0);
+                Reset();
+                return signature;
+            }
+
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal bool VerifySignature(Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] signature)
+            {
+#if PORTABLE
+                byte[] buf = ToArray();
+                int count = buf.Length;
+#else
+                byte[] buf = GetBuffer();
+                int count = (int)Position;
+#endif
+                byte[] pk = publicKey.GetEncoded();
+                bool result = Ed25519.Verify(signature, 0, pk, 0, ctx, buf, 0, count);
+                Reset();
+                return result;
+            }
+
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal void Reset()
+            {
+#if PORTABLE
+                this.Position = 0L;
+
+                // TODO Clear using Write method
+#else
+                Array.Clear(GetBuffer(), 0, (int)Position);
+#endif
+                this.Position = 0L;
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/Ed25519phSigner.cs b/crypto/src/crypto/signers/Ed25519phSigner.cs
new file mode 100644
index 000000000..0d3de96f3
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519phSigner.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class Ed25519phSigner
+        : ISigner
+    {
+        private readonly IDigest prehash = Ed25519.CreatePrehash();
+        private readonly byte[] context;
+
+        private bool forSigning;
+        private Ed25519PrivateKeyParameters privateKey;
+        private Ed25519PublicKeyParameters publicKey;
+
+        public Ed25519phSigner(byte[] context)
+        {
+            this.context = Arrays.Clone(context);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Ed25519ph"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+
+            if (forSigning)
+            {
+                // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters?
+
+                this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+                this.publicKey = privateKey.GeneratePublicKey();
+            }
+            else
+            {
+                this.privateKey = null;
+                this.publicKey = (Ed25519PublicKeyParameters)parameters;
+            }
+
+            Reset();
+        }
+
+        public virtual void Update(byte b)
+        {
+            prehash.Update(b);
+        }
+
+        public virtual void BlockUpdate(byte[] buf, int off, int len)
+        {
+            prehash.BlockUpdate(buf, off, len);
+        }
+
+        public virtual byte[] GenerateSignature()
+        {
+            if (!forSigning)
+                throw new InvalidOperationException("Ed25519phSigner not initialised for signature generation.");
+
+            byte[] msg = new byte[Ed25519.PrehashSize];
+            if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
+                throw new InvalidOperationException("Prehash digest failed");
+
+            byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+            privateKey.Sign(Ed25519.Algorithm.Ed25519ph, publicKey, context, msg, 0, Ed25519.PrehashSize, signature, 0);
+            return signature;
+        }
+
+        public virtual bool VerifySignature(byte[] signature)
+        {
+            if (forSigning)
+                throw new InvalidOperationException("Ed25519phSigner not initialised for verification");
+
+            byte[] pk = publicKey.GetEncoded();
+            return Ed25519.VerifyPrehash(signature, 0, pk, 0, context, prehash);
+        }
+
+        public void Reset()
+        {
+            prehash.Reset();
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/Ed448Signer.cs b/crypto/src/crypto/signers/Ed448Signer.cs
new file mode 100644
index 000000000..c01d84b4d
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed448Signer.cs
@@ -0,0 +1,130 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class Ed448Signer
+        : ISigner
+    {
+        private readonly Buffer buffer = new Buffer();
+        private readonly byte[] context;
+
+        private bool forSigning;
+        private Ed448PrivateKeyParameters privateKey;
+        private Ed448PublicKeyParameters publicKey;
+
+        public Ed448Signer(byte[] context)
+        {
+            this.context = Arrays.Clone(context);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Ed448"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+
+            if (forSigning)
+            {
+                // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+                this.privateKey = (Ed448PrivateKeyParameters)parameters;
+                this.publicKey = privateKey.GeneratePublicKey();
+            }
+            else
+            {
+                this.privateKey = null;
+                this.publicKey = (Ed448PublicKeyParameters)parameters;
+            }
+
+            Reset();
+        }
+
+        public virtual void Update(byte b)
+        {
+            buffer.WriteByte(b);
+        }
+
+        public virtual void BlockUpdate(byte[] buf, int off, int len)
+        {
+            buffer.Write(buf, off, len);
+        }
+
+        public virtual byte[] GenerateSignature()
+        {
+            if (!forSigning)
+                throw new InvalidOperationException("Ed448Signer not initialised for signature generation.");
+
+            return buffer.GenerateSignature(privateKey, publicKey, context);
+        }
+
+        public virtual bool VerifySignature(byte[] signature)
+        {
+            if (forSigning)
+                throw new InvalidOperationException("Ed448Signer not initialised for verification");
+
+            return buffer.VerifySignature(publicKey, context, signature);
+        }
+
+        public virtual void Reset()
+        {
+            buffer.Reset();
+        }
+
+        private class Buffer : MemoryStream
+        {
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal byte[] GenerateSignature(Ed448PrivateKeyParameters privateKey, Ed448PublicKeyParameters publicKey, byte[] ctx)
+            {
+#if PORTABLE
+                byte[] buf = ToArray();
+                int count = buf.Length;
+#else
+                byte[] buf = GetBuffer();
+                int count = (int)Position;
+#endif
+                byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
+                privateKey.Sign(Ed448.Algorithm.Ed448, publicKey, ctx, buf, 0, count, signature, 0);
+                Reset();
+                return signature;
+            }
+
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal bool VerifySignature(Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] signature)
+            {
+#if PORTABLE
+                byte[] buf = ToArray();
+                int count = buf.Length;
+#else
+                byte[] buf = GetBuffer();
+                int count = (int)Position;
+#endif
+                byte[] pk = publicKey.GetEncoded();
+                bool result = Ed448.Verify(signature, 0, pk, 0, ctx, buf, 0, count);
+                Reset();
+                return result;
+            }
+
+            [MethodImpl(MethodImplOptions.Synchronized)]
+            internal void Reset()
+            {
+#if PORTABLE
+                this.Position = 0L;
+
+                // TODO Clear using Write method
+#else
+                Array.Clear(GetBuffer(), 0, (int)Position);
+#endif
+                this.Position = 0L;
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/Ed448phSigner.cs b/crypto/src/crypto/signers/Ed448phSigner.cs
new file mode 100644
index 000000000..50d0a0154
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed448phSigner.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class Ed448phSigner
+        : ISigner
+    {
+        private readonly IXof prehash = Ed448.CreatePrehash();
+        private readonly byte[] context;
+
+        private bool forSigning;
+        private Ed448PrivateKeyParameters privateKey;
+        private Ed448PublicKeyParameters publicKey;
+
+        public Ed448phSigner(byte[] context)
+        {
+            this.context = Arrays.Clone(context);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Ed448ph"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+
+            if (forSigning)
+            {
+                // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters?
+
+                this.privateKey = (Ed448PrivateKeyParameters)parameters;
+                this.publicKey = privateKey.GeneratePublicKey();
+            }
+            else
+            {
+                this.privateKey = null;
+                this.publicKey = (Ed448PublicKeyParameters)parameters;
+            }
+
+            Reset();
+        }
+
+        public virtual void Update(byte b)
+        {
+            prehash.Update(b);
+        }
+
+        public virtual void BlockUpdate(byte[] buf, int off, int len)
+        {
+            prehash.BlockUpdate(buf, off, len);
+        }
+
+        public virtual byte[] GenerateSignature()
+        {
+            if (!forSigning)
+                throw new InvalidOperationException("Ed448phSigner not initialised for signature generation.");
+
+            byte[] msg = new byte[Ed448.PrehashSize];
+            if (Ed448.PrehashSize != prehash.DoFinal(msg, 0, Ed448.PrehashSize))
+                throw new InvalidOperationException("Prehash digest failed");
+
+            byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
+            privateKey.Sign(Ed448.Algorithm.Ed448ph, publicKey, context, msg, 0, Ed448.PrehashSize, signature, 0);
+            return signature;
+        }
+
+        public virtual bool VerifySignature(byte[] signature)
+        {
+            if (forSigning)
+                throw new InvalidOperationException("Ed448phSigner not initialised for verification");
+
+            byte[] pk = publicKey.GetEncoded();
+            return Ed448.VerifyPrehash(signature, 0, pk, 0, context, prehash);
+        }
+
+        public void Reset()
+        {
+            prehash.Reset();
+        }
+    }
+}
diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs
index adb56ca9b..0b0e649d7 100644
--- a/crypto/src/math/ec/rfc8032/Ed25519.cs
+++ b/crypto/src/math/ec/rfc8032/Ed25519.cs
@@ -12,6 +12,13 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
 {
     public abstract class Ed25519
     {
+        public enum Algorithm
+        {
+            Ed25519 = 0,
+            Ed25519ctx = 1,
+            Ed25519ph = 2,
+        }
+
         private const long M28L = 0x0FFFFFFFL;
         private const long M32L = 0xFFFFFFFFL;
 
diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs
index c1c0788a7..f12aa0807 100644
--- a/crypto/src/math/ec/rfc8032/Ed448.cs
+++ b/crypto/src/math/ec/rfc8032/Ed448.cs
@@ -12,6 +12,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
 {
     public abstract class Ed448
     {
+        public enum Algorithm
+        {
+            Ed448 = 0,
+            Ed448ph = 1,
+        }
+
         private const ulong M26UL = 0x03FFFFFFUL;
         private const ulong M28UL = 0x0FFFFFFFUL;
 
diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
index a349a11d2..69eb3fa67 100644
--- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.Sec;
@@ -22,59 +23,68 @@ namespace Org.BouncyCastle.Pkcs
         }
 
         public static PrivateKeyInfo CreatePrivateKeyInfo(
-            AsymmetricKeyParameter key)
+            AsymmetricKeyParameter privateKey)
         {
-            if (key == null)
-                throw new ArgumentNullException("key");
-            if (!key.IsPrivate)
-                throw new ArgumentException("Public key passed - private key expected", "key");
+            return CreatePrivateKeyInfo(privateKey, null);
+        }
+
+        /**
+         * Create a PrivateKeyInfo representation of a private key with attributes.
+         *
+         * @param privateKey the key to be encoded into the info object.
+         * @param attributes the set of attributes to be included.
+         * @return the appropriate PrivateKeyInfo
+         * @throws java.io.IOException on an error encoding the key
+         */
+        public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter privateKey, Asn1Set attributes)
+        {
+            if (privateKey == null)
+                throw new ArgumentNullException("privateKey");
+            if (!privateKey.IsPrivate)
+                throw new ArgumentException("Public key passed - private key expected", "privateKey");
 
-            if (key is ElGamalPrivateKeyParameters)
+            if (privateKey is ElGamalPrivateKeyParameters)
             {
-                ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key;
+                ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)privateKey;
+                ElGamalParameters egp = _key.Parameters;
                 return new PrivateKeyInfo(
-                    new AlgorithmIdentifier(
-                    OiwObjectIdentifiers.ElGamalAlgorithm,
-                    new ElGamalParameter(
-                    _key.Parameters.P,
-                    _key.Parameters.G).ToAsn1Object()),
-                    new DerInteger(_key.X));
+                    new AlgorithmIdentifier(OiwObjectIdentifiers.ElGamalAlgorithm, new ElGamalParameter(egp.P, egp.G).ToAsn1Object()),
+                    new DerInteger(_key.X),
+                    attributes);
             }
 
-            if (key is DsaPrivateKeyParameters)
+            if (privateKey is DsaPrivateKeyParameters)
             {
-                DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key;
+                DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)privateKey;
+                DsaParameters dp = _key.Parameters;
                 return new PrivateKeyInfo(
-                    new AlgorithmIdentifier(
-                    X9ObjectIdentifiers.IdDsa,
-                    new DsaParameter(
-                    _key.Parameters.P,
-                    _key.Parameters.Q,
-                    _key.Parameters.G).ToAsn1Object()),
-                    new DerInteger(_key.X));
+                    new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, new DsaParameter(dp.P, dp.Q, dp.G).ToAsn1Object()),
+                    new DerInteger(_key.X),
+                    attributes);
             }
 
-            if (key is DHPrivateKeyParameters)
+            if (privateKey is DHPrivateKeyParameters)
             {
-                DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key;
+                DHPrivateKeyParameters _key = (DHPrivateKeyParameters)privateKey;
 
                 DHParameter p = new DHParameter(
                     _key.Parameters.P, _key.Parameters.G, _key.Parameters.L);
 
                 return new PrivateKeyInfo(
                     new AlgorithmIdentifier(_key.AlgorithmOid, p.ToAsn1Object()),
-                    new DerInteger(_key.X));
+                    new DerInteger(_key.X),
+                    attributes);
             }
 
-            if (key is RsaKeyParameters)
+            if (privateKey is RsaKeyParameters)
             {
                 AlgorithmIdentifier algID = new AlgorithmIdentifier(
                     PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
 
                 RsaPrivateKeyStructure keyStruct;
-                if (key is RsaPrivateCrtKeyParameters)
+                if (privateKey is RsaPrivateCrtKeyParameters)
                 {
-                    RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
+                    RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)privateKey;
 
                     keyStruct = new RsaPrivateKeyStructure(
                         _key.Modulus,
@@ -88,7 +98,7 @@ namespace Org.BouncyCastle.Pkcs
                 }
                 else
                 {
-                    RsaKeyParameters _key = (RsaKeyParameters) key;
+                    RsaKeyParameters _key = (RsaKeyParameters) privateKey;
 
                     keyStruct = new RsaPrivateKeyStructure(
                         _key.Modulus,
@@ -101,12 +111,12 @@ namespace Org.BouncyCastle.Pkcs
                         BigInteger.Zero);
                 }
 
-                return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
+                return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object(), attributes);
             }
 
-            if (key is ECPrivateKeyParameters)
+            if (privateKey is ECPrivateKeyParameters)
             {
-                ECPrivateKeyParameters priv = (ECPrivateKeyParameters)key;
+                ECPrivateKeyParameters priv = (ECPrivateKeyParameters)privateKey;
                 ECDomainParameters dp = priv.Parameters;
                 int orderBitLength = dp.N.BitLength;
 
@@ -145,12 +155,12 @@ namespace Org.BouncyCastle.Pkcs
                     algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962);
                 }
 
-                return new PrivateKeyInfo(algID, ec);
+                return new PrivateKeyInfo(algID, ec, attributes);
             }
 
-            if (key is Gost3410PrivateKeyParameters)
+            if (privateKey is Gost3410PrivateKeyParameters)
             {
-                Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key;
+                Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)privateKey;
 
                 if (_key.PublicKeyParamSet == null)
                     throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
@@ -170,10 +180,42 @@ namespace Org.BouncyCastle.Pkcs
                     CryptoProObjectIdentifiers.GostR3410x94,
                     algParams.ToAsn1Object());
 
-                return new PrivateKeyInfo(algID, new DerOctetString(keyBytes));
+                return new PrivateKeyInfo(algID, new DerOctetString(keyBytes), attributes);
+            }
+
+            if (privateKey is X448PrivateKeyParameters)
+            {
+                X448PrivateKeyParameters key = (X448PrivateKeyParameters)privateKey;
+
+                return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
+                    new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
+            }
+
+            if (privateKey is X25519PrivateKeyParameters)
+            {
+                X25519PrivateKeyParameters key = (X25519PrivateKeyParameters)privateKey;
+
+                return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
+                    new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
+            }
+
+            if (privateKey is Ed448PrivateKeyParameters)
+            {
+                Ed448PrivateKeyParameters key = (Ed448PrivateKeyParameters)privateKey;
+
+                return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
+                    new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
+            }
+
+            if (privateKey is Ed25519PrivateKeyParameters)
+            {
+                Ed25519PrivateKeyParameters key = (Ed25519PrivateKeyParameters)privateKey;
+
+                return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
+                    new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded());
             }
 
-            throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(key));
+            throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(privateKey));
         }
 
         public static PrivateKeyInfo CreatePrivateKeyInfo(
diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs
index 12d427c8c..26d1628cc 100644
--- a/crypto/src/security/AgreementUtilities.cs
+++ b/crypto/src/security/AgreementUtilities.cs
@@ -1,6 +1,7 @@
 using System.Collections;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Agreement;
@@ -27,7 +28,10 @@ namespace Org.BouncyCastle.Security
             algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF";
 			algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF";
 			algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF";
-		}
+
+            algorithms[EdECObjectIdentifiers.id_X25519.Id] = "X25519";
+            algorithms[EdECObjectIdentifiers.id_X448.Id] = "X448";
+        }
 
         public static IBasicAgreement GetBasicAgreement(
 			DerObjectIdentifier oid)
@@ -38,15 +42,9 @@ namespace Org.BouncyCastle.Security
 		public static IBasicAgreement GetBasicAgreement(
 			string algorithm)
 		{
-			string upper = Platform.ToUpperInvariant(algorithm);
-			string mechanism = (string) algorithms[upper];
-
-			if (mechanism == null)
-			{
-				mechanism = upper;
-			}
+            string mechanism = GetMechanism(algorithm);
 
-			if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN")
+            if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN")
 				return new DHBasicAgreement();
 
 			if (mechanism == "ECDH")
@@ -72,15 +70,9 @@ namespace Org.BouncyCastle.Security
 			string agreeAlgorithm,
 			string wrapAlgorithm)
 		{
-			string upper = Platform.ToUpperInvariant(agreeAlgorithm);
-			string mechanism = (string) algorithms[upper];
+            string mechanism = GetMechanism(agreeAlgorithm);
 
-			if (mechanism == null)
-			{
-				mechanism = upper;
-			}
-
-			// 'DHWITHSHA1KDF' retained for backward compatibility
+            // 'DHWITHSHA1KDF' retained for backward compatibility
 			if (mechanism == "DHWITHSHA1KDF" || mechanism == "ECDHWITHSHA1KDF")
 				return new ECDHWithKdfBasicAgreement(
 					wrapAlgorithm,
@@ -96,10 +88,37 @@ namespace Org.BouncyCastle.Security
 			throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised.");
 		}
 
+        public static IRawAgreement GetRawAgreement(
+            DerObjectIdentifier oid)
+        {
+            return GetRawAgreement(oid.Id);
+        }
+
+        public static IRawAgreement GetRawAgreement(
+            string algorithm)
+        {
+            string mechanism = GetMechanism(algorithm);
+
+            if (mechanism == "X25519")
+                return new X25519Agreement();
+
+            if (mechanism == "X448")
+                return new X448Agreement();
+
+            throw new SecurityUtilityException("Raw Agreement " + algorithm + " not recognised.");
+        }
+
 		public static string GetAlgorithmName(
 			DerObjectIdentifier oid)
 		{
-			return (string) algorithms[oid.Id];
+			return (string)algorithms[oid.Id];
 		}
+
+        private static string GetMechanism(string algorithm)
+        {
+            string upper = Platform.ToUpperInvariant(algorithm);
+            string mechanism = (string)algorithms[upper];
+            return mechanism == null ? upper : mechanism;
+        }
 	}
 }
diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs
index db1929c16..26ddb396b 100644
--- a/crypto/src/security/GeneratorUtilities.cs
+++ b/crypto/src/security/GeneratorUtilities.cs
@@ -2,6 +2,7 @@ using System.Collections;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Iana;
 using Org.BouncyCastle.Asn1.Kisa;
 using Org.BouncyCastle.Asn1.Nist;
@@ -180,12 +181,23 @@ namespace Org.BouncyCastle.Security
             AddKpgAlgorithm("ECGOST3410",
                 "ECGOST-3410",
                 "GOST-3410-2001");
+            AddKpgAlgorithm("Ed25519",
+                "Ed25519ctx",
+                "Ed25519ph",
+                EdECObjectIdentifiers.id_Ed25519);
+            AddKpgAlgorithm("Ed448",
+                "Ed448ph",
+                EdECObjectIdentifiers.id_Ed448);
             AddKpgAlgorithm("ELGAMAL");
             AddKpgAlgorithm("GOST3410",
                 "GOST-3410",
                 "GOST-3410-94");
             AddKpgAlgorithm("RSA",
                 "1.2.840.113549.1.1.1");
+            AddKpgAlgorithm("X25519",
+                EdECObjectIdentifiers.id_X25519);
+            AddKpgAlgorithm("X448",
+                EdECObjectIdentifiers.id_X448);
 
             AddDefaultKeySizeEntries(64, "DES");
             AddDefaultKeySizeEntries(80, "SKIPJACK");
@@ -216,11 +228,11 @@ namespace Org.BouncyCastle.Security
             string			canonicalName,
             params object[] aliases)
         {
-            kgAlgorithms[canonicalName] = canonicalName;
+            kgAlgorithms[Platform.ToUpperInvariant(canonicalName)] = canonicalName;
 
             foreach (object alias in aliases)
             {
-                kgAlgorithms[alias.ToString()] = canonicalName;
+                kgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = canonicalName;
             }
         }
 
@@ -228,11 +240,11 @@ namespace Org.BouncyCastle.Security
             string			canonicalName,
             params object[] aliases)
         {
-            kpgAlgorithms[canonicalName] = canonicalName;
+            kpgAlgorithms[Platform.ToUpperInvariant(canonicalName)] = canonicalName;
 
             foreach (object alias in aliases)
             {
-                kpgAlgorithms[alias.ToString()] = canonicalName;
+                kpgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = canonicalName;
             }
         }
 
@@ -248,7 +260,7 @@ namespace Org.BouncyCastle.Security
 
             foreach (object alias in aliases)
             {
-                kgAlgorithms[alias.ToString()] = mainName;
+                kgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = mainName;
             }
         }
 
@@ -318,6 +330,12 @@ namespace Org.BouncyCastle.Security
             if (Platform.StartsWith(canonicalName, "EC"))
                 return new ECKeyPairGenerator(canonicalName);
 
+            if (canonicalName == "Ed25519")
+                return new Ed25519KeyPairGenerator();
+
+            if (canonicalName == "Ed448")
+                return new Ed448KeyPairGenerator();
+
             if (canonicalName == "ELGAMAL")
                 return new ElGamalKeyPairGenerator();
 
@@ -327,6 +345,12 @@ namespace Org.BouncyCastle.Security
             if (canonicalName == "RSA")
                 return new RsaKeyPairGenerator();
 
+            if (canonicalName == "X25519")
+                return new X25519KeyPairGenerator();
+
+            if (canonicalName == "X448")
+                return new X448KeyPairGenerator();
+
             throw new SecurityUtilityException("KeyPairGenerator " + algorithm
                 + " (" + canonicalName + ") not supported.");
         }
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index c9e19cc7d..0b07d0659 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -5,6 +5,7 @@ using System.Text;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.Sec;
@@ -170,12 +171,37 @@ namespace Org.BouncyCastle.Security
 
 				return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
 			}
+            else if (algOid.Equals(EdECObjectIdentifiers.id_X25519))
+            {
+                return new X25519PrivateKeyParameters(GetRawKey(keyInfo, X25519PrivateKeyParameters.KeySize), 0);
+            }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_X448))
+            {
+                return new X448PrivateKeyParameters(GetRawKey(keyInfo, X448PrivateKeyParameters.KeySize), 0);
+            }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519))
+            {
+                return new Ed25519PrivateKeyParameters(GetRawKey(keyInfo, Ed25519PrivateKeyParameters.KeySize), 0);
+            }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448))
+            {
+                return new Ed448PrivateKeyParameters(GetRawKey(keyInfo, Ed448PrivateKeyParameters.KeySize), 0);
+            }
             else
             {
-                throw new SecurityUtilityException("algorithm identifier in key not recognised");
+                throw new SecurityUtilityException("algorithm identifier in private key not recognised");
             }
         }
 
+        private static byte[] GetRawKey(PrivateKeyInfo keyInfo, int expectedSize)
+        {
+            byte[] result = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
+            if (expectedSize != result.Length)
+                throw new SecurityUtilityException("private key encoding has incorrect length");
+
+            return result;
+        }
+
         public static AsymmetricKeyParameter DecryptKey(
             char[]					passPhrase,
             EncryptedPrivateKeyInfo	encInfo)
diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs
index f1b28b774..e39748e45 100644
--- a/crypto/src/security/PublicKeyFactory.cs
+++ b/crypto/src/security/PublicKeyFactory.cs
@@ -5,6 +5,7 @@ using System.Text;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.Sec;
@@ -218,12 +219,41 @@ namespace Org.BouncyCastle.Security
 
                 return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
             }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_X25519))
+            {
+                return new X25519PublicKeyParameters(GetRawKey(keyInfo, X25519PublicKeyParameters.KeySize), 0);
+            }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_X448))
+            {
+                return new X448PublicKeyParameters(GetRawKey(keyInfo, X448PublicKeyParameters.KeySize), 0);
+            }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519))
+            {
+                return new Ed25519PublicKeyParameters(GetRawKey(keyInfo, Ed25519PublicKeyParameters.KeySize), 0);
+            }
+            else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448))
+            {
+                return new Ed448PublicKeyParameters(GetRawKey(keyInfo, Ed448PublicKeyParameters.KeySize), 0);
+            }
             else
             {
-                throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid);
+                throw new SecurityUtilityException("algorithm identifier in public key not recognised: " + algOid);
             }
         }
 
+        private static byte[] GetRawKey(SubjectPublicKeyInfo keyInfo, int expectedSize)
+        {
+            /*
+             * TODO[RFC 8422]
+             * - Require keyInfo.Algorithm.Parameters == null?
+             */
+            byte[] result = keyInfo.PublicKeyData.GetOctets();
+            if (expectedSize != result.Length)
+                throw new SecurityUtilityException("public key encoding has incorrect length");
+
+            return result;
+        }
+
         private static bool IsPkcsDHParam(Asn1Sequence seq)
         {
             if (seq.Count == 2)
diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index 44281503a..a9045ae6e 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -4,6 +4,7 @@ using System.IO;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
@@ -231,7 +232,13 @@ namespace Org.BouncyCastle.Security
             algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
             algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
 
-
+            algorithms["ED25519"] = "Ed25519";
+            algorithms[EdECObjectIdentifiers.id_Ed25519.Id] = "Ed25519";
+            algorithms["ED25519CTX"] = "Ed25519ctx";
+            algorithms["ED25519PH"] = "Ed25519ph";
+            algorithms["ED448"] = "Ed448";
+            algorithms[EdECObjectIdentifiers.id_Ed448.Id] = "Ed448";
+            algorithms["ED448PH"] = "Ed448ph";
 
             oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
             oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
@@ -264,6 +271,9 @@ namespace Org.BouncyCastle.Security
 
             oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
             oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+
+            oids["Ed25519"] = EdECObjectIdentifiers.id_Ed25519;
+            oids["Ed448"] = EdECObjectIdentifiers.id_Ed448;
         }
 
         /// <summary>
@@ -361,6 +371,30 @@ namespace Org.BouncyCastle.Security
             if (mechanism == null)
                 mechanism = algorithm;
 
+            if (Platform.StartsWith(mechanism, "Ed"))
+            {
+                if (mechanism.Equals("Ed25519"))
+                {
+                    return new Ed25519Signer();
+                }
+                if (mechanism.Equals("Ed25519ctx"))
+                {
+                    return new Ed25519ctxSigner(Arrays.EmptyBytes);
+                }
+                if (mechanism.Equals("Ed25519ph"))
+                {
+                    return new Ed25519phSigner(Arrays.EmptyBytes);
+                }
+                if (mechanism.Equals("Ed448"))
+                {
+                    return new Ed448Signer(Arrays.EmptyBytes);
+                }
+                if (mechanism.Equals("Ed448ph"))
+                {
+                    return new Ed448phSigner(Arrays.EmptyBytes);
+                }
+            }
+
             if (mechanism.Equals("RSA"))
             {
                 return (new RsaDigestSigner(new NullDigest(), (AlgorithmIdentifier)null));
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
index 7614321d4..fca5da3f5 100644
--- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -3,6 +3,7 @@ using System;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
@@ -26,20 +27,20 @@ namespace Org.BouncyCastle.X509
         /// <summary>
         /// Create a Subject Public Key Info object for a given public key.
         /// </summary>
-        /// <param name="key">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
+        /// <param name="publicKey">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
         /// <returns>A subject public key info object.</returns>
         /// <exception cref="Exception">Throw exception if object provided is not one of the above.</exception>
         public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
-            AsymmetricKeyParameter key)
+            AsymmetricKeyParameter publicKey)
         {
-            if (key == null)
-                throw new ArgumentNullException("key");
-            if (key.IsPrivate)
-                throw new ArgumentException("Private key passed - public key expected.", "key");
+            if (publicKey == null)
+                throw new ArgumentNullException("publicKey");
+            if (publicKey.IsPrivate)
+                throw new ArgumentException("Private key passed - public key expected.", "publicKey");
 
-            if (key is ElGamalPublicKeyParameters)
+            if (publicKey is ElGamalPublicKeyParameters)
             {
-                ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+                ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)publicKey;
                 ElGamalParameters kp = _key.Parameters;
 
                 SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
@@ -51,9 +52,9 @@ namespace Org.BouncyCastle.X509
                 return info;
             }
 
-            if (key is DsaPublicKeyParameters)
+            if (publicKey is DsaPublicKeyParameters)
             {
-                DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
+                DsaPublicKeyParameters _key = (DsaPublicKeyParameters) publicKey;
                 DsaParameters kp = _key.Parameters;
                 Asn1Encodable ae = kp == null
                     ?	null
@@ -64,9 +65,9 @@ namespace Org.BouncyCastle.X509
                     new DerInteger(_key.Y));
             }
 
-            if (key is DHPublicKeyParameters)
+            if (publicKey is DHPublicKeyParameters)
             {
-                DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
+                DHPublicKeyParameters _key = (DHPublicKeyParameters) publicKey;
                 DHParameters kp = _key.Parameters;
 
                 SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
@@ -78,9 +79,9 @@ namespace Org.BouncyCastle.X509
                 return info;
             } // End of DH
 
-            if (key is RsaKeyParameters)
+            if (publicKey is RsaKeyParameters)
             {
-                RsaKeyParameters _key = (RsaKeyParameters) key;
+                RsaKeyParameters _key = (RsaKeyParameters) publicKey;
 
                 SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
                     new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
@@ -89,9 +90,9 @@ namespace Org.BouncyCastle.X509
                 return info;
             } // End of RSA.
 
-            if (key is ECPublicKeyParameters)
+            if (publicKey is ECPublicKeyParameters)
             {
-                ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
+                ECPublicKeyParameters _key = (ECPublicKeyParameters) publicKey;
 
                 if (_key.AlgorithmName == "ECGOST3410")
                 {
@@ -139,9 +140,9 @@ namespace Org.BouncyCastle.X509
                 }
             } // End of EC
 
-            if (key is Gost3410PublicKeyParameters)
+            if (publicKey is Gost3410PublicKeyParameters)
             {
-                Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+                Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) publicKey;
 
                 if (_key.PublicKeyParamSet == null)
                     throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
@@ -164,7 +165,35 @@ namespace Org.BouncyCastle.X509
                 return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
             }
 
-            throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(key));
+            if (publicKey is X448PublicKeyParameters)
+            {
+                X448PublicKeyParameters key = (X448PublicKeyParameters)publicKey;
+
+                return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.GetEncoded());
+            }
+
+            if (publicKey is X25519PublicKeyParameters)
+            {
+                X25519PublicKeyParameters key = (X25519PublicKeyParameters)publicKey;
+
+                return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.GetEncoded());
+            }
+
+            if (publicKey is Ed448PublicKeyParameters)
+            {
+                Ed448PublicKeyParameters key = (Ed448PublicKeyParameters)publicKey;
+
+                return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), key.GetEncoded());
+            }
+
+            if (publicKey is Ed25519PublicKeyParameters)
+            {
+                Ed25519PublicKeyParameters key = (Ed25519PublicKeyParameters)publicKey;
+
+                return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), key.GetEncoded());
+            }
+
+            throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(publicKey));
         }
 
         private static void ExtractBytes(
diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj
index 5f0e7af57..bb046c2b6 100644
--- a/crypto/test/UnitTests.csproj
+++ b/crypto/test/UnitTests.csproj
@@ -101,6 +101,7 @@
     <Compile Include="src\asn1\test\ParseTest.cs" />
     <Compile Include="src\asn1\test\ParsingTest.cs" />
     <Compile Include="src\asn1\test\PersonalDataUnitTest.cs" />
+    <Compile Include="src\asn1\test\PrivateKeyInfoTest.cs" />
     <Compile Include="src\asn1\test\ProcurationSyntaxUnitTest.cs" />
     <Compile Include="src\asn1\test\ProfessionInfoUnitTest.cs" />
     <Compile Include="src\asn1\test\QCStatementUnitTest.cs" />
@@ -186,6 +187,8 @@
     <Compile Include="src\crypto\test\ECIESTest.cs" />
     <Compile Include="src\crypto\test\ECNRTest.cs" />
     <Compile Include="src\crypto\test\ECTest.cs" />
+    <Compile Include="src\crypto\test\Ed25519Test.cs" />
+    <Compile Include="src\crypto\test\Ed448Test.cs" />
     <Compile Include="src\crypto\test\ElGamalTest.cs" />
     <Compile Include="src\crypto\test\EqualsHashCodeTest.cs" />
     <Compile Include="src\crypto\test\GCMTest.cs" />
@@ -284,6 +287,8 @@
     <Compile Include="src\crypto\test\VMPCMacTest.cs" />
     <Compile Include="src\crypto\test\VMPCTest.cs" />
     <Compile Include="src\crypto\test\WhirlpoolDigestTest.cs" />
+    <Compile Include="src\crypto\test\X25519Test.cs" />
+    <Compile Include="src\crypto\test\X448Test.cs" />
     <Compile Include="src\crypto\test\X931SignerTest.cs" />
     <Compile Include="src\crypto\test\XSalsa20Test.cs" />
     <Compile Include="src\crypto\test\XTEATest.cs" />
diff --git a/crypto/test/src/asn1/test/PrivateKeyInfoTest.cs b/crypto/test/src/asn1/test/PrivateKeyInfoTest.cs
new file mode 100644
index 000000000..eb17a54c3
--- /dev/null
+++ b/crypto/test/src/asn1/test/PrivateKeyInfoTest.cs
@@ -0,0 +1,60 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class PrivateKeyInfoTest
+        : SimpleTest
+    {
+        private static readonly byte[] priv = Base64.Decode(
+            "MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC");
+
+        private static readonly byte[] privWithPub = Base64.Decode(
+            "MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC" +
+            "oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB" +
+            "Z9w7lshQhqowtrbLDFw4rXAxZuE=");
+
+        public override string Name
+        {
+            get { return "PrivateKeyInfoTest"; }
+        }
+
+        public override void PerformTest()
+        {
+            PrivateKeyInfo privInfo1 = PrivateKeyInfo.GetInstance(priv);
+
+            IsTrue(!privInfo1.HasPublicKey);
+
+            PrivateKeyInfo privInfo2 = new PrivateKeyInfo(privInfo1.PrivateKeyAlgorithm, privInfo1.ParsePrivateKey());
+
+            IsTrue("enc 1 failed", AreEqual(priv, privInfo2.GetEncoded()));
+
+            privInfo1 = PrivateKeyInfo.GetInstance(privWithPub);
+
+            IsTrue(privInfo1.HasPublicKey);
+
+            privInfo2 = new PrivateKeyInfo(privInfo1.PrivateKeyAlgorithm, privInfo1.ParsePrivateKey(), privInfo1.Attributes, privInfo1.PublicKeyData.GetOctets());
+
+            IsTrue("enc 2 failed", AreEqual(privWithPub, privInfo2.GetEncoded()));
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new PrivateKeyInfoTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/RegressionTest.cs b/crypto/test/src/asn1/test/RegressionTest.cs
index 873ab4396..eeca9ccd0 100644
--- a/crypto/test/src/asn1/test/RegressionTest.cs
+++ b/crypto/test/src/asn1/test/RegressionTest.cs
@@ -51,6 +51,7 @@ namespace Org.BouncyCastle.Asn1.Tests
 			new Pkcs10Test(),
             new Pkcs12Test(),
 			new PkiFailureInfoTest(),
+            new PrivateKeyInfoTest(),
 			new ProcurationSyntaxUnitTest(),
 			new ProfessionInfoUnitTest(),
 			new QCStatementUnitTest(),
diff --git a/crypto/test/src/crypto/test/Ed25519Test.cs b/crypto/test/src/crypto/test/Ed25519Test.cs
new file mode 100644
index 000000000..82e36d991
--- /dev/null
+++ b/crypto/test/src/crypto/test/Ed25519Test.cs
@@ -0,0 +1,111 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+    public class Ed25519Test
+        : SimpleTest
+    {
+        private static readonly SecureRandom Random = new SecureRandom();
+
+        public override string Name
+        {
+            get { return "Ed25519"; }
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new Ed25519Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                DoTestConsistency(Ed25519.Algorithm.Ed25519, null);
+
+                byte[] context = RandomContext(Random.NextInt() & 255);
+                DoTestConsistency(Ed25519.Algorithm.Ed25519ctx, context);
+                DoTestConsistency(Ed25519.Algorithm.Ed25519ph, context);
+            }
+        }
+
+        private ISigner CreateSigner(Ed25519.Algorithm algorithm, byte[] context)
+        {
+            switch (algorithm)
+            {
+            case Ed25519.Algorithm.Ed25519:
+                return new Ed25519Signer();
+            case Ed25519.Algorithm.Ed25519ctx:
+                return new Ed25519ctxSigner(context);
+            case Ed25519.Algorithm.Ed25519ph:
+                return new Ed25519phSigner(context);
+            default:
+                throw new ArgumentException("algorithm");
+            }
+        }
+
+        private byte[] RandomContext(int length)
+        {
+            byte[] context = new byte[length];
+            Random.NextBytes(context);
+            return context;
+        }
+
+        private void DoTestConsistency(Ed25519.Algorithm algorithm, byte[] context)
+        {
+            Ed25519KeyPairGenerator kpg = new Ed25519KeyPairGenerator();
+            kpg.Init(new Ed25519KeyGenerationParameters(Random));
+
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+            Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters)kp.Private;
+            Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters)kp.Public;
+
+            byte[] msg = new byte[Random.NextInt() & 255];
+            Random.NextBytes(msg);
+
+            ISigner signer = CreateSigner(algorithm, context);
+            signer.Init(true, privateKey);
+            signer.BlockUpdate(msg, 0, msg.Length);
+            byte[] signature = signer.GenerateSignature();
+
+            ISigner verifier = CreateSigner(algorithm, context);
+            verifier.Init(false, publicKey);
+            verifier.BlockUpdate(msg, 0, msg.Length);
+            bool shouldVerify = verifier.VerifySignature(signature);
+
+            if (!shouldVerify)
+            {
+                Fail("Ed25519(" + algorithm + ") signature failed to verify");
+            }
+
+            signature[Random.Next() % signature.Length] ^= (byte)(1 << (Random.NextInt() & 7));
+
+            verifier.Init(false, publicKey);
+            verifier.BlockUpdate(msg, 0, msg.Length);
+            bool shouldNotVerify = verifier.VerifySignature(signature);
+
+            if (shouldNotVerify)
+            {
+                Fail("Ed25519(" + algorithm + ") bad signature incorrectly verified");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/Ed448Test.cs b/crypto/test/src/crypto/test/Ed448Test.cs
new file mode 100644
index 000000000..b035f554e
--- /dev/null
+++ b/crypto/test/src/crypto/test/Ed448Test.cs
@@ -0,0 +1,107 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class Ed448Test
+        : SimpleTest
+    {
+        private static readonly SecureRandom Random = new SecureRandom();
+
+        public override string Name
+        {
+            get { return "Ed448"; }
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new Ed448Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                byte[] context = RandomContext(Random.NextInt() & 255);
+                DoTestConsistency(Ed448.Algorithm.Ed448, context);
+                DoTestConsistency(Ed448.Algorithm.Ed448ph, context);
+            }
+        }
+
+        private ISigner CreateSigner(Ed448.Algorithm algorithm, byte[] context)
+        {
+            switch (algorithm)
+            {
+                case Ed448.Algorithm.Ed448:
+                    return new Ed448Signer(context);
+                case Ed448.Algorithm.Ed448ph:
+                    return new Ed448phSigner(context);
+                default:
+                    throw new ArgumentException("algorithm");
+            }
+        }
+
+        private byte[] RandomContext(int length)
+        {
+            byte[] context = new byte[length];
+            Random.NextBytes(context);
+            return context;
+        }
+
+        private void DoTestConsistency(Ed448.Algorithm algorithm, byte[] context)
+        {
+            Ed448KeyPairGenerator kpg = new Ed448KeyPairGenerator();
+            kpg.Init(new Ed448KeyGenerationParameters(Random));
+
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+            Ed448PrivateKeyParameters privateKey = (Ed448PrivateKeyParameters)kp.Private;
+            Ed448PublicKeyParameters publicKey = (Ed448PublicKeyParameters)kp.Public;
+
+            byte[] msg = new byte[Random.NextInt() & 255];
+            Random.NextBytes(msg);
+
+            ISigner signer = CreateSigner(algorithm, context);
+            signer.Init(true, privateKey);
+            signer.BlockUpdate(msg, 0, msg.Length);
+            byte[] signature = signer.GenerateSignature();
+
+            ISigner verifier = CreateSigner(algorithm, context);
+            verifier.Init(false, publicKey);
+            verifier.BlockUpdate(msg, 0, msg.Length);
+            bool shouldVerify = verifier.VerifySignature(signature);
+
+            if (!shouldVerify)
+            {
+                Fail("Ed448(" + algorithm + ") signature failed to verify");
+            }
+
+            signature[Random.Next() % signature.Length] ^= (byte)(1 << (Random.NextInt() & 7));
+
+            verifier.Init(false, publicKey);
+            verifier.BlockUpdate(msg, 0, msg.Length);
+            bool shouldNotVerify = verifier.VerifySignature(signature);
+
+            if (shouldNotVerify)
+            {
+                Fail("Ed448(" + algorithm + ") bad signature incorrectly verified");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs
index 13fe23ecc..18aa62d97 100644
--- a/crypto/test/src/crypto/test/RegressionTest.cs
+++ b/crypto/test/src/crypto/test/RegressionTest.cs
@@ -133,6 +133,10 @@ namespace Org.BouncyCastle.Crypto.Tests
             new SM2EngineTest(),
             new SM2KeyExchangeTest(),
             new SM2SignerTest(),
+            new X25519Test(),
+            new X448Test(),
+            new Ed25519Test(),
+            new Ed448Test(),
         };
 
         public static void Main(string[] args)
diff --git a/crypto/test/src/crypto/test/X25519Test.cs b/crypto/test/src/crypto/test/X25519Test.cs
new file mode 100644
index 000000000..29466e0c6
--- /dev/null
+++ b/crypto/test/src/crypto/test/X25519Test.cs
@@ -0,0 +1,69 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class X25519Test
+		: SimpleTest
+    {
+        private static readonly SecureRandom Random = new SecureRandom();
+
+        public override string Name
+        {
+            get { return "X25519"; }
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new X25519Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                DoTestAgreement();
+            }
+        }
+
+        private void DoTestAgreement()
+        {
+            IAsymmetricCipherKeyPairGenerator kpGen = new X25519KeyPairGenerator();
+            kpGen.Init(new X25519KeyGenerationParameters(Random));
+
+            AsymmetricCipherKeyPair kpA = kpGen.GenerateKeyPair();
+            AsymmetricCipherKeyPair kpB = kpGen.GenerateKeyPair();
+
+            X25519Agreement agreeA = new X25519Agreement();
+            agreeA.Init(kpA.Private);
+            byte[] secretA = new byte[agreeA.AgreementSize];
+            agreeA.CalculateAgreement(kpB.Public, secretA, 0);
+
+            X25519Agreement agreeB = new X25519Agreement();
+            agreeB.Init(kpB.Private);
+            byte[] secretB = new byte[agreeB.AgreementSize];
+            agreeB.CalculateAgreement(kpA.Public, secretB, 0);
+
+            if (!AreEqual(secretA, secretB))
+            {
+                Fail("X25519 agreement failed");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/X448Test.cs b/crypto/test/src/crypto/test/X448Test.cs
new file mode 100644
index 000000000..5d4b14b63
--- /dev/null
+++ b/crypto/test/src/crypto/test/X448Test.cs
@@ -0,0 +1,69 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class X448Test
+        : SimpleTest
+    {
+        private static readonly SecureRandom Random = new SecureRandom();
+
+        public override string Name
+        {
+            get { return "X448"; }
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new X448Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                DoTestAgreement();
+            }
+        }
+
+        private void DoTestAgreement()
+        {
+            IAsymmetricCipherKeyPairGenerator kpGen = new X448KeyPairGenerator();
+            kpGen.Init(new X448KeyGenerationParameters(Random));
+
+            AsymmetricCipherKeyPair kpA = kpGen.GenerateKeyPair();
+            AsymmetricCipherKeyPair kpB = kpGen.GenerateKeyPair();
+
+            X448Agreement agreeA = new X448Agreement();
+            agreeA.Init(kpA.Private);
+            byte[] secretA = new byte[agreeA.AgreementSize];
+            agreeA.CalculateAgreement(kpB.Public, secretA, 0);
+
+            X448Agreement agreeB = new X448Agreement();
+            agreeB.Init(kpB.Private);
+            byte[] secretB = new byte[agreeB.AgreementSize];
+            agreeB.CalculateAgreement(kpA.Public, secretB, 0);
+
+            if (!AreEqual(secretA, secretB))
+            {
+                Fail("X448 agreement failed");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs
index 5a42daeae..8a61609af 100644
--- a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs
+++ b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs
@@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
 				Random.NextBytes(sk);
                 Ed25519.GeneratePublicKey(sk, 0, pk, 0);
 
-                int mLen = Random.Next() & 255;
+                int mLen = Random.NextInt() & 255;
 
                 Ed25519.Sign(sk, 0, m, 0, mLen, sig1, 0);
                 Ed25519.Sign(sk, 0, pk, 0, m, 0, mLen, sig2, 0);
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
         {
             byte[] sk = new byte[Ed25519.SecretKeySize];
             byte[] pk = new byte[Ed25519.PublicKeySize];
-            byte[] ctx = new byte[Random.Next() & 7];
+            byte[] ctx = new byte[Random.NextInt() & 7];
             byte[] m = new byte[255];
             byte[] sig1 = new byte[Ed25519.SignatureSize];
             byte[] sig2 = new byte[Ed25519.SignatureSize];
@@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
                 Random.NextBytes(sk);
                 Ed25519.GeneratePublicKey(sk, 0, pk, 0);
 
-                int mLen = Random.Next() & 255;
+                int mLen = Random.NextInt() & 255;
 
                 Ed25519.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0);
                 Ed25519.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0);
@@ -95,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
         {
             byte[] sk = new byte[Ed25519.SecretKeySize];
             byte[] pk = new byte[Ed25519.PublicKeySize];
-            byte[] ctx = new byte[Random.Next() & 7];
+            byte[] ctx = new byte[Random.NextInt() & 7];
             byte[] m = new byte[255];
             byte[] ph = new byte[Ed25519.PrehashSize];
             byte[] sig1 = new byte[Ed25519.SignatureSize];
@@ -109,7 +109,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
                 Random.NextBytes(sk);
                 Ed25519.GeneratePublicKey(sk, 0, pk, 0);
 
-                int mLen = Random.Next() & 255;
+                int mLen = Random.NextInt() & 255;
 
                 IDigest prehash = Ed25519.CreatePrehash();
                 prehash.BlockUpdate(m, 0, mLen);
diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs
index 826f76345..cc8e82de0 100644
--- a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs
+++ b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs
@@ -25,7 +25,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
         {
             byte[] sk = new byte[Ed448.SecretKeySize];
             byte[] pk = new byte[Ed448.PublicKeySize];
-            byte[] ctx = new byte[Random.Next() & 7];
+            byte[] ctx = new byte[Random.NextInt() & 7];
             byte[] m = new byte[255];
             byte[] sig1 = new byte[Ed448.SignatureSize];
             byte[] sig2 = new byte[Ed448.SignatureSize];
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
                 Random.NextBytes(sk);
                 Ed448.GeneratePublicKey(sk, 0, pk, 0);
 
-                int mLen = Random.Next() & 255;
+                int mLen = Random.NextInt() & 255;
 
                 Ed448.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0);
                 Ed448.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0);
@@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
         {
             byte[] sk = new byte[Ed448.SecretKeySize];
             byte[] pk = new byte[Ed448.PublicKeySize];
-            byte[] ctx = new byte[Random.Next() & 7];
+            byte[] ctx = new byte[Random.NextInt() & 7];
             byte[] m = new byte[255];
             byte[] ph = new byte[Ed448.PrehashSize];
             byte[] sig1 = new byte[Ed448.SignatureSize];
@@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests
                 Random.NextBytes(sk);
                 Ed448.GeneratePublicKey(sk, 0, pk, 0);
 
-                int mLen = Random.Next() & 255;
+                int mLen = Random.NextInt() & 255;
 
                 IXof prehash = Ed448.CreatePrehash();
                 prehash.BlockUpdate(m, 0, mLen);
diff --git a/crypto/test/src/security/test/TestSignerUtil.cs b/crypto/test/src/security/test/TestSignerUtil.cs
index f2ee4b048..dc3c1c81b 100644
--- a/crypto/test/src/security/test/TestSignerUtil.cs
+++ b/crypto/test/src/security/test/TestSignerUtil.cs
@@ -94,6 +94,14 @@ namespace Org.BouncyCastle.Security.Tests
 
             AsymmetricCipherKeyPair ecGostPair = ecGostKpg.GenerateKeyPair();
 
+            IAsymmetricCipherKeyPairGenerator ed25519Kpg = GeneratorUtilities.GetKeyPairGenerator("Ed25519");
+            ed25519Kpg.Init(new Ed25519KeyGenerationParameters(new SecureRandom()));
+            AsymmetricCipherKeyPair ed25519Pair = ed25519Kpg.GenerateKeyPair();
+
+            IAsymmetricCipherKeyPairGenerator ed448Kpg = GeneratorUtilities.GetKeyPairGenerator("Ed448");
+            ed448Kpg.Init(new Ed448KeyGenerationParameters(new SecureRandom()));
+            AsymmetricCipherKeyPair ed448Pair = ed448Kpg.GenerateKeyPair();
+
             //
             // GOST3410 parameters
             //
@@ -147,6 +155,16 @@ namespace Org.BouncyCastle.Security.Tests
                     signParams = ecGostPair.Private;
                     verifyParams = ecGostPair.Public;
                 }
+                else if (cipherName == "ED25519")
+                {
+                    signParams = ed25519Pair.Private;
+                    verifyParams = ed25519Pair.Public;
+                }
+                else if (cipherName == "ED448")
+                {
+                    signParams = ed448Pair.Private;
+                    verifyParams = ed448Pair.Public;
+                }
                 else if (cipherName == "GOST3410")
                 {
                     signParams = gostPair.Private;