Skip to content

Commit

Permalink
first GetNewAddress implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
davassi committed Nov 17, 2016
1 parent 87bbf9c commit b7b45bb
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/main/java/jota/IotaAPIProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import jota.dto.request.*;
import jota.dto.response.*;
import jota.utils.IotaAPIUtils;
import okhttp3.OkHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/jota/dto/response/GetNewAddressResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ public class GetNewAddressResponse extends AbstractResponse {
public String getAddress() {
return address;
}

public static GetNewAddressResponse create(String address) {
GetNewAddressResponse res = new GetNewAddressResponse();
res.address = address;
return res;
}
}
130 changes: 130 additions & 0 deletions src/main/java/jota/utils/Converter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package jota.utils;

import java.util.Arrays;

public class Converter {

public static final int RADIX = 3;
public static final int MAX_TRIT_VALUE = (RADIX - 1) / 2, MIN_TRIT_VALUE = -MAX_TRIT_VALUE;

public static final int NUMBER_OF_TRITS_IN_A_BYTE = 5;
public static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3;

static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][];
static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][];

public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ";

static {

final int[] trits = new int[NUMBER_OF_TRITS_IN_A_BYTE];

for (int i = 0; i < 243; i++) {
BYTE_TO_TRITS_MAPPINGS[i] = Arrays.copyOf(trits, NUMBER_OF_TRITS_IN_A_BYTE);
increment(trits, NUMBER_OF_TRITS_IN_A_BYTE);
}

for (int i = 0; i < 27; i++) {
TRYTE_TO_TRITS_MAPPINGS[i] = Arrays.copyOf(trits, NUMBER_OF_TRITS_IN_A_TRYTE);
increment(trits, NUMBER_OF_TRITS_IN_A_TRYTE);
}
}

public static byte[] bytes(final int[] trits, final int offset, final int size) {

final byte[] bytes = new byte[(size + NUMBER_OF_TRITS_IN_A_BYTE - 1) / NUMBER_OF_TRITS_IN_A_BYTE];
for (int i = 0; i < bytes.length; i++) {

int value = 0;
for (int j = (size - i * NUMBER_OF_TRITS_IN_A_BYTE) < 5 ? (size - i * NUMBER_OF_TRITS_IN_A_BYTE) : NUMBER_OF_TRITS_IN_A_BYTE; j-- > 0; ) {
value = value * RADIX + trits[offset + i * NUMBER_OF_TRITS_IN_A_BYTE + j];
}
bytes[i] = (byte)value;
}

return bytes;
}

public static byte[] bytes(final int[] trits) {
return bytes(trits, 0, trits.length);
}

public static void getTrits(final byte[] bytes, final int[] trits) {

int offset = 0;
for (int i = 0; i < bytes.length && offset < trits.length; i++) {
System.arraycopy(BYTE_TO_TRITS_MAPPINGS[bytes[i] < 0 ? (bytes[i] + BYTE_TO_TRITS_MAPPINGS.length) : bytes[i]], 0, trits, offset, trits.length - offset < NUMBER_OF_TRITS_IN_A_BYTE ? (trits.length - offset) : NUMBER_OF_TRITS_IN_A_BYTE);
offset += NUMBER_OF_TRITS_IN_A_BYTE;
}
while (offset < trits.length) {
trits[offset++] = 0;
}
}

public static int[] trits(final String trytes) {

final int[] trits = new int[trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE];
for (int i = 0; i < trytes.length(); i++) {
System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE);
}

return trits;
}

public static void copyTrits(final long value, final int[] destination, final int offset, final int size) {

long absoluteValue = value < 0 ? -value : value;
for (int i = 0; i < size; i++) {

int remainder = (int)(absoluteValue % RADIX);
absoluteValue /= RADIX;
if (remainder > MAX_TRIT_VALUE) {

remainder = MIN_TRIT_VALUE;
absoluteValue++;
}
destination[offset + i] = remainder;
}

if (value < 0) {

for (int i = 0; i < size; i++) {
destination[offset + i] = -destination[offset + i];
}
}
}

public static String trytes(final int[] trits, final int offset, final int size) {

StringBuilder trytes = new StringBuilder();
for (int i = 0; i < (size + NUMBER_OF_TRITS_IN_A_TRYTE - 1) / NUMBER_OF_TRITS_IN_A_TRYTE; i++) {

int j = trits[offset + i * 3] + trits[offset + i * 3 + 1] * 3 + trits[offset + i * 3 + 2] * 9;
if (j < 0) {

j += TRYTE_ALPHABET.length();
}
trytes.append(TRYTE_ALPHABET.charAt(j));
}
return trytes.toString();
}

public static String trytes(final int[] trits) {
return trytes(trits, 0, trits.length);
}

public static int tryteValue(final int[] trits, final int offset) {
return trits[offset] + trits[offset + 1] * 3 + trits[offset + 2] * 9;
}

