diff --git a/core/java/src/net/i2p/crypto/Blinding.java b/core/java/src/net/i2p/crypto/Blinding.java
index 661ba88fe3473ddd3a9541e5b6da67d2dfa26009..22be07a009b8b4eb389279b4c050112eaa7a6da2 100644
--- a/core/java/src/net/i2p/crypto/Blinding.java
+++ b/core/java/src/net/i2p/crypto/Blinding.java
@@ -19,6 +19,7 @@ import net.i2p.data.SigningPublicKey;
 public final class Blinding {
 
     private static final SigType TYPE = SigType.EdDSA_SHA512_Ed25519;
+    private static final SigType TYPER = SigType.RedDSA_SHA512_Ed25519;
 
     private Blinding() {}
 
@@ -26,17 +27,19 @@ public final class Blinding {
      *  Only for SigType EdDSA_SHA512_Ed25519.
      *
      *  @param key must be SigType EdDSA_SHA512_Ed25519
-     *  @param alpha the secret data
-     *  @throws UnsupportedOperationException unless supported
+     *  @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() != TYPE)
+        if (key.getType() != TYPE || alpha.getType() != TYPER)
             throw new UnsupportedOperationException();
         try {
             EdDSAPublicKey jk = SigUtil.toJavaEdDSAKey(key);
             EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
             EdDSAPublicKey bjk = EdDSABlinding.blind(jk, ajk);
-            return SigUtil.fromJavaKey(bjk, TYPE);
+            return SigUtil.fromJavaKey(bjk, TYPER);
         } catch (GeneralSecurityException gse) {
             throw new IllegalArgumentException(gse);
         }
@@ -46,17 +49,19 @@ public final class Blinding {
      *  Only for SigType EdDSA_SHA512_Ed25519.
      *
      *  @param key must be SigType EdDSA_SHA512_Ed25519
-     *  @param alpha the secret data
-     *  @throws UnsupportedOperationException unless supported
+     *  @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() != TYPE)
+        if (key.getType() != TYPE || alpha.getType() != TYPER)
             throw new UnsupportedOperationException();
         try {
             EdDSAPrivateKey jk = SigUtil.toJavaEdDSAKey(key);
             EdDSAPrivateKey ajk = SigUtil.toJavaEdDSAKey(alpha);
             EdDSAPrivateKey bjk = EdDSABlinding.blind(jk, ajk);
-            return SigUtil.fromJavaKey(bjk, TYPE);
+            return SigUtil.fromJavaKey(bjk, TYPER);
         } catch (GeneralSecurityException gse) {
             throw new IllegalArgumentException(gse);
         }
@@ -65,12 +70,14 @@ public final class Blinding {
     /**
      *  Only for SigType EdDSA_SHA512_Ed25519.
      *
-     *  @param key must be SigType EdDSA_SHA512_Ed25519
-     *  @param alpha the secret data
-     *  @throws UnsupportedOperationException unless supported
+     *  @param key must be SigType RedDSA_SHA512_Ed25519
+     *  @param alpha must be SigType RedDSA_SHA512_Ed25519
+     *  @return SigType EdDSA_SHA512_Ed25519
+     *  @throws UnsupportedOperationException unless supported SigTypes
+     *  @throws IllegalArgumentException on bad inputs
      */
     public static SigningPrivateKey unblind(SigningPrivateKey key, SigningPrivateKey alpha) {
-        if (key.getType() != TYPE && alpha.getType() != TYPE)
+        if (key.getType() != TYPER || alpha.getType() != TYPER)
             throw new UnsupportedOperationException();
         try {
             EdDSAPrivateKey bjk = SigUtil.toJavaEdDSAKey(key);
@@ -81,22 +88,39 @@ public final class Blinding {
             throw new IllegalArgumentException(gse);
         }
     }
+
 /******
     public static void main(String args[]) throws Exception {
-        SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(TYPE);
+        net.i2p.data.SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(TYPE);
         SigningPublicKey pub = (SigningPublicKey) keys[0];
         SigningPrivateKey priv = (SigningPrivateKey) keys[1];
-        byte[] b = new byte[32];
+        byte[] b = new byte[64];
         net.i2p.I2PAppContext.getGlobalContext().random().nextBytes(b);
-        Hash h = new Hash(b);
-        SigningPublicKey bpub = blind(pub, h);
-        SigningPrivateKey bpriv = blind(priv, h);
-        SigningPublicKey bpub2 = bpriv.toPublic();
-        boolean ok = bpub2.equals(bpub);
-        System.out.println("Blinding test passed?   " + ok);
-        SigningPrivateKey priv2 = unblind(bpriv, h);
-        ok = priv2.equals(priv);
-        System.out.println("Unblinding test passed? " + ok);
+        b = EdDSABlinding.reduce(b);
+        SigningPrivateKey alpha = new SigningPrivateKey(TYPER, b);
+        SigningPublicKey bpub = null;
+        try {
+            bpub = blind(pub, alpha);
+        } catch (Exception e) {
+            System.out.println("Blinding pubkey test failed");
+            e.printStackTrace();
+        }
+        SigningPrivateKey bpriv = null;
+        try {
+            bpriv = blind(priv, alpha);
+        } catch (Exception e) {
+            System.out.println("Blinding privkey test failed");
+            e.printStackTrace();
+        }
+        if (bpub != null && bpriv != null) {
+            SigningPublicKey bpub2 = bpriv.toPublic();
+            boolean ok = bpub2.equals(bpub);
+            System.out.println("Blinding test passed?   " + ok);
+            // unimplemented
+            //SigningPrivateKey priv2 = unblind(bpriv, alpha);
+            //ok = priv2.equals(priv);
+            //System.out.println("Unblinding test passed? " + ok);
+        }
     }
 ******/
 }
diff --git a/core/java/src/net/i2p/crypto/SigType.java b/core/java/src/net/i2p/crypto/SigType.java
index 5da9e22b0475adf6b20817d229328ed0f11b270c..7832c38604d084aef4cc597ba22bc8ea1fd7c88f 100644
--- a/core/java/src/net/i2p/crypto/SigType.java
+++ b/core/java/src/net/i2p/crypto/SigType.java
@@ -65,6 +65,17 @@ public enum SigType {
     EdDSA_SHA512_Ed25519ph(8, 32, 32, 64, 64, SigAlgo.EdDSA, "SHA-512", "NonewithEdDSA",
                            EdDSANamedCurveTable.getByName("ed25519-sha-512"), "1.3.101.101", "0.9.25"),
 
+    // 9 and 10 reserved for GOST - see proposal 134
+
+    /**
+     *  Blinded version of EdDSA, use for encrypted LS2
+     *  Pubkey 32 bytes; privkey 32 bytes; hash 64 bytes; sig 64 bytes
+     *
+     *  @since 0.9.39
+     */
+    RedDSA_SHA512_Ed25519(11, 32, 32, 64, 64, SigAlgo.EdDSA, "SHA-512", "SHA512withEdDSA",
+                          EdDSANamedCurveTable.getByName("ed25519-sha-512"), "1.3.101.101", "0.9.39"),
+
     ;
 
     // TESTING....................
@@ -295,6 +306,8 @@ public enum SigType {
                 return EdDSA_SHA512_Ed25519;
             if (uc.equals("EDDSA_SHA512_ED25519PH"))
                 return EdDSA_SHA512_Ed25519ph;
+            if (uc.equals("REDDSA_SHA512_ED25519"))
+                return RedDSA_SHA512_Ed25519;
             return valueOf(uc);
         } catch (IllegalArgumentException iae) {
             try {
diff --git a/core/java/src/net/i2p/crypto/SigUtil.java b/core/java/src/net/i2p/crypto/SigUtil.java
index b19f63bef9db93587d7cdb971a9b4e161ee9c5e6..98376e8cba35ef4eb3ea4ff61b0876cf3a915fe2 100644
--- a/core/java/src/net/i2p/crypto/SigUtil.java
+++ b/core/java/src/net/i2p/crypto/SigUtil.java
@@ -369,8 +369,16 @@ public final class SigUtil {
     private static EdDSAPrivateKey cvtToJavaEdDSAKey(SigningPrivateKey pk)
                               throws GeneralSecurityException {
         try {
-            return new EdDSAPrivateKey(new EdDSAPrivateKeySpec(
-                pk.getData(), (EdDSAParameterSpec) pk.getType().getParams()));
+            EdDSAParameterSpec paramspec = (EdDSAParameterSpec) pk.getType().getParams();
+            EdDSAPrivateKeySpec pkspec;
+            SigType type = pk.getType();
+            if (type == SigType.EdDSA_SHA512_Ed25519)
+                pkspec = new EdDSAPrivateKeySpec(pk.getData(), paramspec);
+            else if (type == SigType.RedDSA_SHA512_Ed25519)
+                pkspec = new EdDSAPrivateKeySpec(pk.getData(), null, paramspec);
+            else
+                throw new InvalidKeyException();
+            return new EdDSAPrivateKey(pkspec);
         } catch (IllegalArgumentException iae) {
             throw new InvalidKeyException(iae);
         }
@@ -389,7 +397,14 @@ public final class SigUtil {
      */
     public static SigningPrivateKey fromJavaKey(EdDSAPrivateKey pk, SigType type)
             throws GeneralSecurityException {
-        return new SigningPrivateKey(type, pk.getSeed());
+        byte[] data;
+        if (type == SigType.EdDSA_SHA512_Ed25519)
+            data = pk.getSeed();
+        else if (type == SigType.RedDSA_SHA512_Ed25519)
+            data = pk.geta();
+        else
+            throw new IllegalArgumentException();
+        return new SigningPrivateKey(type, data);
     }
 
     public static DSAPublicKey toJavaDSAKey(SigningPublicKey pk)
diff --git a/core/java/src/net/i2p/crypto/eddsa/EdDSABlinding.java b/core/java/src/net/i2p/crypto/eddsa/EdDSABlinding.java
index 5e4ccb457e3563c841db3299c7a0f1725abe6343..1438b7037855b87d5eb8feeb6bbec340c650a50c 100644
--- a/core/java/src/net/i2p/crypto/eddsa/EdDSABlinding.java
+++ b/core/java/src/net/i2p/crypto/eddsa/EdDSABlinding.java
@@ -1,5 +1,16 @@
 package net.i2p.crypto.eddsa;
 
+import java.math.BigInteger;
+
+import net.i2p.crypto.eddsa.math.Field;
+import net.i2p.crypto.eddsa.math.GroupElement;
+import net.i2p.crypto.eddsa.math.ScalarOps;
+import net.i2p.crypto.eddsa.math.bigint.BigIntegerLittleEndianEncoding;
+import net.i2p.crypto.eddsa.math.bigint.BigIntegerScalarOps;
+import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
+import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
+import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
+
 /**
  * Utilities for Blinding EdDSA keys.
  * PRELIMINARY - Subject to change - see proposal 123
@@ -8,6 +19,10 @@ package net.i2p.crypto.eddsa;
  */
 public final class EdDSABlinding {
 
+    private static final byte[] ONE = Utils.hexToBytes("0100000000000000000000000000000000000000000000000000000000000000");
+    private static final Field FIELD = EdDSANamedCurveTable.getByName("Ed25519").getCurve().getField();
+    private static final BigInteger ORDER = new BigInteger("2").pow(252).add(new BigInteger("27742317777372353535851937790883648493"));
+
     private EdDSABlinding() {}
 
     /**
@@ -18,8 +33,19 @@ public final class EdDSABlinding {
      *  @throws UnsupportedOperationException unless supported
      */
     public static EdDSAPublicKey blind(EdDSAPublicKey key, EdDSAPrivateKey alpha) {
-        // TODO, test only
-        return key;
+        GroupElement a = key.getA();
+        GroupElement aa = alpha.getA();
+        // Add the two public keys together.
+        GroupElement d = a.add(aa.toCached());
+        EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(d, key.getParams());
+        EdDSAPublicKey rv = new EdDSAPublicKey(pubKey);
+        //System.out.println("Adding pubkey\n" +
+        //   net.i2p.util.HexDump.dump(key.getAbyte()) +
+        //   "\nplus privkey\n" +
+        //   net.i2p.util.HexDump.dump(alpha.geta()) +
+        //   "\nequals\n" +
+        //   net.i2p.util.HexDump.dump(rv.getAbyte()));
+        return rv;
     }
 
     /**
@@ -30,19 +56,46 @@ public final class EdDSABlinding {
      *  @throws UnsupportedOperationException unless supported
      */
     public static EdDSAPrivateKey blind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
-        // TODO, test only
-        return key;
+        byte[] a = key.geta();
+        byte[] aa = alpha.geta();
+        Field f = key.getParams().getCurve().getField();
+        BigIntegerLittleEndianEncoding enc = new BigIntegerLittleEndianEncoding();
+        enc.setField(f);
+        ScalarOps sc = new BigIntegerScalarOps(f, ORDER);
+        // Add the two private keys together.
+        // just for now, since we don't have a pure add.
+        byte[] d = sc.multiplyAndAdd(ONE, a, aa);
+        //System.out.println("Adding privkeys\n" +
+        //   net.i2p.util.HexDump.dump(a) +
+        //   "\nplus\n" +
+        //   net.i2p.util.HexDump.dump(aa) +
+        //   "\nequals\n" +
+        //   net.i2p.util.HexDump.dump(d));
+        EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(d, null, key.getParams());
+        return new EdDSAPrivateKey(privKey);
     }
 
     /**
-     *  Only for SigType EdDSA_SHA512_Ed25519.
+     *  Unimplemented, probably not needed except for testing.
      *
      *  @param key must be SigType EdDSA_SHA512_Ed25519
      *  @param alpha generated from hash of secret data
      *  @throws UnsupportedOperationException unless supported
      */
     public static EdDSAPrivateKey unblind(EdDSAPrivateKey key, EdDSAPrivateKey alpha) {
-        // TODO, test only
-        return key;
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     *  Use to generate alpha
+     *
+     *  @param b 64 bytes little endian of random
+     *  @return 32 bytes little endian mod l
+     */
+    public static byte[] reduce(byte[] b) {
+        if (b.length != 64)
+            throw new IllegalArgumentException();
+        ScalarOps sc = new BigIntegerScalarOps(FIELD, ORDER);
+        return sc.reduce(b);
     }
 }
diff --git a/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java b/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java
index 2143eeab2e8ce634d87b7420cd399fb922dcbde9..1f583037aad12951a64699713cbf349c4fd9505b 100644
--- a/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java
+++ b/core/java/src/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java
@@ -83,11 +83,41 @@ public class EdDSAPrivateKeySpec implements KeySpec {
         A = spec.getB().scalarMultiply(a);
     }
 
+    /**
+     *  No validation of any parameters other than a.
+     *  getSeed() and getH() will return null if this constructor is used.
+     *
+     *  @param a must be "clamped" (for Ed) or reduced mod l (for Red)
+     *  @param A if null, will be derived from a.
+     *  @throws IllegalArgumentException if a not clamped or reduced
+     *  @since 0.9.39
+     */
+    public EdDSAPrivateKeySpec(byte[] a, GroupElement A, EdDSAParameterSpec spec) {
+        this(null, null, a, A, spec);
+    }
+
+    /**
+     *  No validation of any parameters other than a.
+     *
+     *  @param seed may be null
+     *  @param h may be null
+     *  @param a must be "clamped" (for Ed) or reduced mod l (for Red)
+     *  @param A if null, will be derived from a.
+     *  @throws IllegalArgumentException if a not clamped or reduced
+     */
     public EdDSAPrivateKeySpec(byte[] seed, byte[] h, byte[] a, GroupElement A, EdDSAParameterSpec spec) {
+/**
+        // TODO if we move RedDSA to a different spec
+        int bd8m1 = (spec.getCurve().getField().getb() / 8) - 1;
+        if ((a[0] & 0x07) != 0 ||
+            (a[bd8m1] & 0xc0) != 0x40)
+            throw new IllegalArgumentException("a not clamped: a[0]=0x" + Integer.toString(a[0] & 0xff, 16) +
+                                                             " a[31]=0x" + Integer.toString(a[31] & 0xff, 16));
+**/
         this.seed = seed;
         this.h = h;
         this.a = a;
-        this.A = A;
+        this.A = (A != null) ? A : spec.getB().scalarMultiply(a);
         this.spec = spec;
     }