diff --git a/core/src/main/java/bisq/core/xmr/knaccc/monero/address/WalletAddress.java b/core/src/main/java/bisq/core/xmr/knaccc/monero/address/WalletAddress.java
index 647dd4355e6..c2665b17f6f 100755
--- a/core/src/main/java/bisq/core/xmr/knaccc/monero/address/WalletAddress.java
+++ b/core/src/main/java/bisq/core/xmr/knaccc/monero/address/WalletAddress.java
@@ -7,6 +7,10 @@
import bisq.core.xmr.org.nem.core.crypto.ed25519.arithmetic.Ed25519Group;
import bisq.core.xmr.org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
import static bisq.core.xmr.knaccc.monero.address.ByteUtil.concat;
import static bisq.core.xmr.knaccc.monero.address.ByteUtil.hexToBytes;
import static bisq.core.xmr.knaccc.monero.address.ByteUtil.longToLittleEndianUint32ByteArray;
@@ -121,7 +125,30 @@ public static String getSubaddressBase58(Scalar privateViewKey,
}
- public String getSubaddressBase58(String privateViewKeyHex, long accountId, long subaddressId) {
+ public String getSubaddressBase58(String privateViewKeyHex, long accountId, long subaddressId) throws InvalidWalletAddressException {
+ if (!checkPrivateViewKey(privateViewKeyHex)) {
+ throw new InvalidWalletAddressException("Wrong private view key for main address");
+ }
return getSubaddressBase58(new Scalar(privateViewKeyHex), hexToBytes(getPublicSpendKeyHex()), accountId, subaddressId);
}
+
+ @VisibleForTesting
+ boolean checkPrivateViewKey(String privateViewKey) {
+ return isPrivateKeyReduced(privateViewKey) && doesPrivateKeyResolveToPublicKey(privateViewKey, this.publicViewKeyHex);
+ }
+
+ @VisibleForTesting
+ static boolean isPrivateKeyReduced(String privateKey) {
+ byte[] input = hexToBytes(privateKey);
+ byte[] reduced = CryptoUtil.scReduce32(input);
+ return Arrays.equals(input, reduced);
+ }
+
+ @VisibleForTesting
+ static boolean doesPrivateKeyResolveToPublicKey(String privateKey, String publicKey) {
+ Scalar m = new Scalar(privateKey);
+ Ed25519GroupElement M = G.scalarMultiply(new Ed25519EncodedFieldElement(m.bytes));
+ byte[] generatedPubKey = M.encode().getRaw();
+ return Arrays.equals(generatedPubKey, hexToBytes(publicKey));
+ }
}
diff --git a/core/src/test/java/knaccc/monero/address/CryptoUtilTest.java b/core/src/test/java/bisq/core/xmr/knaccc/monero/address/CryptoUtilTest.java
similarity index 97%
rename from core/src/test/java/knaccc/monero/address/CryptoUtilTest.java
rename to core/src/test/java/bisq/core/xmr/knaccc/monero/address/CryptoUtilTest.java
index f1d34cd6d06..07e82d3413e 100644
--- a/core/src/test/java/knaccc/monero/address/CryptoUtilTest.java
+++ b/core/src/test/java/bisq/core/xmr/knaccc/monero/address/CryptoUtilTest.java
@@ -15,7 +15,7 @@
* along with Bisq. If not, see .
*/
-package knaccc.monero.address;
+package bisq.core.xmr.knaccc.monero.address;
import bisq.core.xmr.knaccc.monero.crypto.CryptoUtil;
diff --git a/core/src/test/java/knaccc/monero/address/WalletAddressTest.java b/core/src/test/java/bisq/core/xmr/knaccc/monero/address/WalletAddressTest.java
similarity index 60%
rename from core/src/test/java/knaccc/monero/address/WalletAddressTest.java
rename to core/src/test/java/bisq/core/xmr/knaccc/monero/address/WalletAddressTest.java
index 146e8ebd369..dd447cdc0d6 100644
--- a/core/src/test/java/knaccc/monero/address/WalletAddressTest.java
+++ b/core/src/test/java/bisq/core/xmr/knaccc/monero/address/WalletAddressTest.java
@@ -15,13 +15,13 @@
* along with Bisq. If not, see .
*/
-package knaccc.monero.address;
-
-import bisq.core.xmr.knaccc.monero.address.WalletAddress;
+package bisq.core.xmr.knaccc.monero.address;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
public class WalletAddressTest {
@Test
@@ -30,6 +30,7 @@ public void testWalletAddress() throws WalletAddress.InvalidWalletAddressExcepti
WalletAddress walletAddress = new WalletAddress(mainAddress);
String privateViewKeyHex = "7b37d8922245a07244fd31855d1e705a590a9bd2881825f0542ad99cdaba090a";
+ String publicViewKeyHex = "3cd5a3079e8b4cff3630ce16bfda6eebb2da86169accdb93206a92a58d586faa";
System.out.println("subaddress for account index 0, subaddress index 1: "
+ walletAddress.getSubaddressBase58(privateViewKeyHex, 0, 1));
@@ -46,5 +47,25 @@ public void testWalletAddress() throws WalletAddress.InvalidWalletAddressExcepti
assertEquals(walletAddress.getSubaddressBase58(privateViewKeyHex, 0, 1), addr01);
assertEquals(walletAddress.getSubaddressBase58(privateViewKeyHex, 1, 0), addr10);
assertEquals(walletAddress.getSubaddressBase58(privateViewKeyHex, 1, 1), addr11);
+
+ assertTrue(walletAddress.checkPrivateViewKey(privateViewKeyHex));
+ assertTrue(WalletAddress.doesPrivateKeyResolveToPublicKey(privateViewKeyHex, publicViewKeyHex));
+ assertFalse(WalletAddress.doesPrivateKeyResolveToPublicKey(privateViewKeyHex, privateViewKeyHex));
+
+ assertTrue(WalletAddress.doesPrivateKeyResolveToPublicKey(
+ "a82a9017a1d259c71f5392ad9091b743b86dac7a21f5e402ea0a55e5c8a6750f",
+ "bdc158199c8933353627d54edb4bbae547dbbde3130860d7940313210edca0a6"));
+
+ assertTrue(WalletAddress.doesPrivateKeyResolveToPublicKey(
+ "dae1bceeb2563b8c376f8e0456e5fe7aa3d6291b38ace18c6ad5647424a3b104",
+ "d17698d07fe9edbc41552299b90a93de73bb1bd4b94b8083af0bbe3a1931e2ec"));
+
+ assertFalse(WalletAddress.doesPrivateKeyResolveToPublicKey(
+ "0000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF",
+ "0000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF"));
+
+ String nonReducedPrivateKey = "680bceef3ca8b2ca1a9a29283c184f6f590a9bd2881825f0542ad99cdaba091a";
+ assertFalse(WalletAddress.isPrivateKeyReduced(nonReducedPrivateKey));
+ assertTrue(WalletAddress.isPrivateKeyReduced(privateViewKeyHex));
}
}
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/XmrForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/XmrForm.java
index 7e3517d6463..b76f372ae1d 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/XmrForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/XmrForm.java
@@ -251,6 +251,7 @@ public void updateFromInputs() {
xmrAccountDelegate.setPrivateViewKey(privateViewKeyInputTextField.getText());
xmrAccountDelegate.setAccountIndex(accountIndex.getText());
xmrAccountDelegate.setSubAddressIndex(subAddressIndex.getText());
+ subAddressTextField.getStyleClass().remove("error-text");
if (accountIndex.validate() && subAddressIndex.validate()
&& mainAddressTextField.validate()
&& privateViewKeyInputTextField.validate()
@@ -258,10 +259,13 @@ public void updateFromInputs() {
&& privateViewKeyInputTextField.getText().length() > 0) {
try {
xmrAccountDelegate.createAndSetNewSubAddress();
+ subAddressTextField.setText(xmrAccountDelegate.getSubAddress());
} catch (Exception ex) {
- log.warn(ex.toString());
+ log.warn(ex.getMessage());
+ String[] parts = ex.getMessage().split(":");
+ subAddressTextField.setText(parts.length > 0 ? parts[parts.length-1] : ex.getMessage());
+ subAddressTextField.getStyleClass().add("error-text");
}
- subAddressTextField.setText(xmrAccountDelegate.getSubAddress());
} else {
xmrAccountDelegate.setSubAddress("");
subAddressTextField.setText("");