mirror of
https://github.com/gosticks/iota.lib.java.git
synced 2026-10-04 05:26:59 +00:00
fixed signing
This commit is contained in:
@@ -313,7 +313,7 @@ public class IotaAPICore {
|
||||
nodeConfig = new Properties();
|
||||
if (null == fileReader) {
|
||||
try {
|
||||
fileReader = new FileReader("node_config.properties");
|
||||
fileReader = new FileReader("../node_config.properties");
|
||||
|
||||
if (null == bufferedReader) {
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jota.utils;
|
||||
|
||||
import jota.error.InvalidAddressException;
|
||||
import jota.error.InvalidSecurityLevelException;
|
||||
import jota.model.Bundle;
|
||||
import jota.model.Input;
|
||||
import jota.model.Transaction;
|
||||
@@ -28,8 +29,9 @@ public class IotaAPIUtils {
|
||||
* @param curl The curl instance.
|
||||
* @return An String with 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 static String newAddress(String seed, int security, int index, boolean checksum, ICurl curl) throws InvalidAddressException {
|
||||
public static String newAddress(String seed, int security, int index, boolean checksum, ICurl curl) throws InvalidAddressException, InvalidSecurityLevelException {
|
||||
Signing signing = new Signing(curl);
|
||||
final int[] key = signing.key(Converter.trits(seed), index, security);
|
||||
final int[] digests = signing.digests(key);
|
||||
@@ -46,7 +48,7 @@ public class IotaAPIUtils {
|
||||
public static List<String> signInputsAndReturn(final String seed,
|
||||
final List<Input> inputs,
|
||||
final Bundle bundle,
|
||||
final List<String> signatureFragments, ICurl curl) {
|
||||
final List<String> signatureFragments, ICurl curl) throws InvalidSecurityLevelException {
|
||||
|
||||
bundle.finalize(curl);
|
||||
bundle.addTrytes(signatureFragments);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package jota.utils;
|
||||
|
||||
import jota.error.InvalidSecurityLevelException;
|
||||
import jota.model.Bundle;
|
||||
import jota.pow.ICurl;
|
||||
import jota.pow.SpongeFactory;
|
||||
@@ -36,7 +37,7 @@ public class Multisig {
|
||||
* @param index Key index to start search from. If the index is provided, the generation of the address is not deterministic.
|
||||
* @return trytes
|
||||
**/
|
||||
public String getDigest(String seed, int security, int index) {
|
||||
public String getDigest(String seed, int security, int index) throws InvalidSecurityLevelException {
|
||||
int[] key = signingInstance.key(Converter.trits(seed, 243), index, security);
|
||||
return Converter.trytes(signingInstance.digests(key));
|
||||
}
|
||||
@@ -75,7 +76,7 @@ public class Multisig {
|
||||
* @return trytes.
|
||||
**/
|
||||
|
||||
public String getKey(String seed, int index, int security) {
|
||||
public String getKey(String seed, int index, int security) throws InvalidSecurityLevelException {
|
||||
|
||||
return Converter.trytes(signingInstance.key(Converter.trits(seed, 81 * security), index, security));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package jota.utils;
|
||||
|
||||
import jota.error.InvalidSecurityLevelException;
|
||||
import jota.model.Bundle;
|
||||
import jota.model.Transaction;
|
||||
import jota.pow.ICurl;
|
||||
@@ -9,12 +10,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static jota.pow.JCurl.HASH_LENGTH;
|
||||
|
||||
|
||||
public class Signing {
|
||||
public final static int KEY_LENGTH = 6561;
|
||||
|
||||
/**
|
||||
* Ask @come-from-beyond
|
||||
*/
|
||||
private ICurl curl;
|
||||
|
||||
/**
|
||||
@@ -31,15 +32,21 @@ public class Signing {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param seed
|
||||
* @param inSeed
|
||||
* @param index
|
||||
* @param length
|
||||
* @param security
|
||||
* @return
|
||||
*/
|
||||
public int[] key(int[] seed, int index, int length) {
|
||||
public int[] key(final int[] inSeed, final int index, int security) throws InvalidSecurityLevelException {
|
||||
if (security < 1 || security > 3) {
|
||||
throw new InvalidSecurityLevelException();
|
||||
}
|
||||
|
||||
int[] seed = inSeed.clone();
|
||||
|
||||
// Derive subseed.
|
||||
for (int i = 0; i < index; i++) {
|
||||
for (int j = 0; j < 243; j++) {
|
||||
for (int j = 0; j < HASH_LENGTH; j++) {
|
||||
if (++seed[j] > 1) {
|
||||
seed[j] = -1;
|
||||
} else {
|
||||
@@ -50,16 +57,18 @@ public class Signing {
|
||||
|
||||
curl.reset();
|
||||
curl.absorb(seed, 0, seed.length);
|
||||
curl.squeeze(seed, 0, seed.length);
|
||||
// seed[0..HASH_LENGTH] contains subseed
|
||||
curl.squeeze(seed, 0, HASH_LENGTH);
|
||||
curl.reset();
|
||||
curl.absorb(seed, 0, seed.length);
|
||||
// absorb subseed
|
||||
curl.absorb(seed, 0, HASH_LENGTH);
|
||||
|
||||
final int[] key = new int[length * seed.length * 27];
|
||||
final int[] key = new int[security * HASH_LENGTH * 27];
|
||||
int offset = 0;
|
||||
|
||||
while (length-- > 0) {
|
||||
while (security-- > 0) {
|
||||
for (int i = 0; i < 27; i++) {
|
||||
curl.squeeze(key, offset, seed.length);
|
||||
curl.squeeze(key, offset, HASH_LENGTH);
|
||||
offset += seed.length;
|
||||
}
|
||||
}
|
||||
@@ -67,20 +76,22 @@ public class Signing {
|
||||
}
|
||||
|
||||
public int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) {
|
||||
int[] signatureFragment = keyFragment.clone();
|
||||
|
||||
for (int i = 0; i < 27; i++) {
|
||||
|
||||
for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) {
|
||||
curl.reset()
|
||||
.absorb(keyFragment, i * 243, 243)
|
||||
.squeeze(keyFragment, i * 243, 243);
|
||||
.absorb(signatureFragment, i * HASH_LENGTH, HASH_LENGTH)
|
||||
.squeeze(signatureFragment, i * HASH_LENGTH, HASH_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
return keyFragment;
|
||||
return signatureFragment;
|
||||
}
|
||||
|
||||
public int[] address(int[] digests) {
|
||||
int[] address = new int[243];
|
||||
int[] address = new int[HASH_LENGTH];
|
||||
curl.reset()
|
||||
.absorb(digests)
|
||||
.squeeze(address);
|
||||
@@ -88,23 +99,25 @@ public class Signing {
|
||||
}
|
||||
|
||||
public int[] digests(int[] key) {
|
||||
int security = (int) Math.floor(key.length / KEY_LENGTH);
|
||||
|
||||
int[] digests = new int[(int) Math.floor(key.length / 6561) * 243];
|
||||
int[] digests = new int[security * HASH_LENGTH];
|
||||
int[] keyFragment = 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 i = 0; i < Math.floor(key.length / KEY_LENGTH); i++) {
|
||||
System.arraycopy(key, i * KEY_LENGTH, keyFragment, 0, KEY_LENGTH);
|
||||
|
||||
for (int j = 0; j < 27; j++) {
|
||||
for (int k = 0; k < 26; k++) {
|
||||
curl.reset()
|
||||
.absorb(keyFragment, j * 243, 243)
|
||||
.squeeze(keyFragment, j * 243, 243);
|
||||
.absorb(keyFragment, j * HASH_LENGTH, HASH_LENGTH)
|
||||
.squeeze(keyFragment, j * HASH_LENGTH, HASH_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
curl.reset();
|
||||
curl.absorb(keyFragment, 0, keyFragment.length);
|
||||
curl.squeeze(digests, i * 243, 243);
|
||||
curl.squeeze(digests, i * HASH_LENGTH, HASH_LENGTH);
|
||||
}
|
||||
return digests;
|
||||
}
|
||||
@@ -112,10 +125,10 @@ public class Signing {
|
||||
public int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) {
|
||||
curl.reset();
|
||||
ICurl jCurl = SpongeFactory.create(SpongeFactory.Mode.KERL);
|
||||
int[] buffer = new int[243];
|
||||
int[] buffer = new int[HASH_LENGTH];
|
||||
|
||||
for (int i = 0; i < 27; i++) {
|
||||
buffer = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243);
|
||||
buffer = Arrays.copyOfRange(signatureFragment, i * HASH_LENGTH, (i + 1) * HASH_LENGTH);
|
||||
|
||||
for (int j = normalizedBundleFragment[i] + 13; j-- > 0; ) {
|
||||
jCurl.reset();
|
||||
@@ -133,8 +146,8 @@ public class Signing {
|
||||
String bundleHash = "";
|
||||
Transaction trx;
|
||||
List<String> signatureFragments = new ArrayList<>();
|
||||
for (int i = 0; i < signedBundle.getTransactions().size(); i++) {
|
||||
|
||||
for (int i = 0; i < signedBundle.getTransactions().size(); i++) {
|
||||
trx = signedBundle.getTransactions().get(i);
|
||||
|
||||
if (trx.getAddress().equals(inputAddress)) {
|
||||
@@ -149,7 +162,6 @@ public class Signing {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return validateSignatures(inputAddress, signatureFragments.toArray(new String[signatureFragments.size()]), bundleHash);
|
||||
}
|
||||
|
||||
@@ -167,13 +179,13 @@ public class Signing {
|
||||
}
|
||||
|
||||
// Get digests
|
||||
int[] digests = new int[signatureFragments.length * 243];
|
||||
int[] digests = new int[signatureFragments.length * HASH_LENGTH];
|
||||
|
||||
for (int i = 0; i < signatureFragments.length; i++) {
|
||||
|
||||
int[] digestBuffer = digest(normalizedBundleFragments[i % 3], Converter.trits(signatureFragments[i]));
|
||||
|
||||
System.arraycopy(digestBuffer, 0, digests, i * 243, 243);
|
||||
System.arraycopy(digestBuffer, 0, digests, i * HASH_LENGTH, HASH_LENGTH);
|
||||
}
|
||||
String address = Converter.trytes(address(digests));
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import jota.error.InvalidAddressException;
|
||||
import jota.error.InvalidBundleException;
|
||||
import jota.error.InvalidSecurityLevelException;
|
||||
import jota.error.InvalidTransferException;
|
||||
import jota.model.Bundle;
|
||||
import jota.model.Transaction;
|
||||
@@ -39,7 +40,7 @@ public class IotaMultisigTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicMultiSigTest() throws InvalidBundleException, InvalidTransferException, InvalidAddressException {
|
||||
public void basicMultiSigTest() throws InvalidBundleException, InvalidTransferException, InvalidAddressException, InvalidSecurityLevelException {
|
||||
|
||||
Multisig ms = new Multisig();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jota;
|
||||
|
||||
import jota.error.InvalidAddressException;
|
||||
import jota.error.InvalidSecurityLevelException;
|
||||
import jota.model.Bundle;
|
||||
import jota.utils.*;
|
||||
import org.junit.Test;
|
||||
@@ -22,13 +23,13 @@ public class SigningTest {
|
||||
private static final String SIGNATURE2 = "URKFKLNXFEKDOGSQVMAOPEDIWSMTCKJZ9KEVWYALY9JAO9KHUGNDTMGQLKQJUIPWDIVMPEDSVPLFMDCIXDDT9WBBRTFQENL9AXLSBYHINXCDYBFGRNKJDYHAQVJKWCVOYXHTNBEZUNLVMJLUMZYJFAOW9PVVMJZNZZFJQEQFELVFZVFVWPJ9WQZJLPSGBYECHXSFVFQJGUCPFXC9GATTILVCAANNHOYMLOYX9QSUPCERYCOXPACZEEGLREBRZWXGUTTVTHB9GBRCIFEOBPIRXXPQKRSODEHDSZXLGIKXUQWNTQKIOPVDVSIK9WJUAEFOJBU9MBPBSVYSCLBMINTT9ZCTREZSMSVOPXSZOMCGFEZKMOCNLJ9QUTAPKBHRIAIYLCHUQHOINKSCMXWZVDGDXHNJQXJHPCCGBEWROVKEPAPBFFRCAVXZWIRKCRAWYHIHMDXFAGDJQNJJPYSQUHKFOOCEVQOGRQEIOQFKZWUQ9XVRNXKGMJOQEZHQZXQABWUQRBKXWHYUXEAEMDGXVY9WS9VJOCMGBQASSRNKAYJPTSPQEMYSJMTCLMDQJKDPBGQZZSFBDOKHBYY9UDRXNKTPWBCQTVKUGMEDUXL9TTKPATNIKVAGHACHPFSCRYNIRJBQC9OADPGWBFYYARSVNQCGMYQGCYLZH9KLMUIJPCLPQVS9BORXCJBXPDECJGKDNOUYWTKKFLXZARWKGUSMVMXKJTMRYZRERFCFGTZFZFCAOQSZGPQJUEZUJLJPU9QPMJUTZNLMSMPRGIFHUUZHMPMRBEBATEIIWPCOIMWOYOG9NYFBYOWFDKRXOTREBU99GNCPXKOWGI99LNVPRFFF9FCLFXI9HMUFU9NRLNJVTFNUSUJTAVOG9GKUYYEXIM9HTPIDTWIGLKRAQPKMQVZAPYMPSQIOJ9JZBWDMQHDSSRSHNCWSAJCSRORSEXLLQNZUKPXPGRLYMXOXWCCWWSBALFLXPHSGFLTOAFWPETBKJUMBLHMSKYLPJT9EJAZCPPNZWKPVCGKDJCRCLBBIAKVDSNWGONPLKFAYXZDI9FKPHDPKCB9UUPXLJVQTXOAZOQDRNSONXDVSLQGZYRIPGREYHRAUOSBFZDZPZHFNMWCZQGPXCZVLNCSASB9RQDFHOYMUVYLFKOEEWNREYCDMCTZIAFBFKLKRQWZCJHQZCZGWXIFTKRVMPHMVHAABHBDEV9WDEZBR9FLXLNBVNYKUOUFJQKNZVZVGZDDTFYNYFUVRLZKOLXXQYNV9MDVBLZSERXPGYKRIEZQZD9IBKFDT9AIYGWJJCXFWDUDURGJQLXVEJAVEOMZUVVTNCVBXEVQRDQIEHDUCSLCIJUTSCLFXEGMFYP9YLXELCZPMTBZWBIODZCFNJLVWTPQGLMQIHIABAYGJFFMOEDTCXGEDTNXMVXZYFGXRKVVRTIZ9ISXTDHAFPEKQZSM9XXQLOYBLTMD9MBERBIBEJDEXGMOLDZPZVVEPIRKJBDPAKFAWJPTCJSHZPDUKZEEHRFLMZCUGCOWFJBSTDGPHUIXSPPPHRQARMCFMTWKYPJNJQV9VSFZ9EWB9GVEAFUXHWRNUXQLCSBWROOITBATWUXUYGSMGAXKGEBP9ZJWXQWHBVPOSLDHTWXUOFQNO9EXSYPQF9LQLQAFNRU9MTIIRQLBBBYKUPANWRQKGESFARQIRUTGFMZVUKHZJYKTYOARTDOBIYBFRHJWEFHCYVHRHTLTWBRMUDVIVQVNELQMQRXYDNGVSICZINWIZCIWVFXLYOLYKWDNWCWFZUXHUWOPRDHMTSXOZX9CVHANU9ZXTJOGKEPYR9CHGOTIUQSWIALAOIKHQFXWY9ZWTSZADVXJNNZOLSCXVVFBRHLRBTGMSZOYNIXTAMABKGJTLGTZKRHOPPJMNYIQNVKRGXUQDWYEIEZYM9CSXO9YLSBJLDJUWOLUXDEKBGGEIDEXFLZMESDOITNYTNRLGOMHJH9HOLXJABUNLXCZYTXFPZMHRJPLXSVPDBJBBZX9TBIMZZFZOXUSFEJYHEXPFXGJCQTBBLPEEWAPHUETGXSXYYAF9PCCCOONRMQGAPJ9JO9BZQ9QSKTPFFYIFVHSLAZY9CWYSIMKDOSLRKWBHPGJGVEJEEMLCCWXKSOCMBMZZZJWYBBXE9FTAYJALGWITJRXAXWZEXMECTZEEIWZPHYX";
|
||||
|
||||
@Test
|
||||
public void testAddressGeneration() throws InvalidAddressException {
|
||||
public void testAddressGeneration() throws InvalidAddressException, InvalidSecurityLevelException {
|
||||
assertEquals(FIRST_ADDR, IotaAPIUtils.newAddress(TEST_SEED, 2, 0, true, null));
|
||||
assertEquals(SIXTH_ADDR, IotaAPIUtils.newAddress(TEST_SEED, 2, 5, true, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSigning() throws InvalidAddressException {
|
||||
public void testSigning() throws InvalidAddressException, InvalidSecurityLevelException {
|
||||
// we can sign any hash, so for convenience we will sign the first
|
||||
// address of our test seed
|
||||
// (but remove the checksum) with the key of our fifth address
|
||||
@@ -42,6 +43,17 @@ public class SigningTest {
|
||||
assertEquals(SIGNATURE2, Converter.trytes(signature2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyLength() throws InvalidSecurityLevelException {
|
||||
Signing signing = new Signing(null);
|
||||
int[] key = signing.key(Converter.trits(TEST_SEED), 5, 1);
|
||||
assertEquals(Signing.KEY_LENGTH, key.length);
|
||||
key = signing.key(Converter.trits(TEST_SEED), 5, 2);
|
||||
assertEquals(2 * Signing.KEY_LENGTH, key.length);
|
||||
key = signing.key(Converter.trits(TEST_SEED), 5, 3);
|
||||
assertEquals(3 * Signing.KEY_LENGTH, key.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVerifying() throws InvalidAddressException {
|
||||
assertTrue(new Signing(null).validateSignatures(removeChecksum(SIXTH_ADDR), new String[]{SIGNATURE1, SIGNATURE2}, removeChecksum(FIRST_ADDR)));
|
||||
|
||||
Reference in New Issue
Block a user