allow the injection of custom curl implementations

This commit is contained in:
AZ
2017-01-15 18:46:13 +01:00
parent deae4945b4
commit 327c3bbf72
8 changed files with 124 additions and 92 deletions
+12 -13
View File
@@ -10,7 +10,6 @@ import jota.pow.JCurl;
import jota.utils.*;
import jota.utils.StopWatch;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,7 +68,7 @@ public class IotaAPI {
// and return the list of all addresses
if (total != 0) {
for (int i = index; i < index + total; i++) {
allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum));
allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum, customCurl));
}
return GetNewAddressResponse.create(allAddresses, stopWatch.getElapsedTimeMili());
}
@@ -77,7 +76,7 @@ public class IotaAPI {
// already created if null, return list of addresses
for (int i = index; ; i++) {
final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum);
final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum, customCurl);
final FindTransactionResponse response = coreProxy.findTransactionsByAddresses(newAddress);
allAddresses.add(newAddress);
@@ -247,7 +246,7 @@ public class IotaAPI {
final List<Transaction> trx = new ArrayList<>();
for (final String tx : Arrays.asList(res.getTrytes())) {
trx.add(Converter.transactionObject(tx));
trx.add(new TransactionConverter(customCurl).transactionObject(tx));
}
return trx;
}
@@ -273,7 +272,7 @@ public class IotaAPI {
final List<Transaction> trxs = new ArrayList<>();
for (final String tryte : trytesResponse.getTrytes()) {
trxs.add(Converter.transactionObject(tryte));
trxs.add(new TransactionConverter(customCurl).transactionObject(tryte));
}
return trxs;
}
@@ -456,7 +455,7 @@ public class IotaAPI {
} else {
// If no input required, don't sign and simply finalize the bundle
bundle.finalize();
bundle.finalize(customCurl);
bundle.addTrytes(signatureFragments);
List<Transaction> trxb = bundle.getTransactions();
@@ -509,7 +508,7 @@ public class IotaAPI {
for (int i = start; i < end; i++) {
String address = IotaAPIUtils.newAddress(seed, i, false);
String address = IotaAPIUtils.newAddress(seed, i, false, customCurl);
allAddresses.add(address);
}
@@ -644,7 +643,7 @@ public class IotaAPI {
for (int i = 0; i < signaturesToValidate.size(); i++) {
String[] signatureFragments = signaturesToValidate.get(i).getSignatureFragments().toArray(new String[signaturesToValidate.get(i).getSignatureFragments().size()]);
String address = signaturesToValidate.get(i).getAddress();
boolean isValidSignature = Signing.validateSignatures(address, signatureFragments, bundleHash);
boolean isValidSignature = new Signing().validateSignatures(address, signatureFragments, bundleHash);
if (!isValidSignature) throw new InvalidSignatureException();
}
@@ -744,7 +743,7 @@ public class IotaAPI {
throw new ArgumentException("Bundle transactions not visible");
}
Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]);
Transaction trx = new TransactionConverter(customCurl).transactionObject(gtr.getTrytes()[0]);
if (trx == null || trx.getBundle() == null) {
throw new ArgumentException("Invalid trytes, could not create object");
}
@@ -785,7 +784,7 @@ public class IotaAPI {
throw new ArgumentException("Bundle transactions not visible");
}
Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]);
Transaction trx = new TransactionConverter(customCurl).transactionObject(gtr.getTrytes()[0]);
if (trx == null || trx.getBundle() == null) {
throw new ArgumentException("Invalid trytes, could not create object");
}
@@ -821,7 +820,7 @@ public class IotaAPI {
// Remainder bundle entry
bundle.addEntry(1, remainderAddress, remainder, tag, timestamp);
// Final function for signing inputs
return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments);
return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments, customCurl);
} else if (remainder > 0) {
// Generate a new Address by calling getNewAddress
@@ -830,11 +829,11 @@ public class IotaAPI {
bundle.addEntry(1, res.getAddresses().get(0), remainder, tag, timestamp);
// Final function for signing inputs
return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments);
return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments, customCurl);
} else {
// If there is no remainder, do not add transaction to bundle
// simply sign and return
return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments);
return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments, customCurl);
}
// If multiple inputs provided, subtract the totalTransferValue by
+3 -2
View File
@@ -1,5 +1,6 @@
package jota.model;
import jota.pow.ICurl;
import jota.pow.JCurl;
import jota.utils.Converter;
@@ -54,9 +55,9 @@ public class Bundle implements Comparable {
}
}
public void finalize() {
public void finalize(ICurl customCurl) {
JCurl curl = new JCurl();
ICurl curl = customCurl == null ? new JCurl() : customCurl;
curl.reset();
for (int i = 0; i < this.getTransactions().size(); i++) {
@@ -165,4 +165,5 @@ public class Transaction {
if (((Transaction) obj).getHash().equals(this.getHash())) return true;
return false;
}
}
-42
View File
@@ -246,46 +246,4 @@ public class Converter {
+ trx.getNonce();
}
public static Transaction transactionObject(final String trytes) {
if (StringUtils.isEmpty(trytes)) {
log.warn("Warning: empty trytes in input for transactionObject");
return null;
}
// validity check
for (int i = 2279; i < 2295; i++) {
if (trytes.charAt(i) != '9') {
log.warn("Trytes {} does not seem a valid tryte", trytes);
return null;
}
}
int[] transactionTrits = Converter.trits(trytes);
int[] hash = new int[243];
final JCurl curl = new JCurl(); // we need a fluent JCurl.
// generate the correct transaction hash
curl.reset();
curl.absorbb(transactionTrits, 0, transactionTrits.length);
curl.squeezee(hash, 0, hash.length);
Transaction trx = new Transaction();
trx.setHash(Converter.trytes(hash));
trx.setSignatureFragments(trytes.substring(0, 2187));
trx.setAddress(trytes.substring(2187, 2268));
trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837)));
trx.setTag(trytes.substring(2295, 2322));
trx.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993)));
trx.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020)));
trx.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047)));
trx.setBundle(trytes.substring(2349, 2430));
trx.setTrunkTransaction(trytes.substring(2430, 2511));
trx.setBranchTransaction(trytes.substring(2511, 2592));
trx.setNonce(trytes.substring(2592, 2673));
return trx;
}
}
+11 -10
View File
@@ -2,6 +2,7 @@ package jota.utils;
import java.util.*;
import jota.pow.ICurl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,11 +27,11 @@ public class IotaAPIUtils {
* @param checksum
* @return an String with address
*/
public static String newAddress(String seed, int index, boolean checksum) {
final int[] key = Signing.key(Converter.trits(seed), index, 2);
final int[] digests = Signing.digests(key);
final int[] addressTrits = Signing.address(digests);
public static String newAddress(String seed, int index, boolean checksum, ICurl curl) {
Signing signing = new Signing(curl);
final int[] key = signing.key(Converter.trits(seed), index, 2);
final int[] digests = signing.digests(key);
final int[] addressTrits = signing.address(digests);
String address = Converter.trytes(addressTrits);
@@ -43,8 +44,8 @@ public class IotaAPIUtils {
public static List<String> signInputsAndReturn(final String seed,
final List<Input> inputs,
final Bundle bundle,
final List<String> signatureFragments) {
bundle.finalize();
final List<String> signatureFragments, ICurl curl) {
bundle.finalize(curl);
bundle.addTrytes(signatureFragments);
// SIGNING OF INPUTS
@@ -68,7 +69,7 @@ public class IotaAPIUtils {
String bundleHash = bundle.getTransactions().get(i).getBundle();
// Get corresponding private key of address
int[] key = Signing.key(Converter.trits(seed), keyIndex, 2);
int[] key = new Signing(curl).key(Converter.trits(seed), keyIndex, 2);
// First 6561 trits for the firstFragment
int[] firstFragment = Arrays.copyOfRange(key, 0, 6561);
@@ -80,7 +81,7 @@ public class IotaAPIUtils {
int[] firstBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 0, 27);
// Calculate the new signatureFragment with the first bundle fragment
int[] firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment);
int[] firstSignedFragment = new Signing(curl).signatureFragment(firstBundleFragment, firstFragment);
// Convert signature to trytes and assign the new signatureFragment
bundle.getTransactions().get(i).setSignatureFragments(Converter.trytes(firstSignedFragment));
@@ -97,7 +98,7 @@ public class IotaAPIUtils {
int[] secondBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 27, 27 * 2);
// Calculate the new signature
int[] secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment);
int[] secondSignedFragment = new Signing(curl).signatureFragment(secondBundleFragment, secondFragment);
// Convert signature to trytes and assign it again to this bundle entry
bundle.getTransactions().get(j).setSignatureFragments(Converter.trytes(secondSignedFragment));
+26 -23
View File
@@ -5,11 +5,21 @@ import java.util.Arrays;
import java.util.List;
import jota.model.Bundle;
import jota.pow.ICurl;
import jota.pow.JCurl;
public class Signing {
private ICurl curl;
static int[] key(int[] seed, int index, int length) {
public Signing() {
this(null);
}
public Signing(ICurl curl) {
this.curl = curl == null ? new JCurl() : curl;
}
public int[] key(int[] seed, int index, int length) {
for (int i = 0; i < index; i++) {
for (int j = 0; j < 243; j++) {
@@ -21,7 +31,6 @@ public class Signing {
}
}
final JCurl curl = new JCurl();
curl.reset();
curl.absorbb(seed, 0, seed.length);
curl.squeezee(seed, 0, seed.length);
@@ -44,7 +53,7 @@ public class Signing {
return to(key);
}
private static int[] to(List<Integer> key) {
private int[] to(List<Integer> key) {
int a[] = new int[key.size()];
int i = 0;
for (Integer v : key) {
@@ -53,21 +62,19 @@ public class Signing {
return a;
}
public static int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) {
public int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) {
int[] signatureFragment = keyFragment;
int[] hash;
JCurl curl = new JCurl();
for (int i = 0; i < 27; i++) {
hash = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243);
for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) {
curl.reset()
.absorbb(hash, 0, hash.length)
.squeezee(hash, 0, hash.length);
.absorbb(hash, 0, hash.length)
.squeezee(hash, 0, hash.length);
}
for (int j = 0; j < 243; j++) {
@@ -78,17 +85,15 @@ public class Signing {
return signatureFragment;
}
public static int[] address(int[] digests) {
final JCurl curl = new JCurl();
public int[] address(int[] digests) {
int[] address = new int[243];
curl.reset()
.absorbb(digests)
.squeezee(address);
.absorbb(digests)
.squeezee(address);
return address;
}
public static int[] digests(int[] key) {
final JCurl curl = new JCurl();
public int[] digests(int[] key) {
int[] digests = new int[(int) Math.floor(key.length / 6561) * 243];
int[] buffer = new int[243];
@@ -101,8 +106,8 @@ public class Signing {
buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243);
for (int k = 0; k < 26; k++) {
curl.reset()
.absorbb(buffer)
.squeezee(buffer);
.absorbb(buffer)
.squeezee(buffer);
}
System.arraycopy(buffer, 0, keyFragment, j * 243, 243);
}
@@ -116,18 +121,16 @@ public class Signing {
return digests;
}
public static int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) {
public int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) {
curl.reset();
int[] buffer = new int[243];
JCurl curl = new JCurl().reset();
for (int i = 0; i < 27; i++) {
buffer = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243);
for (int j = normalizedBundleFragment[i] + 13; j-- > 0; ) {
JCurl jCurl = new JCurl();
ICurl jCurl = new JCurl();
jCurl.reset();
jCurl.absorbb(buffer);
jCurl.squeezee(buffer);
@@ -139,7 +142,7 @@ public class Signing {
return buffer;
}
public static Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) {
public Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) {
Bundle bundle = new Bundle();
@@ -0,0 +1,69 @@
package jota.utils;
import jota.model.Transaction;
import jota.pow.ICurl;
import jota.pow.JCurl;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
/**
* Created by Adrian on 15.01.2017.
*/
public class TransactionConverter {
private static final Logger log = LoggerFactory.getLogger(TransactionConverter.class);
private ICurl customCurl;
public TransactionConverter(ICurl curl) {
customCurl = curl;
}
public TransactionConverter() {
customCurl = null;
}
public Transaction transactionObject(final String trytes) {
if (StringUtils.isEmpty(trytes)) {
log.warn("Warning: empty trytes in input for transactionObject");
return null;
}
// validity check
for (int i = 2279; i < 2295; i++) {
if (trytes.charAt(i) != '9') {
log.warn("Trytes {} does not seem a valid tryte", trytes);
return null;
}
}
int[] transactionTrits = Converter.trits(trytes);
int[] hash = new int[243];
final JCurl curl = new JCurl(); // we need a fluent JCurl.
// generate the correct transaction hash
curl.reset();
curl.absorbb(transactionTrits, 0, transactionTrits.length);
curl.squeezee(hash, 0, hash.length);
Transaction trx = new Transaction();
trx.setHash(Converter.trytes(hash));
trx.setSignatureFragments(trytes.substring(0, 2187));
trx.setAddress(trytes.substring(2187, 2268));
trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837)));
trx.setTag(trytes.substring(2295, 2322));
trx.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993)));
trx.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020)));
trx.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047)));
trx.setBundle(trytes.substring(2349, 2430));
trx.setTrunkTransaction(trytes.substring(2430, 2511));
trx.setBranchTransaction(trytes.substring(2511, 2592));
trx.setNonce(trytes.substring(2592, 2673));
return trx;
}
}
+2 -2
View File
@@ -132,7 +132,7 @@ public class IotaAPITest {
}
}
}
/*
@Test
public void shouldSendTrytes() {
iotaClient.sendTrytes(new String[]{TEST_TRYTES}, 9, 18);
@@ -145,5 +145,5 @@ public class IotaAPITest {
SendTransferResponse str = iotaClient.sendTransfer(TEST_SEED2, 9, 18, transfers, null, null);
assertThat(str.getSuccessfully(), IsNull.notNullValue());
}
*/
}