-
-
Save th0br0/616b2441641c22a34fe154e8303b34d2 to your computer and use it in GitHub Desktop.
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
public int[] findChecksum(final int[] trits, final int length, int numberOfThreads, final int sumLength) { | |
int rem = trits.length % Curl.HASH_LENGTH; | |
int end = trits.length / Curl.HASH_LENGTH; | |
if(rem != 0) { | |
end++; | |
} | |
int[] lengthTrits = Converter.trits(trits.length); | |
Pair<long[], long[]> midCurlState = absorb(lengthTrits, 1, null); | |
absorb(trits, end, midCurlState); | |
for(int i = 0; i < length; i++) { | |
midCurlState.hi[i] = HIGH_BITS; | |
midCurlState.low[i] = HIGH_BITS; | |
} | |
offset(midCurlState); | |
numberOfThreads = getThreadCount(numberOfThreads); | |
Thread[] workers = new Thread[numberOfThreads]; | |
int[] checksum; | |
AtomicInteger state = new AtomicInteger(RUNNING); | |
AtomicInteger checksumLength = new AtomicInteger(length); | |
checksum = new int[Curl.HASH_LENGTH]; | |
while (numberOfThreads-- > 0) { | |
workers[numberOfThreads] = new Thread(spawnChecksumFinder(checksum, trits, midCurlState, checksumLength, sumLength, numberOfThreads, syncObj, state), "Checksum Finder " + numberOfThreads); | |
workers[numberOfThreads].start(); | |
} | |
try { | |
synchronized (syncObj) { | |
if (state.get() == RUNNING) { | |
syncObj.wait(); | |
} | |
} | |
} catch (final InterruptedException e) { | |
state.set(CANCELLED); | |
synchronized (syncObj) { | |
state.set(CANCELLED); | |
} | |
} | |
for (Thread worker : workers) { | |
try { | |
worker.join(); | |
} catch (final InterruptedException e) { | |
synchronized (syncObj) { | |
state.set(CANCELLED); | |
} | |
} | |
} | |
checksum = Arrays.copyOf(checksum, checksumLength.get()); | |
int sum = ISS.checkChecksum(trits, checksum); | |
return checksum; | |
} | |
private static Runnable spawnChecksumFinder(final int[] out, final int[] trits, final Pair<long[], long[]> midCurlState, final AtomicInteger checksumLength, | |
final int sumLength, final int threadIndex, final Object syncObj, final AtomicInteger state) { | |
return () -> { | |
int length = checksumLength.get(); | |
int midLength = length/2; | |
Pair<long[], long[]> midCurlStateCopy = new Pair<>(new long[CURL_STATE_LENGTH], new long[CURL_STATE_LENGTH]); | |
Pair<long[], long[]> curlState = new Pair<>(new long[CURL_STATE_LENGTH], new long[CURL_STATE_LENGTH]); | |
Pair<long[], long[]> curlScratchpad = new Pair<>(new long[CURL_STATE_LENGTH], new long[CURL_STATE_LENGTH]); | |
System.arraycopy(midCurlState.low, 0, midCurlStateCopy.low, 0, CURL_STATE_LENGTH); | |
System.arraycopy(midCurlState.hi, 0, midCurlStateCopy.hi, 0, CURL_STATE_LENGTH); | |
for (int i = threadIndex; i-- > 0; ) { | |
increment(midCurlStateCopy.low, midCurlStateCopy.hi, 4, midLength); | |
} | |
while (state.get() == RUNNING) { | |
if(increment(midCurlStateCopy.low, midCurlStateCopy.hi, midLength, length) && length < CURL_HASH_LENGTH) { | |
length += 3; | |
} | |
System.arraycopy(midCurlStateCopy.low, 0, curlState.low, 0, CURL_STATE_LENGTH); | |
System.arraycopy(midCurlStateCopy.hi, 0, curlState.hi, 0, CURL_STATE_LENGTH); | |
transform(curlState.low, curlState.hi, curlScratchpad.low, curlScratchpad.hi); | |
int checksumIndex = checkChecksum(curlState, sumLength); | |
if(checksumIndex == -1) continue; | |
synchronized (syncObj) { | |
if (state.get() == RUNNING) { | |
int[] checksum = Converter.trits(midCurlStateCopy, checksumIndex); | |
int sum = ISS.checkChecksum(trits, Arrays.copyOf(checksum, length)); | |
if(sum == 0) { | |
state.set(COMPLETED); | |
System.arraycopy(checksum, 0, out, 0, length); | |
checksumLength.set(length); | |
syncObj.notifyAll(); | |
break; | |
} | |
} | |
} | |
} | |
}; | |
} | |
/** | |
* The point of the checksum finder is to find a checksum such that the sum of all trits of the final hash is 0. | |
* Here, we take the output of the final transform that would be run on `squeeze`, and we check that the number of | |
* high trits equals the number of low trits. This is done by transposing the state function so that each column, | |
* which was previously an individual state, is now in a row. We then find the first index where the hamming weight | |
* of the low hash is equal to the hi hash. | |
* the | |
* @param midCurlState the low/hi state array | |
* @return index | |
*/ | |
static int checkChecksum(Pair<long[], long[]> midCurlState, final int length) { | |
Pair<BigInteger[], BigInteger[]> checks = transpose(midCurlState, 0, length); | |
int out = -1; | |
for(int i = 0; i < Long.SIZE; i++) { | |
if(checks.low[i].bitCount() == checks.hi[i].bitCount()) { | |
out = i; | |
break; | |
} | |
} | |
return out; | |
} | |
private static long[] identity = new long[Long.SIZE]; | |
static { | |
for(int i = 0; i < identity.length; i++) { | |
identity[i] = 1<<i; | |
} | |
} | |
/** | |
* This performs a vanilla binary transpose, making rows into columns and vice versa. | |
* @param midCurlState | |
* @param offset | |
* @param length | |
* @return transposed pair matrix | |
*/ | |
static Pair<BigInteger[], BigInteger[]> transpose(Pair<long[], long[]> midCurlState, final int offset, final int length) { | |
Pair<BigInteger[], BigInteger[]> output = new Pair<>(new BigInteger[Long.SIZE], new BigInteger[Long.SIZE]); | |
for(int j = 0; j < Long.SIZE; j++) { | |
output.low[j] = new BigInteger(new byte[length]); | |
output.hi[j] = new BigInteger(new byte[length]); | |
for(int i = 0; i < length; i++) { | |
if((midCurlState.low[offset + i] & identity[j]) != 0) { | |
output.low[j] = output.low[j].setBit(i); | |
} | |
if((midCurlState.hi[offset + i] & identity[j]) != 0) { | |
output.hi[j] = output.hi[j].setBit(i); | |
} | |
} | |
} | |
return output; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment