-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dfa19e2
commit e2cad6a
Showing
5 changed files
with
512 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
core/src/main/java/org/bitcorej/chain/adk/ADKStateProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package org.bitcorej.chain.adk; | ||
|
||
import org.apache.commons.lang3.ArrayUtils; | ||
import org.bitcorej.chain.ChainState; | ||
import org.bitcorej.chain.KeyPair; | ||
import org.bitcorej.chain.Transaction; | ||
import org.bitcorej.chain.adk.hash.Curl; | ||
import org.bitcorej.chain.adk.hash.ISS; | ||
import org.bitcorej.utils.NumericUtil; | ||
import org.json.JSONArray; | ||
import org.json.JSONObject; | ||
import org.nervos.ckb.type.fixed.UInt32; | ||
|
||
import java.security.SecureRandom; | ||
import java.util.List; | ||
|
||
public class ADKStateProvider implements ChainState { | ||
String characters = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||
|
||
@Override | ||
public KeyPair generateKeyPair(String secret) { | ||
int[] seed = Converter.trits(secret); | ||
int[] subseed = ISS.subseed(seed, 0); | ||
int[] key = ISS.key(subseed, 2); | ||
int[] digests = ISS.digests(key); | ||
int[] addressTrits = ISS.address(digests); | ||
String address = Converter.trytes(addressTrits); | ||
|
||
int[] l = Converter.trits(address); | ||
final int[] state = ArrayUtils.addAll(l, new int[729 - l.length]); | ||
Curl.transform(state); | ||
String checksum = Converter.trytes(state).substring(0, 9); | ||
return new KeyPair(secret, address + checksum); | ||
} | ||
|
||
@Override | ||
public KeyPair generateKeyPair() { | ||
StringBuilder seed = new StringBuilder(); | ||
for (int i = 0; i < 81; i++) { | ||
SecureRandom random = new SecureRandom(); | ||
byte[] bytes = new byte[4]; | ||
random.nextBytes(bytes); | ||
UInt32 uInt32 = new UInt32(NumericUtil.bytesToHex(bytes)); | ||
long index = uInt32.getValue() % 27; | ||
seed.append(characters, (int)index, (int)index + 1); | ||
} | ||
return generateKeyPair(seed.toString()); | ||
} | ||
|
||
@Override | ||
public Boolean validateTx(String rawTx, String requestTx) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public Transaction decodeRawTransaction(String rawTx) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public String signRawTransaction(String rawTx, List<String> keys) { | ||
String secret = keys.get(0); | ||
int[] seed = Converter.trits(secret); | ||
int[] subseed = ISS.subseed(seed, 0); | ||
int[] key = ISS.key(subseed, 2); | ||
|
||
JSONArray bundle = new JSONArray(rawTx); | ||
|
||
for (int i = 0; i < bundle.length(); i++) { | ||
if (bundle.getJSONObject(i).getLong("value") < 0) { | ||
String thisAddress = bundle.getJSONObject(i).getString("address"); | ||
JSONArray normalizedBundleHashArray = bundle.getJSONObject(i).getJSONArray("normalizedBundleHash"); | ||
int[] normalizedBundleHash = new int[normalizedBundleHashArray.length()]; | ||
for (int j = 0; j < normalizedBundleHashArray.length(); j++) { | ||
normalizedBundleHash[j] = normalizedBundleHashArray.getInt(j); | ||
} | ||
int[] firstBundleFragment = getSliceOfArray(normalizedBundleHash,0, 27); | ||
int[] firstFragment = getSliceOfArray(key,0, 6561); | ||
int[] firstSignedFragment = ISS.signatureFragment(firstBundleFragment, firstFragment); | ||
bundle.getJSONObject(i).put("signatureMessageFragment", Converter.trytes(firstSignedFragment)); | ||
for (int j = 0; j < bundle.length(); j++) { | ||
if (bundle.getJSONObject(j).getString("address").equals(thisAddress) && bundle.getJSONObject(i).getLong("value") == 0) { | ||
int[] secondFragment = getSliceOfArray(key, 6561, 2 * 6561); | ||
int[] secondBundleFragment = getSliceOfArray(key,27, 27 * 2); | ||
int[] secondSignedFragment = ISS.signatureFragment(secondBundleFragment, secondFragment); | ||
bundle.getJSONObject(j).put("signatureMessageFragment", Converter.trytes(secondSignedFragment)); | ||
} | ||
} | ||
} | ||
bundle.getJSONObject(i).remove("normalizedBundleHash"); | ||
} | ||
return bundle.toString(); | ||
} | ||
|
||
public static int[] getSliceOfArray(int[] arr, | ||
int start, int end) | ||
{ | ||
|
||
// Get the slice of the Array | ||
int[] slice = new int[end - start]; | ||
|
||
// Copy elements of arr to slice | ||
for (int i = 0; i < slice.length; i++) { | ||
slice[i] = arr[start + i]; | ||
} | ||
|
||
// return the slice | ||
return slice; | ||
} | ||
} |
136 changes: 136 additions & 0 deletions
136
core/src/main/java/org/bitcorej/chain/adk/Converter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package org.bitcorej.chain.adk; | ||
|
||
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"; | ||
|
||
public static final int MIN_TRYTE_VALUE = -13, MAX_TRYTE_VALUE = 13; | ||
|
||
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 long longValue(final int[] trits, final int offset, final int size) { | ||
|
||
long value = 0; | ||
for (int i = size; i-- > 0; ) { | ||
value = value * RADIX + trits[offset + i]; | ||
} | ||
return value; | ||
} | ||
|
||
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) { | ||
|
||
final 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; | ||
} | ||
|
||
private 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; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package org.bitcorej.chain.adk.hash; | ||
|
||
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 void 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); | ||
} | ||
|
||
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 static void transform(int[] state) { | ||
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; | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.