diff --git a/router/java/src/com/southernstorm/noise/protocol/Curve25519DHState.java b/router/java/src/com/southernstorm/noise/protocol/Curve25519DHState.java
index 62524153ac2cadd1356f9cb50c57c2d6aa4314ff..1a3d7fb014cd04ad29b4ce321749c02edce6c906 100644
--- a/router/java/src/com/southernstorm/noise/protocol/Curve25519DHState.java
+++ b/router/java/src/com/southernstorm/noise/protocol/Curve25519DHState.java
@@ -107,12 +107,35 @@ class Curve25519DHState implements DHState, Cloneable {
 		System.arraycopy(privateKey, 0, key, offset, 32);
 	}
 
+	/**
+	 * @deprecated use setKeys()
+	 */
+	@Deprecated
 	@Override
 	public void setPrivateKey(byte[] key, int offset) {
 		System.arraycopy(key, offset, privateKey, 0, 32);
 		Curve25519.eval(publicKey, 0, privateKey, null);
 		mode = 0x03;
 	}
+	
+	/**
+	 * Sets the private and public keys for this object.
+	 * I2P for efficiency, since setPrivateKey() calculates the public key
+	 * and overwrites it.
+	 * Does NOT check that the two keys match.
+	 * 
+	 * @param privkey The buffer containing the private key.
+	 * @param privoffset The first offset in the buffer that contains the key.
+	 * @param pubkey The buffer containing the public key.
+	 * @param puboffset The first offset in the buffer that contains the key.
+	 * @since 0.9.48
+	 */
+	@Override
+	public void setKeys(byte[] privkey, int privoffset, byte[] pubkey, int puboffset) {
+		System.arraycopy(privkey, privoffset, privateKey, 0, 32);
+		System.arraycopy(pubkey, puboffset, publicKey, 0, 32);
+		mode = 0x03;
+	}
 
 	@Override
 	public void setToNullPublicKey() {
diff --git a/router/java/src/com/southernstorm/noise/protocol/DHState.java b/router/java/src/com/southernstorm/noise/protocol/DHState.java
index a3a9cdef5b6c95933a3e6d9e648807fdf7ddc9c6..62b135a3f78ce94a435d3c9b137a3258ef4414c5 100644
--- a/router/java/src/com/southernstorm/noise/protocol/DHState.java
+++ b/router/java/src/com/southernstorm/noise/protocol/DHState.java
@@ -95,8 +95,25 @@ public interface DHState extends Destroyable, Cloneable {
 	 * 
 	 * If this object previously held only a public key, then
 	 * this function will change it into a key pair.
+	 * 
+	 * @deprecated use setKeys()
 	 */
+	@Deprecated
 	void setPrivateKey(byte[] key, int offset);
+	
+	/**
+	 * Sets the private and public keys for this object.
+	 * I2P for efficiency, since setPrivateKey() calculates the public key
+	 * and overwrites it.
+	 * Does NOT check that the two keys match.
+	 * 
+	 * @param privkey The buffer containing the private key.
+	 * @param privoffset The first offset in the buffer that contains the key.
+	 * @param pubkey The buffer containing the private key.
+	 * @param puboffset The first offset in the buffer that contains the key.
+	 * @since 0.9.48
+	 */
+	void setKeys(byte[] privkey, int privoffset, byte[] pubkey, int puboffset);
 
 	/**
 	 * Sets this object to the null public key and clears the private key.
diff --git a/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java b/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java
index bd5085667f34b4599fc41c43207986c8f089ebe4..48ed6b717a54fa2b5290a19c566d8190972e9177 100644
--- a/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java
+++ b/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java
@@ -380,8 +380,8 @@ public class BuildRequestRecord {
             try {
                 KeyFactory kf = TEST ? TESTKF : ctx.commSystem().getXDHFactory();
                 state = new HandshakeState(HandshakeState.PATTERN_ID_N, HandshakeState.RESPONDER, kf);
-                state.getLocalKeyPair().setPublicKey(ourKey.toPublic().getData(), 0);
-                state.getLocalKeyPair().setPrivateKey(ourKey.getData(), 0);
+                state.getLocalKeyPair().setKeys(ourKey.getData(), 0,
+                                                ourKey.toPublic().getData(), 0);
                 state.start();
                 decrypted = new byte[LENGTH_EC];
                 state.readMessage(encryptedRecord.getData(), PEER_SIZE, EncryptedBuildRecord.LENGTH - PEER_SIZE,
diff --git a/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java b/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java
index 56183161cfdce3ff97f348067cfc82da3ea9ca25..36bd14da41e77ac8e1ef7d026715a38b927fc537 100644
--- a/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java
+++ b/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java
@@ -356,8 +356,8 @@ public final class ECIESAEADEngine {
         } catch (GeneralSecurityException gse) {
             throw new IllegalStateException("bad proto", gse);
         }
-        state.getLocalKeyPair().setPublicKey(targetPrivateKey.toPublic().getData(), 0);
-        state.getLocalKeyPair().setPrivateKey(targetPrivateKey.getData(), 0);
+        state.getLocalKeyPair().setKeys(targetPrivateKey.getData(), 0,
+                                        targetPrivateKey.toPublic().getData(), 0);
         state.start();
         if (_log.shouldDebug())
             _log.debug("State before decrypt new session: " + state);
@@ -786,8 +786,8 @@ public final class ECIESAEADEngine {
             throw new IllegalStateException("bad proto", gse);
         }
         state.getRemotePublicKey().setPublicKey(target.getData(), 0);
-        state.getLocalKeyPair().setPublicKey(priv.toPublic().getData(), 0);
-        state.getLocalKeyPair().setPrivateKey(priv.getData(), 0);
+        state.getLocalKeyPair().setKeys(priv.getData(), 0,
+                                        priv.toPublic().getData(), 0);
         state.start();
         if (_log.shouldDebug())
             _log.debug("State before encrypt new session: " + state);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
index b7d0d6f990092d40b12e758e3f430cc6289370f4..1bd397cc04b0b34ffcbc31951a539412c0cfc3ba 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java
@@ -685,8 +685,8 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa
             } catch (GeneralSecurityException gse) {
                 throw new IllegalStateException("bad proto", gse);
             }
-            _handshakeState.getLocalKeyPair().setPublicKey(_transport.getNTCP2StaticPubkey(), 0);
-            _handshakeState.getLocalKeyPair().setPrivateKey(_transport.getNTCP2StaticPrivkey(), 0);
+            _handshakeState.getLocalKeyPair().setKeys(_transport.getNTCP2StaticPrivkey(), 0,
+                                                      _transport.getNTCP2StaticPubkey(), 0);
             Hash h = _context.routerHash();
             SessionKey bobHash = new SessionKey(h.getData());
             // save encrypted data for CBC for msg 2
diff --git a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
index be1f9c8908510b5f940064203682941984055283..7ecc42a0d7b3eac5650b4457a8c11bab022eef4f 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
@@ -217,8 +217,8 @@ class OutboundNTCP2State implements EstablishState {
             return;
         }
         _handshakeState.getRemotePublicKey().setPublicKey(bk, 0);
-        _handshakeState.getLocalKeyPair().setPublicKey(_transport.getNTCP2StaticPubkey(), 0);
-        _handshakeState.getLocalKeyPair().setPrivateKey(_transport.getNTCP2StaticPrivkey(), 0);
+        _handshakeState.getLocalKeyPair().setKeys(_transport.getNTCP2StaticPrivkey(), 0,
+                                                  _transport.getNTCP2StaticPubkey(), 0);
         // output to _tmp
         try {
             _handshakeState.start();