diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index b742299..b1a07d3 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -195,8 +195,8 @@ public class IotaAPIProxy { return IotaAPIUtils.getBundle(transaction); } - public GetNewAddressResponse getNewAddress(String seed, Integer securityLevel) { - return IotaAPIUtils.getNewAddress(seed, securityLevel); + public GetNewAddressResponse getNewAddress(String seed, Integer index, boolean checksum, int total, boolean returnAll) { + return IotaAPIUtils.getNewAddress(seed, index, checksum, total, returnAll); } public static class Builder { diff --git a/src/main/java/jota/dto/response/GetNewAddressResponse.java b/src/main/java/jota/dto/response/GetNewAddressResponse.java index dab7d86..b54384d 100644 --- a/src/main/java/jota/dto/response/GetNewAddressResponse.java +++ b/src/main/java/jota/dto/response/GetNewAddressResponse.java @@ -1,16 +1,18 @@ package jota.dto.response; +import java.util.List; + public class GetNewAddressResponse extends AbstractResponse { - private String address; + private List addresses; - public String getAddress() { - return address; - } - - public static GetNewAddressResponse create(String address) { + public static GetNewAddressResponse create(List addresses) { GetNewAddressResponse res = new GetNewAddressResponse(); - res.address = address; + res.addresses = addresses; return res; } + + public List getAddress() { + return addresses; + } } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index bc26d80..8713502 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,11 +1,16 @@ package jota.utils; +import jota.IotaAPIProxy; +import jota.dto.response.FindTransactionResponse; import jota.dto.response.GetBundleResponse; import jota.dto.response.GetNewAddressResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; + /** * Client Side computation service * @@ -15,7 +20,75 @@ public class IotaAPIUtils { private static final Logger log = LoggerFactory.getLogger(IotaAPIUtils.class); - public static GetNewAddressResponse getNewAddress(final String seed, final int index) { + /** + * Generates a new address from a seed and returns the remainderAddress. + * This is either done deterministically, or by providing the index of the new remainderAddress + * + * @param seed Tryte-encoded seed. It should be noted that this seed is not transferred + * @param index Optional (default null). Key index to start search from. If the index is provided, the generation of the address is not deterministic. + * @param checksum Optional (default false). Adds 9-tryte address checksum + * @param total Optional (default 1)Total number of addresses to generate + * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) + * @return an array of strings with the specifed number of addresses + */ + + public static GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { + + final List allAddresses = new ArrayList<>(); + // Case 1: total + // + // If total number of addresses to generate is supplied, simply generate + // and return the list of all addresses + // + // + if (total != 0) { + // Increase index with each iteration + for (int i = index; i < index + total; i++) { + allAddresses.add(newAddress(seed, i, checksum)); + } + } + // Case 2: no total provided + // + // Continue calling findTransactions to see if address was already created + // if null, return list of addresses + // + else { + + // TODO init with params + IotaAPIProxy proxy = new IotaAPIProxy.Builder().build(); + + for (int i = index; ; i++) { + String newAddress = newAddress(seed, i, checksum); + + FindTransactionResponse response = proxy.findTransactions(null, new String[]{newAddress}, null, null); + + // If returnAll, return list of allAddresses + // else return only the last address that was generated + + if (!returnAll) { + allAddresses.clear(); + } + + allAddresses.add(newAddress); + + if (response.getHashes().length == 0) { + break; + } + } + } + + return GetNewAddressResponse.create(allAddresses); + } + + /** + * Generates a new address + * + * @param seed + * @param index + * @param checksum + * @return an String with address + */ + private static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); log.debug("key Length = {}", key.length ); @@ -24,14 +97,16 @@ public class IotaAPIUtils { log.debug("digests Length = {}", digests.length ); final int[] addressTrits = Signing.address(digests); - log.debug("addressTrits Length = {}", addressTrits.length ); + String address = Converter.trytes(addressTrits); - final String address = Converter.trytes(addressTrits); - - return GetNewAddressResponse.create(address); + if (checksum) { + address = Checksum.addChecksum(address); + } + return address; } public static GetBundleResponse getBundle(final String transaction) { throw new NotImplementedException("Not yet implemented"); } } + diff --git a/src/main/java/jota/utils/IotaUnits.java b/src/main/java/jota/utils/IotaUnits.java index f3fbfe0..28e52f3 100644 --- a/src/main/java/jota/utils/IotaUnits.java +++ b/src/main/java/jota/utils/IotaUnits.java @@ -3,6 +3,10 @@ package jota.utils; /** * Created by pinpong on 30.11.16. */ + +/** + * Table of IOTA units based off of the standard system of Units + **/ public enum IotaUnits { IOTA("i", 0), KILO_IOTA("Ki", 3), diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 3cff61c..025529e 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -8,27 +8,25 @@ public class Signing { static int[] key(int[] seed, int index, int length) { - final int[] subseed = seed; - for (int i = 0; i < index; i++) { for (int j = 0; j < 243; j++) { - if (++subseed[j] > 1) { - subseed[j] = -1; + if (++seed[j] > 1) { + seed[j] = -1; } else { break; } } } - Curl curl = new Curl(); + final Curl curl = new Curl(); curl.reset(); - curl.absorb(subseed, 0, subseed.length); - curl.squeeze(subseed, 0, subseed.length); + curl.absorb(seed, 0, seed.length); + curl.squeeze(seed, 0, seed.length); curl.reset(); - curl.absorb(subseed, 0, subseed.length); + curl.absorb(seed, 0, seed.length); - List key = new ArrayList<>(); - int[] buffer = new int[subseed.length]; + final List key = new ArrayList<>(); + int[] buffer = new int[seed.length]; int offset = 0; while (length-- > 0) { @@ -70,19 +68,14 @@ public class Signing { curl.absorb(buffer, 0, buffer.length); curl.squeeze(buffer, 0, buffer.length); } - for (int k = 0; k < 243; k++) { - - keyFragment[j * 243 + k] = buffer[k]; - } + System.arraycopy(buffer, 0, keyFragment, j * 243, 243); } curl.reset(); curl.absorb(keyFragment, 0, keyFragment.length); curl.squeeze(buffer, 0, buffer.length); - for (int j = 0; j < 243; j++) { - digests[i * 243 + j] = buffer[j]; - } + System.arraycopy(buffer, 0, digests, i * 243, 243); } return digests; } diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index 2efaec0..1413f69 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -1,7 +1,6 @@ package jota; import jota.utils.Checksum; -import jota.utils.InputValidator; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -23,4 +22,9 @@ public class ChecksumTest { public void shouldRemoveChecksum() { assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); } + + @Test + public void shouldIsValidChecksum() { + assertEquals(Checksum.isValidChecksum(TEST_ADDRESS_WITH_CHECKSUM), true); + } } diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index bac2d3d..b588479 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -10,6 +10,9 @@ import org.hamcrest.core.IsNull; import org.junit.Before; import org.junit.Test; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; /** @@ -128,7 +131,7 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { - GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 4); + final GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 4); assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); } } \ No newline at end of file