Multisig implementation finished

This commit is contained in:
adrianziser 2017-02-18 20:37:26 +01:00
parent 5e956137a4
commit bbaa4d8b2f
24 changed files with 248 additions and 228 deletions

View File

@ -7,8 +7,8 @@ The JOTA library is a simple Java wrapper around [[IOTA]](http://www.iotatoken.c
It allows to connect easily using java directly to a local or a remote [[IOTA node]](https://iota.readme.io/docs/syncing-to-the-network).
* **Latest release:** 0.9.0 RC1
* **Compatibility:** fully compatible with IOTA IRI v1.2.4
* **Latest release:** 0.9.1
* **Compatibility:** fully compatible with IOTA IRI v1.2.6
* **API coverage:** 14 of 14 commands fully implemented
* **License:** Apache License 2.0
* **Readme updated:** 2016-01-19 21:05:02 (UTC)
@ -54,7 +54,7 @@ In order to communicate with *IOTA node*, JOTA needs to be aware of your node's
iota.node.host=127.0.0.1
iota.node.port=14265
Jota is still *not* in the central maven repository. It will be available when it will cover 100% iota's rest interface.
Jota is still *not* in the central maven repository.
##Warning
- This is pre-release software!

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.iota</groupId>
<artifactId>jota</artifactId>
<version>0.9.0-RC1</version>
<version>0.9.1</version>
<name>JOTA</name>
<description>JOTA library is a simple Java wrapper around IOTA Node's JSON-REST HTTP interface.</description>

View File

@ -14,13 +14,13 @@ import java.util.*;
/**
* IotaAPI Builder. Usage:
*
* <p>
* IotaApiProxy api = IotaApiProxy.Builder
* .protocol("http")
* .nodeAddress("localhost")
* .port(12345)
* .build();
*
* <p>
* GetNodeInfoResponse response = api.getNodeInfo();
*
* @author davassi
@ -39,14 +39,14 @@ public class IotaAPI extends IotaAPICore {
* 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 security Security level to be used for the private key / address. Can be 1, 2 or 3.
* @param index Key index to start search from. If the index is provided, the generation of the address is not deterministic.
* @param checksum Adds 9-tryte address checksum.
* @param total Total number of addresses to generate.
* @param seed Tryte-encoded seed. It should be noted that this seed is not transferred.
* @param security Security level to be used for the private key / address. Can be 1, 2 or 3.
* @param index Key index to start search from. If the index is provided, the generation of the address is not deterministic.
* @param checksum Adds 9-tryte address checksum.
* @param total Total number of addresses to generate.
* @param returnAll If <code>true</code>, it returns all addresses which were deterministically generated (until findTransactions returns null).
* @return An array of strings with the specifed number of addresses.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
*/
public GetNewAddressResponse getNewAddress(final String seed, int security, final int index, final boolean checksum, final int total, final boolean returnAll) throws InvalidSecurityLevelException, InvalidAddressException {
@ -90,18 +90,18 @@ public class IotaAPI extends IotaAPICore {
}
/**
* @param seed Tryte-encoded seed. It should be noted that this seed is not transferred.
* @param security The security level of private key / seed.
* @param start Starting key index.
* @param end Ending key index.
* @param seed Tryte-encoded seed. It should be noted that this seed is not transferred.
* @param security The security level of private key / seed.
* @param start Starting key index.
* @param end Ending key index.
* @param inclusionStates If <code>true</code>, it gets the inclusion states of the transfers.
* @return Bundle of transfers.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidSignatureException is thrown when an invalid signature is encountered.
* @throws NoNodeInfoException is thrown when its not possible to get node info.
* @throws NoInclusionStatesException when it not possible to get a inclusion state.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidSignatureException is thrown when an invalid signature is encountered.
* @throws NoNodeInfoException is thrown when its not possible to get node info.
* @throws NoInclusionStatesException when it not possible to get a inclusion state.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
*/
public GetTransferResponse getTransfers(String seed, int security, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoNodeInfoException, NoInclusionStatesException, InvalidSecurityLevelException, InvalidAddressException {
@ -131,15 +131,15 @@ public class IotaAPI extends IotaAPICore {
}
/**
*
* Internal function to get the formatted bundles of a list of addresses.
* @param addresses List of addresses.
*
* @param addresses List of addresses.
* @param inclusionStates If <code>true</code>, it gets the inclusion states of the transfers.
* @return A Transaction objects.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidSignatureException is thrown when an invalid signature is encountered.
* @throws NoNodeInfoException is thrown when its not possible to get node info.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidSignatureException is thrown when an invalid signature is encountered.
* @throws NoNodeInfoException is thrown when its not possible to get node info.
* @throws NoInclusionStatesException when it not possible to get a inclusion state.
*/
public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoNodeInfoException, NoInclusionStatesException {
@ -242,8 +242,8 @@ public class IotaAPI extends IotaAPICore {
/**
* Facade method: Gets transactions to approve, attaches to Tangle, broadcasts and stores.
*
* @param trytes The trytes.
* @param depth The depth.
* @param trytes The trytes.
* @param depth The depth.
* @param minWeightMagnitude The minimum weight magnitude.
* @return Transactions objects.
* @throws InvalidTrytesException is thrown when invalid trytes is provided.
@ -326,16 +326,16 @@ public class IotaAPI extends IotaAPICore {
/**
* Prepares transfer by generating bundle, finding and signing inputs.
*
* @param seed 81-tryte encoded address of recipient.
* @param security The security level of private key / seed.
* @param seed 81-tryte encoded address of recipient.
* @param security The security level of private key / seed.
* @param transfers Array of transfer objects.
* @param remainder If defined, this address will be used for sending the remainder value (of the inputs) to.
* @param inputs The inputs.
* @param inputs The inputs.
* @return Returns bundle trytes.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws NotEnoughBalanceException is thrown when a transfer fails because their is not enough balance to perform the transfer.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws NotEnoughBalanceException is thrown when a transfer fails because their is not enough balance to perform the transfer.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
* @throws InvalidTransferException is thrown when an invalid transfer is provided.
* @throws InvalidTransferException is thrown when an invalid transfer is provided.
*/
public List<String> prepareTransfers(String seed, int security, final List<Transfer> transfers, String remainder, List<Input> inputs) throws NotEnoughBalanceException, InvalidSecurityLevelException, InvalidAddressException, InvalidTransferException {
@ -489,14 +489,13 @@ public class IotaAPI extends IotaAPICore {
/**
* Gets the inputs of a seed
*
* @param seed Tryte-encoded seed. It should be noted that this seed is not transferred.
* @param security The Security level of private key / seed.
* @param start Starting key index.
* @param end Ending key index.
* @param seed Tryte-encoded seed. It should be noted that this seed is not transferred.
* @param security The Security level of private key / seed.
* @param start Starting key index.
* @param end Ending key index.
* @param threshold Min balance required.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
**/
public GetBalancesAndFormatResponse getInputs(String seed, int security, int start, int end, long threshold) throws InvalidSecurityLevelException, InvalidAddressException {
StopWatch stopWatch = new StopWatch();
@ -552,10 +551,10 @@ public class IotaAPI extends IotaAPICore {
*
* @param addresses The addresses.
* @param threshold Min balance required.
* @param start Starting key index.
* @param end Ending key index.
* @param start Starting key index.
* @param end Ending key index.
* @param stopWatch the stopwatch.
* @param security The security level of private key / seed.
* @param security The security level of private key / seed.
* @return Inputs object.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
**/
@ -606,8 +605,8 @@ public class IotaAPI extends IotaAPICore {
*
* @param transaction The transaction encoded in trytes.
* @return an array of bundle, if there are multiple arrays it means that there are conflicting bundles.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidSignatureException is thrown when an invalid signature is encountered.
*/
public GetBundleResponse getBundle(String transaction) throws ArgumentException, InvalidBundleException, InvalidSignatureException {
@ -677,7 +676,7 @@ public class IotaAPI extends IotaAPICore {
for (Signature aSignaturesToValidate : signaturesToValidate) {
String[] signatureFragments = aSignaturesToValidate.getSignatureFragments().toArray(new String[aSignaturesToValidate.getSignatureFragments().size()]);
String address = aSignaturesToValidate.getAddress();
boolean isValidSignature = new Signing().validateSignatures(address, signatureFragments, bundleHash);
boolean isValidSignature = new Signing(customCurl.clone()).validateSignatures(address, signatureFragments, bundleHash);
if (!isValidSignature) throw new InvalidSignatureException();
}
@ -688,14 +687,14 @@ public class IotaAPI extends IotaAPICore {
/**
* Replays a transfer by doing Proof of Work again.
*
* @param transaction The transaction.
* @param depth The depth.
* @param transaction The transaction.
* @param depth The depth.
* @param minWeightMagnitude The minimum weight magnitude.
* @return Analyzed Transaction objects.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws ArgumentException is thrown when an invalid argument is provided.
* @throws InvalidSignatureException is thrown when an invalid signature is encountered.
* @throws InvalidTransferException is thrown when an invalid transfer is provided.
* @throws InvalidTransferException is thrown when an invalid transfer is provided.
*/
public ReplayBundleResponse replayBundle(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, ArgumentException, InvalidSignatureException, InvalidTrytesException {
StopWatch stopWatch = new StopWatch();
@ -743,20 +742,20 @@ public class IotaAPI extends IotaAPICore {
/**
* Wrapper function that basically does prepareTransfers, as well as attachToTangle and finally, it broadcasts and stores the transactions locally.
*
* @param seed Tryte-encoded seed
* @param security The security level of private key / seed.
* @param depth The depth.
* @param seed Tryte-encoded seed
* @param security The security level of private key / seed.
* @param depth The depth.
* @param minWeightMagnitude The minimum weight magnitude.
* @param transfers Array of transfer objects.
* @param inputs List of inputs used for funding the transfer.
* @param address If defined, this address will be used for sending the remainder value (of the inputs) to.
* @param transfers Array of transfer objects.
* @param inputs List of inputs used for funding the transfer.
* @param address If defined, this address will be used for sending the remainder value (of the inputs) to.
* @return Array of Transaction objects.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws NotEnoughBalanceException is thrown when a transfer fails because their is not enough balance to perform the transfer.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws NotEnoughBalanceException is thrown when a transfer fails because their is not enough balance to perform the transfer.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
* @throws InvalidTrytesException is thrown when invalid trytes is provided.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidTransferException is thrown when an invalid transfer is provided.
* @throws InvalidTrytesException is thrown when invalid trytes is provided.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidTransferException is thrown when an invalid transfer is provided.
*/
public SendTransferResponse sendTransfer(String seed, int security, int depth, int minWeightMagnitude, final List<Transfer> transfers, Input[] inputs, String address) throws NotEnoughBalanceException, InvalidSecurityLevelException, InvalidTrytesException, InvalidAddressException, InvalidTransferException {
@ -786,9 +785,9 @@ public class IotaAPI extends IotaAPICore {
* the bundle hash of the transaction is no longer the same. In case the input
* transaction hash is not a tail, we return an error.
*
* @param trunkTx Hash of a trunk or a tail transaction of a bundle.
* @param trunkTx Hash of a trunk or a tail transaction of a bundle.
* @param bundleHash The bundle hashes.
* @param bundle List of bundles to be populated.
* @param bundle List of bundles to be populated.
* @return Transaction objects.
* @throws ArgumentException is thrown when an invalid argument is provided.
*/
@ -838,14 +837,15 @@ public class IotaAPI extends IotaAPICore {
* Prepares transfer by generating the bundle with the corresponding cosigner transactions.
* Does not contain signatures.
*
* @param securitySum The sum of security levels used by all co-signers.
* @param inputAddress Array of input addresses as well as the securitySum.
* @param securitySum The sum of security levels used by all co-signers.
* @param inputAddress Array of input addresses as well as the securitySum.
* @param remainderAddress Has to be generated by the cosigners before initiating the transfer, can be null if fully spent.
* @return Bundle of transaction objects.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidBundleException is thrown if an invalid bundle was found or provided.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
*/
private GetTransferResponse initiateTransfer(int securitySum, final List<String> inputAddress, String remainderAddress, final List<Transfer> transfers) throws InvalidAddressException, InvalidBundleException, InvalidTransferException {
public List<Transaction> initiateTransfer(int securitySum, final String inputAddress, String remainderAddress,
final List<Transfer> transfers, boolean testMode) throws InvalidAddressException, InvalidBundleException, InvalidTransferException {
StopWatch sw = new StopWatch();
@ -869,10 +869,8 @@ public class IotaAPI extends IotaAPICore {
// validate input address
for (String address : inputAddress) {
if (!InputValidator.isAddress(address))
throw new InvalidBundleException();
}
if (!InputValidator.isAddress(inputAddress))
throw new InvalidAddressException();
// validate remainder address
if (remainderAddress != null && !InputValidator.isAddress(remainderAddress)) {
@ -944,7 +942,7 @@ public class IotaAPI extends IotaAPICore {
// Get inputs if we are sending tokens
if (totalValue != 0) {
GetBalancesResponse balancesResponse = getBalances(100, inputAddress);
GetBalancesResponse balancesResponse = getBalances(100, new String[]{inputAddress});
String[] balances = balancesResponse.getBalances();
long totalBalance = 0;
@ -958,16 +956,18 @@ public class IotaAPI extends IotaAPICore {
// get current timestamp in seconds
long timestamp = (long) Math.floor(Calendar.getInstance().getTimeInMillis() / 1000);
// bypass the balance checks during unit testing
if (testMode)
totalBalance += 1000;
if (totalBalance > 0) {
long toSubtract = 0 - totalBalance;
// Add input as bundle entry
// Only a single entry, signatures will be added later
// TODO: unfinished stuff
bundle.addEntry(securitySum, "", toSubtract, tag, timestamp);
bundle.addEntry(securitySum, inputAddress, toSubtract, tag, timestamp);
}
// Return not enough balance error
if (totalValue > totalBalance) {
throw new IllegalStateException("Not enough balance");
@ -986,24 +986,12 @@ public class IotaAPI extends IotaAPICore {
bundle.addEntry(1, remainderAddress, remainder, tag, timestamp);
}
// TODO: unfinished stuff
/*
bundle.finalize(customCurl.clone());
bundle.addTrytes(signatureFragments);
List<Transaction> trxb = bundle.getTransactions();
List<String> bundleTrytes = new ArrayList<>();
for (Transaction trx : trxb) {
bundleTrytes.add(trx.toTrytes());
}
return GetTransferResponse.create(bundle.getTransactions(), sw.getElapsedTimeMili());
*/
return null;
return bundle.getTransactions();
} else {
throw new RuntimeException("Invalid value transfer: the transfer does not require a signature.");
}
@ -1032,18 +1020,17 @@ public class IotaAPI extends IotaAPICore {
}
/**
* @param seed Tryte-encoded seed.
* @param security The security level of private key / seed.
* @param inputs List of inputs used for funding the transfer.
* @param bundle To be populated.
* @param tag The tag.
* @param totalValue The total value.
* @param remainderAddress If defined, this address will be used for sending the remainder value (of the inputs) to.
* @param seed Tryte-encoded seed.
* @param security The security level of private key / seed.
* @param inputs List of inputs used for funding the transfer.
* @param bundle To be populated.
* @param tag The tag.
* @param totalValue The total value.
* @param remainderAddress If defined, this address will be used for sending the remainder value (of the inputs) to.
* @param signatureFragments The signature fragments.
*
* @throws NotEnoughBalanceException is thrown when a transfer fails because their is not enough balance to perform the transfer.
* @throws NotEnoughBalanceException is thrown when a transfer fails because their is not enough balance to perform the transfer.
* @throws InvalidSecurityLevelException is thrown when the specified security level is not valid.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
*/
public List<String> addRemainder(final String seed,
final int security,

View File

@ -2,7 +2,7 @@ package jota;
/**
* IOTA's node command list
*
* <p>
* 'params' is not currently used.
*/
public enum IotaAPICommands {
@ -42,7 +42,6 @@ public enum IotaAPICommands {
}
/**
*
* @return
*/
public int params() {

View File

@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit;
/**
* This class provides access to the Iota core API
*
* @author Adrian
*/
public class IotaAPICore {
@ -65,7 +66,6 @@ public class IotaAPICore {
}
/**
*
* @param env
* @param def
* @return
@ -188,7 +188,7 @@ public class IotaAPICore {
}
public GetAttachToTangleResponse attachToTangle(String trunkTransaction, String branchTransaction, Integer minWeightMagnitude, String... trytes) throws InvalidTrytesException {
if(!InputValidator.isArrayOfTrytes(trytes)){
if (!InputValidator.isArrayOfTrytes(trytes)) {
throw new InvalidTrytesException();
}
@ -268,7 +268,6 @@ public class IotaAPICore {
}
/**
*
* @param host
* @return
*/
@ -278,7 +277,6 @@ public class IotaAPICore {
}
/**
*
* @param port
* @return
*/
@ -288,7 +286,6 @@ public class IotaAPICore {
}
/**
*
* @param protocol
* @return
*/

View File

@ -19,7 +19,7 @@ public interface IotaAPIService {
/**
* Returns information about your node.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getNodeInfo"}'
*
@ -31,7 +31,7 @@ public interface IotaAPIService {
/**
* Get the list of latest tips (unconfirmed transactions).
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getNeighbors"}'
*/
@ -41,7 +41,7 @@ public interface IotaAPIService {
/**
* Add a list of neighbors to your node.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "addNeighbors", "uris": ["udp://8.8.8.8:14265", "udp://8.8.8.5:14265"]}'
*/
@ -51,7 +51,7 @@ public interface IotaAPIService {
/**
* Removes a list of neighbors to your node.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "removeNeighbors", "uris": ["udp://8.8.8.8:14265", "udp://8.8.8.5:14265"]}'
*/
@ -61,7 +61,7 @@ public interface IotaAPIService {
/**
* Get the list of latest tips (unconfirmed transactions).
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getTips"}'
*/
@ -71,7 +71,7 @@ public interface IotaAPIService {
/**
* Find the transactions which match the specified input and return
*
* <p>
* curl http://localhost:14265 \ -X POST \ -H 'Content-Type: application/json' \
* -d '{"command": "findTransactions", "addresses": ["RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"]}'
*/
@ -82,7 +82,7 @@ public interface IotaAPIService {
/**
* Get the inclusion states of a set of transactions. This is for determining if a transaction was accepted and confirmed by the network or not. You can search for multiple tips (and thus, milestones) to get past inclusion states of transactions.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getInclusionStates", "transactions"Q9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"], "tips" : []}'
*/
@ -92,7 +92,7 @@ public interface IotaAPIService {
/**
* Returns the raw trytes data of a transaction.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getTrytes", "hashes": ["OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999"]}'
*/
@ -102,7 +102,7 @@ public interface IotaAPIService {
/**
* Tip selection which returns trunkTransaction and branchTransaction. The input value is the latest coordinator milestone, as provided through the getNodeInfo API call.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getTransactionsToApprove", "depth": 27}'
*/
@ -112,7 +112,7 @@ public interface IotaAPIService {
/**
* It returns the confirmed balance which a list of addresses have at the latest confirmed milestone.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "getBalances", "addresses": ["HBBYKAKTILIPVUKFOTSLHGENPTXYBNKXZFQFR9VQFWNBMTQNRVOUKPVPRNBSZVVILMAFBKOTBLGLWLOHQ"], "threshold": 100}'
*/
@ -122,7 +122,7 @@ public interface IotaAPIService {
/**
* Attaches the specified transactions (trytes) to the Tangle by doing Proof of Work.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "attachToTangle", "trunkTransaction": "JVMTDGDPDFYHMZPMWEKKANBQSLSDTIIHAYQUMZOKHXXXGJHJDQPOMDOMNRDKYCZRUFZROZDADTHZC9999", "branchTransaction": "P9KFSJVGSPLXAEBJSHWFZLGP9GGJTIO9YITDEHATDTGAFLPLBZ9FOFWWTKMAZXZHFGQHUOXLXUALY9999", "minWeightMagnitude": 18, "trytes": ["TRYTVALUEHERE"]}'
*/
@ -132,7 +132,7 @@ public interface IotaAPIService {
/**
* Interrupts and completely aborts the attachToTangle process.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "interruptAttachingToTangle" }
*/
@ -142,7 +142,7 @@ public interface IotaAPIService {
/**
* Broadcast a list of transactions to all neighbors. The input trytes for this call are provided by attachToTangle.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "broadcastTransactions", "trytes": ["BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"]}
*/
@ -152,7 +152,7 @@ public interface IotaAPIService {
/**
* Store transactions into the local storage. The trytes to be used for this call are returned by attachToTangle.
*
* <p>
* curl http://localhost:14265 -X POST -H 'Content-Type: application/json'
* -d '{"command": "storeTransactions", "trytes": ["BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"]}'
*/

View File

@ -29,6 +29,7 @@ public class GetBalancesResponse extends AbstractResponse {
/**
* Gets the balances.
*
* @return The balances.
*/
public String[] getBalances() {

View File

@ -2,6 +2,7 @@ package jota.error;
/**
* This exception occurs when invalid trytes is provided.
*
* @author Adrian
*/
public class InvalidTrytesException extends BaseException {

View File

@ -2,6 +2,7 @@ package jota.error;
/**
* This exception occurs when its not possible to get node info.
*
* @author Adrian
*/
public class NoNodeInfoException extends BaseException {

View File

@ -67,10 +67,10 @@ public class Bundle implements Comparable<Bundle> {
* Adds a bundle entry.
*
* @param signatureMessageLength Length of the signature message.
* @param address The address.
* @param value The value.
* @param tag The tag.
* @param timestamp The timestamp.
* @param address The address.
* @param value The value.
* @param tag The tag.
* @param timestamp The timestamp.
*/
public void addEntry(int signatureMessageLength, String address, long value, String tag, long timestamp) {
if (getTransactions() == null) {
@ -79,7 +79,7 @@ public class Bundle implements Comparable<Bundle> {
for (int i = 0; i < signatureMessageLength; i++) {
Transaction trx = new Transaction(address, i == 0 ? value : 0, tag, timestamp);
getTransactions().add(trx);
transactions.add(trx);
}
}
@ -197,7 +197,6 @@ public class Bundle implements Comparable<Bundle> {
*
* @param o An object to compare with this object.
* @return A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other" /> parameter.Zero This object is equal to <paramref name="other" />. Greater than zero This object is greater than <paramref name="other" />.
*/
@Override
public int compareTo(Bundle o) {

View File

@ -7,7 +7,7 @@ import java.util.List;
/**
* This class represents an Inputs.
*
* @author Adrian
* @author Adrian
**/
public class Inputs {

View File

@ -50,7 +50,7 @@ public class Signature {
/**
* Set the signatureFragments.
*
* @param signatureFragments The signatureFragments.
* @param signatureFragments The signatureFragments.
*/
public void setSignatureFragments(List<String> signatureFragments) {
this.signatureFragments = signatureFragments;

View File

@ -222,6 +222,7 @@ public class Transaction {
/**
* Set the current index.
*
* @param currentIndex The current index.
*/
public void setCurrentIndex(long currentIndex) {

View File

@ -28,7 +28,7 @@ public interface ICurl {
/**
* Squeezes the specified trits.
*
* @param trits The trits.
* @param trits The trits.
* @param offset The offset to start from.
* @param length The length.
* @return The squeezed trits.

View File

@ -2,7 +2,7 @@ package jota.pow;
/**
* (c) 2016 Come-from-Beyond
*
* <p>
* JCurl belongs to the sponge function family.
*/
public class JCurl implements ICurl {

View File

@ -34,6 +34,8 @@ public class Checksum {
public static String removeChecksum(String address) throws InvalidAddressException {
if (isAddressWithChecksum(address)) {
return removeChecksumFromAddress(address);
} else if (isAddressWithoutChecksum(address)) {
return address;
}
throw new InvalidAddressException();
}

View File

@ -49,9 +49,9 @@ public class Converter {
/**
* Converts the specified trits array to bytes.
*
* @param trits The trits.
* @param trits The trits.
* @param offset The offset to start from.
* @param size The size.
* @param size The size.
* @return The bytes.
*/
public static byte[] bytes(final int[] trits, final int offset, final int size) {
@ -122,6 +122,7 @@ public class Converter {
/**
* Converts the specified trinary encoded string into a trits array of the specified length.
*
* @param trytes The trytes.
* @param length The length.
* @return A trits array.
@ -200,7 +201,7 @@ public class Converter {
/**
* Copies the trits from the input string into the destination array
*
* @param input The input String.
* @param input The input String.
* @param destination The destination array.
* @return The destination.
*/
@ -217,9 +218,9 @@ public class Converter {
/**
* Converts trites to trytes.
*
* @param trits Teh trits to be converted.
* @param trits Teh trits to be converted.
* @param offset The offset to start from.
* @param size The size.
* @param size The size.
* @return The trytes.
**/
public static String trytes(final int[] trits, final int offset, final int size) {
@ -244,7 +245,7 @@ public class Converter {
/**
* Converts the specified trits array to trytes in integer representation.
*
* @param trits The trits.
* @param trits The trits.
* @param offset The offset to start from.
* @return The value.
*/
@ -286,7 +287,7 @@ public class Converter {
* Increments the specified trits.
*
* @param trits The trits.
* @param size The size.
* @param size The size.
*/
public static void increment(final int[] trits, final int size) {

View File

@ -55,7 +55,7 @@ public class InputValidator {
*
* @param trytes The trytes to validate.
* @param length The length.
* @return <code>true</code> if the specified string consist only of '9'; otherwise, <code>false</code>.
* @return <code>true</code> if the specified string consist only of '9'; otherwise, <code>false</code>.
**/
public static boolean isNinesTrytes(final String trytes, final int length) {
return trytes.matches("^[9]{" + (length == 0 ? "0," : length) + "}$");
@ -77,7 +77,7 @@ public class InputValidator {
* @param trytes The trytes array to validate.
* @return <code>true</code> if the specified array contains only valid trytes otherwise, <code>false</code>.
**/
public static boolean isArrayOfTrytes(String[] trytes){
public static boolean isArrayOfTrytes(String[] trytes) {
for (String tryte : trytes) {
// Check if correct 2673 trytes
if (!isTrytes(tryte, 2673)) {

View File

@ -21,11 +21,11 @@ public class IotaAPIUtils {
/**
* Generates a new address
*
* @param seed The tryte-encoded seed. It should be noted that this seed is not transferred.
* @param seed The tryte-encoded seed. It should be noted that this seed is not transferred.
* @param security The secuirty level of private key / seed.
* @param index The index to start search from. If the index is provided, the generation of the address is not deterministic.
* @param index The index to start search from. If the index is provided, the generation of the address is not deterministic.
* @param checksum The adds 9-tryte address checksum
* @param curl The curl instance.
* @param curl The curl instance.
* @return An String with address.
* @throws InvalidAddressException is thrown when the specified address is not an valid address.
*/

View File

@ -12,9 +12,9 @@ public class IotaUnitConverter {
/**
* Convert the iota amount.
*
* @param amount The amount.
* @param amount The amount.
* @param fromUnit The source unit e.g. the unit of amount.
* @param toUnit The target unit.
* @param toUnit The target unit.
* @return The specified amount in the target unit.
**/
public static long convertUnits(long amount, IotaUnits fromUnit, IotaUnits toUnit) {
@ -36,7 +36,7 @@ public class IotaUnitConverter {
/**
* Convert the iota amount to text.
*
* @param amount The amount.
* @param amount The amount.
* @param extended Extended length.
* @return The specified amount in the target unit.
**/
@ -60,8 +60,8 @@ public class IotaUnitConverter {
* Create amount with unit text.
*
* @param amountInUnit The amount in units.
* @param unit The unit.
* @param extended Extended length.
* @param unit The unit.
* @param extended Extended length.
* @return The target unit.
**/
private static String createAmountWithUnitDisplayText(double amountInUnit, IotaUnits unit, boolean extended) {
@ -74,8 +74,8 @@ public class IotaUnitConverter {
* Create amount text.
*
* @param amountInUnit The amount in units.
* @param unit The unit.
* @param extended Extended length.
* @param unit The unit.
* @param extended Extended length.
* @return The target unit.
**/
public static String createAmountDisplayText(double amountInUnit, IotaUnits unit, boolean extended) {

View File

@ -16,6 +16,7 @@ public class Multisig {
public Multisig(ICurl customCurl) {
this.curl = customCurl;
this.curl.reset();
this.signingInstance = new Signing(curl.clone());
}
@ -24,14 +25,13 @@ public class Multisig {
}
/**
* @param seed tryte-encoded seed. It should be noted that this seed is not transferred
* @param seed tryte-encoded seed. It should be noted that this seed is not transferred
* @param security security secuirty level of private key / seed
* @param index
* @return digest trytes
**/
private String getDigest(String seed, int security, int index) {
int[] key = signingInstance.key(Converter.trits(seed), security, index);
public String getDigest(String seed, int security, int index) {
int[] key = signingInstance.key(Converter.trits(seed, 243), index, security);
return Converter.trytes(signingInstance.digests(key));
}
@ -40,21 +40,19 @@ public class Multisig {
*
* @param digestTrytes
* @param curlStateTrytes
* @method addAddressDigest
* @return digest trytes
* @method addAddressDigest
**/
private String addAddressDigest(String digestTrytes, String curlStateTrytes, ICurl customCurl) {
public String addAddressDigest(String digestTrytes, String curlStateTrytes) {
int[] digest = Converter.trits(digestTrytes);
int[] digest = Converter.trits(digestTrytes, digestTrytes.length() * 3);
// If curlStateTrytes is provided, convert into trits
// else use empty state and initiate the creation of a new address
int[] curlState = curlStateTrytes.isEmpty() ? Converter.trits(curlStateTrytes) : new int[243];
ICurl curl = customCurl == null ? new JCurl() : customCurl;
int[] curlState = !curlStateTrytes.isEmpty() ? Converter.trits(curlStateTrytes,
digestTrytes.length() * 3) : new int[digestTrytes.length() * 3];
// initialize Curl with the provided state
curl.setState(curlState);
@ -67,24 +65,23 @@ public class Multisig {
/**
* Gets the key value of a seed
*
* @param seed tryte-encoded seed. It should be noted that this seed is not transferred
* @param seed tryte-encoded seed. It should be noted that this seed is not transferred
* @param index
* @return digest trytes
**/
private String getKey(String seed, int index, int security) {
public String getKey(String seed, int index, int security) {
return Converter.trytes(signingInstance.key(Converter.trits(seed), index, security));
return Converter.trytes(signingInstance.key(Converter.trits(seed, 81 * security), index, security));
}
/**
* Generates a new address
*
* @param curlStateTrytes
* @param customCurl
* @return address
**/
private String finalizeAddress(String curlStateTrytes, ICurl customCurl) {
public String finalizeAddress(String curlStateTrytes) {
int[] curlState = Converter.trits(curlStateTrytes);
@ -103,10 +100,9 @@ public class Multisig {
*
* @param multisigAddress
* @param digests
* @param customCurl
* @returns boolean
**/
private boolean validateAddress(String multisigAddress, int[][] digests, ICurl customCurl) {
public boolean validateAddress(String multisigAddress, int[][] digests) {
// initialize Curl with the provided state
curl.reset();
@ -131,7 +127,7 @@ public class Multisig {
* @param keyTrytes
* @return Returns bundle trytes.
**/
private void addSignature(Bundle[] bundleToSign, String inputAddress, String keyTrytes) {
public Bundle addSignature(Bundle bundleToSign, String inputAddress, String keyTrytes) {
// Get the security used for the private key
@ -148,66 +144,65 @@ public class Multisig {
int numSignedTxs = 0;
for (Bundle bundle : bundleToSign)
for (int i = 0; i < bundleToSign.getTransactions().size(); i++) {
for (int i = 0; i < bundle.getTransactions().size(); i++) {
if (bundleToSign.getTransactions().get(i).getAddress().equals(inputAddress)) {
if (!bundle.getTransactions().get(i).getAddress().equals(inputAddress)) {
// If transaction is already signed, increase counter
if (!InputValidator.isNinesTrytes(bundleToSign.getTransactions().get(i).getSignatureFragments(),
bundleToSign.getTransactions().get(i).getSignatureFragments().length())) {
// If transaction is already signed, increase counter
if (!InputValidator.isNinesTrytes(bundle.getTransactions().get(i).getSignatureFragments(), bundle.getTransactions().get(i).getSignatureFragments().length())) {
numSignedTxs++;
}
// Else sign the transactions
else {
numSignedTxs++;
String bundleHash = bundleToSign.getTransactions().get(i).getBundle();
// First 6561 trits for the firstFragment
int[] firstFragment = Arrays.copyOfRange(key, 0, 6561);
// Get the normalized bundle hash
int[][] normalizedBundleFragments = new int[3][27];
int[] normalizedBundleHash = bundleToSign.normalizedBundle(bundleHash);
// Split hash into 3 fragments
for (int k = 0; k < 3; k++) {
normalizedBundleFragments[k] = Arrays.copyOfRange(normalizedBundleHash, (k * 27), (k + 1) * 27);
}
// Else sign the transactions
else {
String bundleHash = bundle.getTransactions().get(i).getBundle();
// First 6561 trits for the firstFragment
int[] firstFragment = Arrays.copyOfRange(key, 0, 6561);
// Get the normalized bundle hash
int[][] normalizedBundleFragments = new int[3][27];
int[] normalizedBundleHash = bundle.normalizedBundle(bundleHash);
// Split hash into 3 fragments
for (int k = 0; k < 3; k++) {
normalizedBundleFragments[k] = Arrays.copyOfRange(normalizedBundleHash, (k * 27), (k + 1) * 27);
}
// First bundle fragment uses 27 trytes
int[] firstBundleFragment = normalizedBundleFragments[numSignedTxs % 3];
// Calculate the new signatureFragment with the first bundle fragment
int[] firstSignedFragment = signingInstance.signatureFragment(firstBundleFragment, firstFragment);
// First bundle fragment uses 27 trytes
int[] firstBundleFragment = normalizedBundleFragments[numSignedTxs % 3];
// Convert signature to trytes and assign the new signatureFragment
bundleToSign.getTransactions().get(i).setSignatureFragments(Converter.trytes(firstSignedFragment));
for (int j = 1; j < security; j++) {
// Next 6561 trits for the firstFragment
int[] nextFragment = Arrays.copyOfRange(key, 6561 * j, (j + 1) * 6561);
// Use the next 27 trytes
int[] nextBundleFragment = normalizedBundleFragments[(numSignedTxs + j) % 3];
// Calculate the new signatureFragment with the first bundle fragment
int[] firstSignedFragment = signingInstance.signatureFragment(firstBundleFragment, firstFragment);
int[] nextSignedFragment = signingInstance.signatureFragment(nextBundleFragment, nextFragment);
// Convert signature to trytes and assign the new signatureFragment
bundle.getTransactions().get(i).setSignatureFragments(Converter.trytes(firstSignedFragment));
for (int j = 1; j < security; j++) {
// Next 6561 trits for the firstFragment
int[] nextFragment = Arrays.copyOfRange(key, 6561 * j, (j + 1) * 6561);
// Use the next 27 trytes
int[] nextBundleFragment = normalizedBundleFragments[(numSignedTxs + j) % 3];
// Calculate the new signatureFragment with the first bundle fragment
int[] nextSignedFragment = signingInstance.signatureFragment(nextBundleFragment, nextFragment);
// Convert signature to trytes and add new bundle entry at i + j position
// Assign the signature fragment
bundle.getTransactions().get(i + j).setSignatureFragments(Converter.trytes(nextSignedFragment));
}
break;
// Convert signature to trytes and add new bundle entry at i + j position
// Assign the signature fragment
bundleToSign.getTransactions().get(i + j).setSignatureFragments(Converter.trytes(nextSignedFragment));
}
break;
}
}
}
return;
return bundleToSign;
}
}

View File

@ -51,7 +51,6 @@ public class Parallel {
}
/**
*
* @param <T>
*/
public interface Operation<T> {

View File

@ -1,6 +1,7 @@
package jota.utils;
import jota.model.Bundle;
import jota.model.Transaction;
import jota.pow.ICurl;
import jota.pow.JCurl;
@ -8,6 +9,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Signing {
/**
@ -15,14 +17,25 @@ public class Signing {
*/
private ICurl curl;
public Signing() {
this(null);
}
/**
* public Signing() {
* this(null);
* }
* <p>
* /**
*
* @param curl
*/
public Signing(ICurl curl) {
this.curl = curl == null ? new JCurl() : curl;
}
/**
* @param seed
* @param index
* @param length
* @return
*/
public int[] key(int[] seed, int index, int length) {
for (int i = 0; i < index; i++) {
@ -145,6 +158,31 @@ public class Signing {
return buffer;
}
public Boolean validateSignatures(Bundle signedBundle, String inputAddress) {
String bundleHash = "";
Transaction trx;
List<String> signatureFragments = new ArrayList<>();
for (int i = 0; i < signedBundle.getTransactions().size(); i++) {
trx = signedBundle.getTransactions().get(i);
if (trx.getAddress().equals(inputAddress)) {
bundleHash = trx.getBundle();
// if we reached remainder bundle
String signatureFragment = trx.getSignatureFragments();
if (InputValidator.isNinesTrytes(signatureFragment, signatureFragment.length())) {
break;
}
signatureFragments.add(signatureFragment);
}
}
return validateSignatures(inputAddress, signatureFragments.toArray(new String[signatureFragments.size()]), bundleHash);
}
public Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) {
Bundle bundle = new Bundle();

View File

@ -10,20 +10,20 @@ public class TrytesConverter {
/**
* Conversion of ascii encoded bytes to trytes.
* Input is a string (can be stringified JSON object), return value is Trytes
*
* <p>
* How the conversion works:
* 2 Trytes === 1 Byte
* There are a total of 27 different tryte values: 9ABCDEFGHIJKLMNOPQRSTUVWXYZ
*
* <p>
* 1. We get the decimal value of an individual ASCII character
* 2. From the decimal value, we then derive the two tryte values by basically calculating the tryte equivalent (e.g. 100 === 19 + 3 * 27)
* a. The first tryte value is the decimal value modulo 27 (27 trytes)
* b. The second value is the remainder (decimal value - first value), divided by 27
* 3. The two values returned from Step 2. are then input as indices into the available values list ('9ABCDEFGHIJKLMNOPQRSTUVWXYZ') to get the correct tryte value
*
*
* <p>
* <p>
* EXAMPLE
*
* <p>
* Lets say we want to convert the ASCII character "Z".
* 1. 'Z' has a decimal value of 90.
* 2. 90 can be represented as 9 + 3 * 27. To make it simpler:
@ -34,7 +34,6 @@ public class TrytesConverter {
* b. The second tryte value is '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'[3] === "C"
* Our tryte pair is "IC"
*
*
* @param inputString The input String.
* @return The ASCII char "Z" is represented as "IC" in trytes.
*/