diff --git a/crypto/src/main/java/io/neow3j/crypto/ECKeyPair.java b/crypto/src/main/java/io/neow3j/crypto/ECKeyPair.java index 7237209f6..aeb778cde 100644 --- a/crypto/src/main/java/io/neow3j/crypto/ECKeyPair.java +++ b/crypto/src/main/java/io/neow3j/crypto/ECKeyPair.java @@ -40,13 +40,13 @@ */ public class ECKeyPair { - private final BigInteger privateKey; - private final ECPublicKey publicKey; - static { addBouncyCastle(); } + private final BigInteger privateKey; + private final ECPublicKey publicKey; + // TODO: Remove as soon as private key is also its own type (ECPrivateKey). public ECKeyPair(BigInteger privateKey, BigInteger publicKey) { this.privateKey = privateKey; @@ -59,7 +59,6 @@ public ECKeyPair(BigInteger privateKey, ECPublicKey publicKey) { this.publicKey = publicKey; } - public BigInteger getPrivateKey() { return privateKey; } @@ -75,14 +74,26 @@ public ECPublicKey getPublicKey2() { } /** - * Constructs the NEO address from this key pairs public key. - * The address is constructed ad hoc each time this method is called. + * Constructs the NEO address from this key pairs public key, specifying the address version + * prefix and the address version. The address is constructed ad hoc each time this method is + * called. * * @return the NEO address of the public key. */ - public String getAddress() { + public String getAddress(byte addressVersion) { byte[] script = ScriptBuilder.buildVerificationScript(this.publicKey.getEncoded(true)); - return ScriptHash.fromScript(script).toAddress(); + return ScriptHash.fromScript(script).toAddress(addressVersion); + } + + /** + * Constructs the NEO address from this key pairs public key. The address is constructed ad hoc + * each time this method is called. It uses the default address version {@link + * NeoConstants#DEFAULT_ADDRESS_VERSION}. + * + * @return the NEO address of the public key. + */ + public String getAddress() { + return getAddress(NeoConstants.DEFAULT_ADDRESS_VERSION); } /** @@ -195,17 +206,6 @@ public byte[] serialize() { return result; } - public static ECKeyPair deserialize(byte[] input) { - if (input.length != PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE) { - throw new RuntimeException("Invalid input key size"); - } - - BigInteger privateKey = Numeric.toBigInt(input, 0, PRIVATE_KEY_SIZE); - BigInteger publicKey = Numeric.toBigInt(input, PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE); - - return new ECKeyPair(privateKey, publicKey); - } - @Override public boolean equals(Object o) { if (this == o) { @@ -260,8 +260,9 @@ public ECPublicKey() { } /** - * Creates a new - * @param ecPoint + * Creates a new {@link ECPublicKey} based on a EC point ({@link ECPoint}). + * + * @param ecPoint The EC point (x,y) to construct the public key. */ public ECPublicKey(ECPoint ecPoint) { if (!ecPoint.getCurve().equals(NeoConstants.CURVE_PARAMS.getCurve())) { @@ -300,7 +301,8 @@ public ECPublicKey(BigInteger publicKey) { * Gets this public key's elliptic curve point encoded as defined in section 2.3.3 of * SEC1. * - * @param compressed If the EC point should be encoded in compressed or uncompressed format. + * @param compressed If the EC point should be encoded in compressed or uncompressed + * format. * @return the encoded public key. */ public byte[] getEncoded(boolean compressed) { diff --git a/utils/src/main/java/io/neow3j/constants/NeoConstants.java b/utils/src/main/java/io/neow3j/constants/NeoConstants.java index a462f81eb..3090c0329 100644 --- a/utils/src/main/java/io/neow3j/constants/NeoConstants.java +++ b/utils/src/main/java/io/neow3j/constants/NeoConstants.java @@ -33,7 +33,9 @@ public class NeoConstants { //region Accounts, Addresses, Keys - public static final byte ADDRESS_VERSION = 0x17; + public static final byte DEFAULT_ADDRESS_VERSION = 0x17; + + public static final byte PRIVATENET_ADDRESS_VERSION = 0x37; /** * The maximum number of public keys that can take part in a multi-signature address. diff --git a/utils/src/main/java/io/neow3j/contract/ScriptHash.java b/utils/src/main/java/io/neow3j/contract/ScriptHash.java index 26e4435ed..409376599 100644 --- a/utils/src/main/java/io/neow3j/contract/ScriptHash.java +++ b/utils/src/main/java/io/neow3j/contract/ScriptHash.java @@ -98,12 +98,22 @@ public String toString() { } /** - * Derives the address corresponding to this script hash. + * Derives the address corresponding to this script hash, specifying the address version. + * + * @return the address. + */ + public String toAddress(byte addressVersion) { + return AddressUtils.scriptHashToAddress(this.scriptHash, addressVersion); + } + + /** + * Derives the address corresponding to this script hash. It uses the default address version + * {@link NeoConstants#DEFAULT_ADDRESS_VERSION} * * @return the address. */ public String toAddress() { - return AddressUtils.scriptHashToAddress(this.scriptHash); + return toAddress(NeoConstants.DEFAULT_ADDRESS_VERSION); } @Override @@ -161,7 +171,7 @@ public static ScriptHash fromScript(String script) { private void checkAndThrowHashLength(byte[] scriptHash) { if (scriptHash.length != NeoConstants.SCRIPTHASH_LENGHT_BYTES) { throw new IllegalArgumentException("Script hash must be " + - NeoConstants.SCRIPTHASH_LENGHT_BYTES + " bytes long but was "+ scriptHash.length + + NeoConstants.SCRIPTHASH_LENGHT_BYTES + " bytes long but was " + scriptHash.length + " bytes."); } } diff --git a/utils/src/main/java/io/neow3j/utils/AddressUtils.java b/utils/src/main/java/io/neow3j/utils/AddressUtils.java index cb7506b8f..1f17781b0 100644 --- a/utils/src/main/java/io/neow3j/utils/AddressUtils.java +++ b/utils/src/main/java/io/neow3j/utils/AddressUtils.java @@ -7,7 +7,26 @@ public class AddressUtils { + /** + * Checks whether the give address is valid or not. It uses the default address version {@link + * NeoConstants#DEFAULT_ADDRESS_VERSION}. + * + * @param address The address to be checked. + * @return whether the address is valid or not + */ public static boolean isValidAddress(String address) { + return isValidAddress(address, NeoConstants.DEFAULT_ADDRESS_VERSION); + } + + /** + * Checks whether the give address is valid or not. It uses the default address version {@link + * NeoConstants#DEFAULT_ADDRESS_VERSION}. + * + * @param address The address to be checked. + * @param addressVersion The address version. + * @return whether the address is valid or not + */ + public static boolean isValidAddress(String address, byte addressVersion) { byte[] data; try { data = Base58.decode(address); @@ -17,7 +36,7 @@ public static boolean isValidAddress(String address) { if (data.length != 25) { return false; } - if (data[0] != NeoConstants.ADDRESS_VERSION) { + if (data[0] != addressVersion) { return false; } byte[] checksum = Hash.sha256(Hash.sha256(data, 0, 21)); @@ -46,7 +65,8 @@ public static byte[] addressToScriptHash(String address) { } /** - * Derives the Neo address from the given script hash. + * Derives the Neo address from the given script hash. It uses the default address version + * {@link NeoConstants#DEFAULT_ADDRESS_VERSION}. *

* The script hash needs to be in little-endian order. * @@ -54,7 +74,20 @@ public static byte[] addressToScriptHash(String address) { * @return the address */ public static String scriptHashToAddress(byte[] scriptHash) { - byte[] script = ArrayUtils.concatenate(NeoConstants.ADDRESS_VERSION, scriptHash); + return scriptHashToAddress(scriptHash, NeoConstants.DEFAULT_ADDRESS_VERSION); + } + + /** + * Derives the Neo address from the given script hash, also specifying the address version. Use + * {@link #scriptHashToAddress} if the default address version should be used. + *

+ * The script hash needs to be in little-endian order. + * + * @param scriptHash The script hash to get the address for. + * @return the address + */ + public static String scriptHashToAddress(byte[] scriptHash, byte addressVersion) { + byte[] script = ArrayUtils.concatenate(addressVersion, scriptHash); byte[] checksum = ArrayUtils.getFirstNBytes(Hash.sha256(Hash.sha256(script)), 4); return Base58.encode(ArrayUtils.concatenate(script, checksum)); } diff --git a/utils/src/test/java/io/neow3j/utils/AddressUtilsTest.java b/utils/src/test/java/io/neow3j/utils/AddressUtilsTest.java index 088715c2f..4da17045f 100644 --- a/utils/src/test/java/io/neow3j/utils/AddressUtilsTest.java +++ b/utils/src/test/java/io/neow3j/utils/AddressUtilsTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import io.neow3j.constants.NeoConstants; import io.neow3j.crypto.Hash; import org.junit.Test; @@ -15,18 +16,30 @@ public class AddressUtilsTest { @Test public void scriptHashToAddress() { String script = - "2102208aea0068c429a03316e37be0e3e8e21e6cda5442df4c5914a19b3a9b6de37568747476aa"; + "2102208aea0068c429a03316e37be0e3e8e21e6cda5442df4c5914a19b3a9b6de37568747476aa"; byte[] scriptHash = Hash.sha256AndThenRipemd160(Numeric.hexStringToByteArray(script)); String address = AddressUtils.scriptHashToAddress(scriptHash); String expectedAddress = "Aa63RMYRWHPRcrZNzUnq5SNrPqoV866Spu"; assertThat(address, is(expectedAddress)); } + @Test + public void scriptHashToAddressWithAddressVersion() { + String script = + "21030529d1296dc2af1f77d8344138a77748599b69599af7ae6be57812a4ec3fa33968747476aa"; + byte[] scriptHash = Hash.sha256AndThenRipemd160(Numeric.hexStringToByteArray(script)); + System.out.println(Numeric.toHexString(scriptHash)); + String address = + AddressUtils.scriptHashToAddress(scriptHash, NeoConstants.PRIVATENET_ADDRESS_VERSION); + String expectedAddress = "PRivaTenetyWuqK7Gj7Vd747d77ssYeDhL"; + assertThat(address, is(expectedAddress)); + } + @Test public void addressToScriptHash() { byte[] scriptHash = AddressUtils.addressToScriptHash("Aa63RMYRWHPRcrZNzUnq5SNrPqoV866Spu"); String script = - "2102208aea0068c429a03316e37be0e3e8e21e6cda5442df4c5914a19b3a9b6de37568747476aa"; + "2102208aea0068c429a03316e37be0e3e8e21e6cda5442df4c5914a19b3a9b6de37568747476aa"; byte[] expected = Hash.sha256AndThenRipemd160(Numeric.hexStringToByteArray(script)); assertArrayEquals(scriptHash, expected); } @@ -38,10 +51,16 @@ public void testToScriptHashLargerThan25Chars() { @Test public void testScriptHashToAddress() { - byte[] script = Numeric.hexStringToByteArray("d336d7eb9975a29b2404fdb28185e277a4b299bc"); + byte[] scriptHash = Numeric.hexStringToByteArray("d336d7eb9975a29b2404fdb28185e277a4b299bc"); String address = "Ab2fvZdmnM4HwDgVbdBrbTLz1wK5TcEyhU"; + assertThat(AddressUtils.scriptHashToAddress(scriptHash), is(address)); + } - assertThat(AddressUtils.scriptHashToAddress(script), is(address)); + @Test + public void testScriptHashToAddressWithVersion() { + byte[] scriptHash = Numeric.hexStringToByteArray("bbf14c0d508108e56402116aede9942a064f7dc6"); + String address = "PRivaTenetyWuqK7Gj7Vd747d77ssYeDhL"; + assertThat(AddressUtils.scriptHashToAddress(scriptHash, NeoConstants.PRIVATENET_ADDRESS_VERSION), is(address)); } @Test @@ -63,4 +82,9 @@ public void testIsValidAddress() { } fail(); } + + @Test + public void test() { + + } } \ No newline at end of file