diff --git a/core/java/src/net/i2p/crypto/Blinding.java b/core/java/src/net/i2p/crypto/Blinding.java
index d9a423cbf95e3e334cc21ec6658345b88e8d7bb0..6ef788d324acdb8f94f1bb8f34381bdedb0cb9fc 100644
--- a/core/java/src/net/i2p/crypto/Blinding.java
+++ b/core/java/src/net/i2p/crypto/Blinding.java
@@ -39,16 +39,18 @@ public final class Blinding {
     private Blinding() {}
 
     /**
-     *  Only for SigType EdDSA_SHA512_Ed25519.
+     *  Only for SigTypes EdDSA_SHA512_Ed25519 and RedDSA_SHA512_Ed25519.
      *
-     *  @param key must be SigType EdDSA_SHA512_Ed25519
+     *  @param key must be SigType EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
      *  @param alpha must be SigType RedDSA_SHA512_Ed25519
      *  @return SigType RedDSA_SHA512_Ed25519
      *  @throws UnsupportedOperationException unless supported SigTypes
      *  @throws IllegalArgumentException on bad inputs
      */
     public static SigningPublicKey blind(SigningPublicKey key, SigningPrivateKey alpha) {
-        if (key.getType() != TYPE || alpha.getType() != TYPER)
+        SigType type = key.getType();
+        if ((type != TYPE && type != TYPER) ||
+            alpha.getType() != TYPER)
             throw new UnsupportedOperationException();
         try {
             EdDSAPublicKey jk = SigUtil.toJavaEdDSAKey(key);
@@ -61,16 +63,18 @@ public final class Blinding {
     }
 
     /**
-     *  Only for SigType EdDSA_SHA512_Ed25519.
+     *  Only for SigTypes EdDSA_SHA512_Ed25519 and RedDSA_SHA512_Ed25519.
      *
-     *  @param key must be SigType EdDSA_SHA512_Ed25519
+     *  @param key must be SigType EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
      *  @param alpha must be SigType RedDSA_SHA512_Ed25519
      *  @return SigType RedDSA_SHA512_Ed25519
      *  @throws UnsupportedOperationException unless supported SigTypes
      *  @throws IllegalArgumentException on bad inputs
      */
     public static SigningPrivateKey blind(SigningPrivateKey key, SigningPrivateKey alpha) {
-        if (key.getType() != TYPE || alpha.getType() != TYPER)
+        SigType type = key.getType();
+        if ((type != TYPE && type != TYPER) ||
+            alpha.getType() != TYPER)
             throw new UnsupportedOperationException();
         try {
             EdDSAPrivateKey jk = SigUtil.toJavaEdDSAKey(key);
@@ -122,9 +126,9 @@ public final class Blinding {
 
     /**
      *  Generate alpha for the given time.
-     *  Only for SigType EdDSA_SHA512_Ed25519.
+     *  Only for SigType EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519.
      *
-     *  @param dest spk must be SigType EdDSA_SHA512_Ed25519
+     *  @param dest spk must be SigType EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
      *  @param secret may be null or zero-length
      *  @param now for what time?
      *  @return SigType RedDSA_SHA512_Ed25519
diff --git a/core/java/src/net/i2p/crypto/KeyGenerator.java b/core/java/src/net/i2p/crypto/KeyGenerator.java
index 21b839a6e2515bd4bd4287084f3d26fa0262773d..d7f1b6135a456c5b0df9e76ac5c951beb7e188db 100644
--- a/core/java/src/net/i2p/crypto/KeyGenerator.java
+++ b/core/java/src/net/i2p/crypto/KeyGenerator.java
@@ -35,6 +35,7 @@ import com.southernstorm.noise.crypto.x25519.Curve25519;
 import net.i2p.I2PAppContext;
 import net.i2p.crypto.eddsa.EdDSAPrivateKey;
 import net.i2p.crypto.eddsa.EdDSAPublicKey;
+import net.i2p.crypto.eddsa.RedKeyPairGenerator;
 import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
 import net.i2p.crypto.provider.I2PProvider;
 import net.i2p.data.Hash;
@@ -289,7 +290,11 @@ public final class KeyGenerator {
             return generateSigningKeys();
         java.security.KeyPair kp;
         if (type.getBaseAlgorithm() == SigAlgo.EdDSA) {
-            net.i2p.crypto.eddsa.KeyPairGenerator kpg = new net.i2p.crypto.eddsa.KeyPairGenerator();
+            net.i2p.crypto.eddsa.KeyPairGenerator kpg;
+            if (type == SigType.RedDSA_SHA512_Ed25519)
+                kpg = new RedKeyPairGenerator();
+            else
+                kpg = new net.i2p.crypto.eddsa.KeyPairGenerator();
             kpg.initialize(type.getParams(), _context.random());
             kp = kpg.generateKeyPair();
         } else {
diff --git a/core/java/src/net/i2p/crypto/SU3File.java b/core/java/src/net/i2p/crypto/SU3File.java
index 65b2ee542d056bea797c330e2e98f003f270b29b..70da7e9c4365c136f6a8a5c5691d437cbd3be562 100644
--- a/core/java/src/net/i2p/crypto/SU3File.java
+++ b/core/java/src/net/i2p/crypto/SU3File.java
@@ -673,7 +673,8 @@ public class SU3File {
         for (SigType t : EnumSet.allOf(SigType.class)) {
             if (!t.isAvailable())
                 continue;
-            if (t == SigType.EdDSA_SHA512_Ed25519)
+            if (t == SigType.EdDSA_SHA512_Ed25519 ||
+                t == SigType.RedDSA_SHA512_Ed25519)
                 continue; // not supported by keytool, and does double hashing right now
             buf.append("      ").append(t).append("\t(code: ").append(t.getCode()).append(')');
             if (t.getCode() == DEFAULT_SIG_CODE)
diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java
index 8703c2945d3ded88c5f19ae066ec2e17c71d851a..36d88e193253e3fa9f73219ffc389f4a2e108f78 100644
--- a/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java
+++ b/core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java
@@ -71,7 +71,7 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey {
     }
 
     /**
-     * Returns the public key in its canonical encoding.
+     * Returns the private key in its canonical encoding.
      *<p>
      * This implements the following specs:
      *<ul><li>
diff --git a/core/java/src/net/i2p/crypto/eddsa/KeyPairGenerator.java b/core/java/src/net/i2p/crypto/eddsa/KeyPairGenerator.java
index f42f272d06ef51ba3bf1b26f9723db42a822190a..3480355cf34cc46704c51a026cf068ca7c7bab60 100644
--- a/core/java/src/net/i2p/crypto/eddsa/KeyPairGenerator.java
+++ b/core/java/src/net/i2p/crypto/eddsa/KeyPairGenerator.java
@@ -21,11 +21,11 @@ import net.i2p.util.RandomSource;
  *
  *  @since 0.9.15
  */
-public final class KeyPairGenerator extends KeyPairGeneratorSpi {
-    private static final int DEFAULT_KEYSIZE = 256;
-    private EdDSAParameterSpec edParams;
-    private SecureRandom random;
-    private boolean initialized;
+public class KeyPairGenerator extends KeyPairGeneratorSpi {
+    protected static final int DEFAULT_KEYSIZE = 256;
+    protected EdDSAParameterSpec edParams;
+    protected SecureRandom random;
+    protected boolean initialized;
 
     private static final Hashtable<Integer, AlgorithmParameterSpec> edParameters;
 
diff --git a/core/java/src/net/i2p/crypto/eddsa/RedKeyPairGenerator.java b/core/java/src/net/i2p/crypto/eddsa/RedKeyPairGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..de0e532af5570f393efa7a5ecc0b6c9f2b4a7fb7
--- /dev/null
+++ b/core/java/src/net/i2p/crypto/eddsa/RedKeyPairGenerator.java
@@ -0,0 +1,31 @@
+package net.i2p.crypto.eddsa;
+
+import java.security.KeyPair;
+
+import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
+import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
+import net.i2p.util.RandomSource;
+
+/**
+ *  Default keysize is 256 (Ed25519)
+ *
+ *  @since 0.9.39
+ */
+public final class RedKeyPairGenerator extends KeyPairGenerator {
+
+    @Override
+    public KeyPair generateKeyPair() {
+        if (!initialized)
+            initialize(DEFAULT_KEYSIZE, RandomSource.getInstance());
+
+        // 64 bytes
+        byte[] seed = new byte[edParams.getCurve().getField().getb()/4];
+        random.nextBytes(seed);
+        byte[] b = EdDSABlinding.reduce(seed);
+
+        EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(b, null, edParams);
+        EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(privKey.getA(), edParams);
+
+        return new KeyPair(new EdDSAPublicKey(pubKey), new EdDSAPrivateKey(privKey));
+    }
+}
diff --git a/core/java/src/net/i2p/data/EncryptedLeaseSet.java b/core/java/src/net/i2p/data/EncryptedLeaseSet.java
index f83f9c85b798736b23fd3308c62063f43cdb6eb2..0d70b9010ed9f6df3497284bd208617c56c0f298 100644
--- a/core/java/src/net/i2p/data/EncryptedLeaseSet.java
+++ b/core/java/src/net/i2p/data/EncryptedLeaseSet.java
@@ -82,7 +82,7 @@ public class EncryptedLeaseSet extends LeaseSet2 {
     /**
      * Overridden to set the blinded key
      *
-     * @param dest non-null, must be EdDSA_SHA512_Ed25519
+     * @param dest non-null, must be EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
      * @throws IllegalStateException if already signed
      * @throws IllegalArgumentException if not EdDSA
      */
@@ -90,7 +90,9 @@ public class EncryptedLeaseSet extends LeaseSet2 {
     public void setDestination(Destination dest) {
         super.setDestination(dest);
         SigningPublicKey spk = dest.getSigningPublicKey();
-        if (spk.getType() != SigType.EdDSA_SHA512_Ed25519)
+        SigType type = spk.getType();
+        if (type != SigType.EdDSA_SHA512_Ed25519 &&
+            type != SigType.RedDSA_SHA512_Ed25519)
             throw new IllegalArgumentException();
         SigningPublicKey bpk = blind();
         if (_signingKey == null)