Skip to content

Instantly share code, notes, and snippets.

@th0br0
Created June 21, 2017 07:00
Show Gist options
  • Save th0br0/616b2441641c22a34fe154e8303b34d2 to your computer and use it in GitHub Desktop.
Save th0br0/616b2441641c22a34fe154e8303b34d2 to your computer and use it in GitHub Desktop.
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