public static void increment(final int[] trits, final int size) {

for (int i = 0; i < size; i++) {
if (++trits[i] > Converter.MAX_TRIT_VALUE) {
trits[i] = Converter.MIN_TRIT_VALUE;
} else {
break;
}
}
}
}
60 changes: 60 additions & 0 deletions src/main/java/jota/utils/Curl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package jota.utils;

/**
* (c) 2016 Come-from-Beyond
*
* Curl belongs to the sponge function family.
*
*/
public class Curl {

public static final int HASH_LENGTH = 243;
private static final int STATE_LENGTH = 3 * HASH_LENGTH;

private static final int NUMBER_OF_ROUNDS = 27;
private static final int[] TRUTH_TABLE = {1, 0, -1, 1, -1, 0, -1, 1, 0};

private final int[] state = new int[STATE_LENGTH];

public void absorb(final int[] trits, int offset, int length) {

do {
System.arraycopy(trits, offset, state, 0, length < HASH_LENGTH ? length : HASH_LENGTH);
transform();
offset += HASH_LENGTH;
} while ((length -= HASH_LENGTH) > 0);
}

public int [] squeeze(final int[] trits, int offset, int length) {

do {
System.arraycopy(state, 0, trits, offset, length < HASH_LENGTH ? length : HASH_LENGTH);
transform();
offset += HASH_LENGTH;
} while ((length -= HASH_LENGTH) > 0);

return state;
}

private void transform() {

final int[] scratchpad = new int[STATE_LENGTH];
int scratchpadIndex = 0;
for (int round = 0; round < NUMBER_OF_ROUNDS; round++) {
System.arraycopy(state, 0, scratchpad, 0, STATE_LENGTH);
for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) {
state[stateIndex] = TRUTH_TABLE[scratchpad[scratchpadIndex] + scratchpad[scratchpadIndex += (scratchpadIndex < 365 ? 364 : -365)] * 3 + 4];
}
}
}

public void reset() {
for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) {
state[stateIndex] = 0;
}
}

public int[] getState() {
return state;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package jota;
package jota.utils;

import jota.dto.response.GetBundleResponse;
import jota.dto.response.GetNewAddressResponse;
Expand All @@ -15,8 +15,14 @@ public class IotaAPIUtils {

private static final Logger log = LoggerFactory.getLogger(IotaAPIUtils.class);

public static GetNewAddressResponse getNewAddress(final String seed, final Integer securityLevel) {
throw new NotImplementedException("Not yet implemented");
public static GetNewAddressResponse getNewAddress(final String seed, final int index) {

final int [] key = Signing.key(Converter.trits(seed), index, 2);
final int [] digests = Signing.digests(key);
final int [] addressTrits = Signing.address(digests);
final String address = Converter.trytes(addressTrits);

return GetNewAddressResponse.create(address);
}

public static GetBundleResponse getBundle(final String transaction) {
Expand Down
93 changes: 93 additions & 0 deletions src/main/java/jota/utils/Signing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package jota.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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;
} else {
break;
}
}
}

Curl curl = new Curl();
//curl.absorb(subseed, state);
//curl.squeeze(subseed, state);
curl.absorb(subseed, 0, subseed.length);

List<Integer> key = new ArrayList<>();
int [] buffer = new int[subseed.length];
int offset = 0;

while (length-- > 0) {

for (int i = 0; i < 27; i++) {

curl.squeeze(buffer, 0, buffer.length);
for (int j = 0; j < 243; j++) {
key.add(buffer[j]);
}
}
}
return to(key);
}

private static int[] to(List<Integer> key) {
int a [] = new int[key.size()]; int i = 0;
for (Integer v : key) {
a[i++] = v;
}
return a;
}

public static int [] digests(int [] key) {
final Curl curl = new Curl();

int[] digests = new int[key.length];
int[] buffer = new int[key.length];

for (int i = 0; i < Math.floor(key.length / 6561); i++) {
int [] keyFragment = Arrays.copyOfRange(key, i * 6561, (i + 1) * 6561);

for (int j = 0; j < 27; j++) {

buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243);
for (int k = 0; k < 26; k++) {

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];
}
}

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];
}
}
return digests;
}

public static int [] address(int [] digests) {
final Curl curl = new Curl();
int [] address = new int[digests.length];
curl.absorb(digests, 0, digests.length);
curl.squeeze(address, 0, address.length);
return address;
}
}
9 changes: 8 additions & 1 deletion src/test/java/jota/IotaAPIProxyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import jota.dto.response.*;
import jota.utils.IotaAPIUtils;
import org.hamcrest.core.IsNull;
import org.junit.Before;
import org.junit.Ignore;
Expand Down Expand Up @@ -122,5 +123,11 @@ public void shouldCreateIotaApiProxyInstanceWithDefaultValues() {
IotaAPIProxy proxy = new IotaAPIProxy.Builder().build();
assertThat(proxy, IsNull.notNullValue());
}


@Test
public void shouldCreateANewAddress() {
GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 2);
System.err.println(res);
}

}

0 comments on commit b7b45bb

Please sign in to comment.