11package cfb .pearldiver ;
22
3+ import static cfb .pearldiver .PearlDiver .State .CANCELLED ;
4+ import static cfb .pearldiver .PearlDiver .State .COMPLETED ;
5+ import static cfb .pearldiver .PearlDiver .State .RUNNING ;
6+ import static jota .pow .JCurl .NUMBER_OF_ROUNDSP81 ;
7+
8+
39/**
4- * (c) 2016 Come-from-Beyond.
5- *
6- * See <https://github.com/iotaledger/PearlDiver>.
10+ * (c) 2016 Come-from-Beyond
11+ * See <https://github.com/iotaledger/iri/blob/dev/src/main/java/com/iota/iri/hash/PearlDiver.java
712 */
813public class PearlDiver {
914
10- public static final int TRANSACTION_LENGTH = 8019 ;
15+ enum State {
16+ RUNNING ,
17+ CANCELLED ,
18+ COMPLETED
19+ }
20+
21+ private static final int TRANSACTION_LENGTH = 8019 ;
1122
1223 private static final int CURL_HASH_LENGTH = 243 ;
1324 private static final int CURL_STATE_LENGTH = CURL_HASH_LENGTH * 3 ;
1425
15- private static final int RUNNING = 0 ;
16- private static final int CANCELLED = 1 ;
17- private static final int COMPLETED = 2 ;
18-
19- private volatile int state ;
26+ private static final long HIGH_BITS = 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L;
27+ private static final long LOW_BITS = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L;
2028
21- public synchronized void cancel () {
29+ private volatile State state ;
30+ private final Object syncObj = new Object ();
2231
23- state = CANCELLED ;
24-
25- notifyAll ();
32+ public void cancel () {
33+ synchronized (syncObj ) {
34+ state = CANCELLED ;
35+ syncObj .notifyAll ();
36+ }
2637 }
2738
28- public synchronized boolean search (final int [] transactionTrits , final int minWeightMagnitude , int numberOfThreads ) {
39+ public synchronized boolean search (final int [] transactionTrits , final int minWeightMagnitude ,
40+ int numberOfThreads ) {
2941
3042 if (transactionTrits .length != TRANSACTION_LENGTH ) {
31-
32- throw new RuntimeException ( "Invalid transaction trits length: " + transactionTrits .length );
43+ throw new RuntimeException (
44+ "Invalid transaction trits length: " + transactionTrits .length );
3345 }
3446 if (minWeightMagnitude < 0 || minWeightMagnitude > CURL_HASH_LENGTH ) {
35-
3647 throw new RuntimeException ("Invalid min weight magnitude: " + minWeightMagnitude );
3748 }
3849
39- state = RUNNING ;
50+ synchronized (syncObj ) {
51+ state = RUNNING ;
52+ }
4053
4154 final long [] midCurlStateLow = new long [CURL_STATE_LENGTH ], midCurlStateHigh = new long [CURL_STATE_LENGTH ];
4255
4356 {
4457 for (int i = CURL_HASH_LENGTH ; i < CURL_STATE_LENGTH ; i ++) {
45-
46- midCurlStateLow [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
47- midCurlStateHigh [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
58+ midCurlStateLow [i ] = HIGH_BITS ;
59+ midCurlStateHigh [i ] = HIGH_BITS ;
4860 }
4961
5062 int offset = 0 ;
@@ -54,25 +66,22 @@ public synchronized boolean search(final int[] transactionTrits, final int minWe
5466 for (int j = 0 ; j < CURL_HASH_LENGTH ; j ++) {
5567
5668 switch (transactionTrits [offset ++]) {
57-
5869 case 0 : {
70+ midCurlStateLow [j ] = HIGH_BITS ;
71+ midCurlStateHigh [j ] = HIGH_BITS ;
5972
60- midCurlStateLow [j ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
61- midCurlStateHigh [j ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
62-
63- } break ;
73+ }
74+ break ;
6475
6576 case 1 : {
66-
67- midCurlStateLow [j ] = 0b0000000000000000000000000000000000000000000000000000000000000000L;
68- midCurlStateHigh [j ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
69-
70- } break ;
77+ midCurlStateLow [j ] = LOW_BITS ;
78+ midCurlStateHigh [j ] = HIGH_BITS ;
79+ }
80+ break ;
7181
7282 default : {
73-
74- midCurlStateLow [j ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
75- midCurlStateHigh [j ] = 0b0000000000000000000000000000000000000000000000000000000000000000L;
83+ midCurlStateLow [j ] = HIGH_BITS ;
84+ midCurlStateHigh [j ] = LOW_BITS ;
7685 }
7786 }
7887 }
@@ -89,16 +98,14 @@ public synchronized boolean search(final int[] transactionTrits, final int minWe
8998 midCurlStateLow [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
9099 midCurlStateHigh [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
91100
92- }
93- break ;
101+ } break ;
94102
95103 case 1 : {
96104
97105 midCurlStateLow [i ] = 0b0000000000000000000000000000000000000000000000000000000000000000L;
98106 midCurlStateHigh [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
99107
100- }
101- break ;
108+ } break ;
102109
103110 default : {
104111
@@ -116,100 +123,117 @@ public synchronized boolean search(final int[] transactionTrits, final int minWe
116123 midCurlStateHigh [162 + 2 ] = 0b1111111111000000000111111111111111111000000000111111111111111111L;
117124 midCurlStateLow [162 + 3 ] = 0b1111111111000000000000000000000000000111111111111111111111111111L;
118125 midCurlStateHigh [162 + 3 ] = 0b0000000000111111111111111111111111111111111111111111111111111111L;
126+
119127 }
120128
121129 if (numberOfThreads <= 0 ) {
122-
123- numberOfThreads = Runtime .getRuntime ().availableProcessors () - 1 ;
124- if (numberOfThreads < 1 ) {
125-
126- numberOfThreads = 1 ;
127- }
130+ numberOfThreads = Math .max (Runtime .getRuntime ().availableProcessors () - 1 , 1 );
128131 }
129132
133+ Thread [] workers = new Thread [numberOfThreads ];
134+
130135 while (numberOfThreads -- > 0 ) {
131136
132137 final int threadIndex = numberOfThreads ;
133- ( new Thread (new Runnable () { public void run () {
138+ Thread worker = (new Thread () { public void run () {
134139
135140 final long [] midCurlStateCopyLow = new long [CURL_STATE_LENGTH ], midCurlStateCopyHigh = new long [CURL_STATE_LENGTH ];
136141 System .arraycopy (midCurlStateLow , 0 , midCurlStateCopyLow , 0 , CURL_STATE_LENGTH );
137142 System .arraycopy (midCurlStateHigh , 0 , midCurlStateCopyHigh , 0 , CURL_STATE_LENGTH );
138143 for (int i = threadIndex ; i -- > 0 ; ) {
144+ increment (midCurlStateCopyLow , midCurlStateCopyHigh , 162 + CURL_HASH_LENGTH / 9 ,
145+ 162 + (CURL_HASH_LENGTH / 9 ) * 2 );
139146
140- increment (midCurlStateCopyLow , midCurlStateCopyHigh , 162 + CURL_HASH_LENGTH / 9 , 162 + (CURL_HASH_LENGTH / 9 ) * 2 );
141147 }
142148
143149 final long [] curlStateLow = new long [CURL_STATE_LENGTH ], curlStateHigh = new long [CURL_STATE_LENGTH ];
144150 final long [] curlScratchpadLow = new long [CURL_STATE_LENGTH ], curlScratchpadHigh = new long [CURL_STATE_LENGTH ];
151+ long mask , outMask = 1 ;
145152 while (state == RUNNING ) {
146153
147- increment (midCurlStateCopyLow , midCurlStateCopyHigh , 162 + CURL_HASH_LENGTH / 9 , 162 + (CURL_HASH_LENGTH / 9 ) * 2 );
154+ increment (midCurlStateCopyLow , midCurlStateCopyHigh , 162 + (CURL_HASH_LENGTH / 9 ) * 2 ,
155+ CURL_HASH_LENGTH );
156+
148157 System .arraycopy (midCurlStateCopyLow , 0 , curlStateLow , 0 , CURL_STATE_LENGTH );
149158 System .arraycopy (midCurlStateCopyHigh , 0 , curlStateHigh , 0 , CURL_STATE_LENGTH );
150159 transform (curlStateLow , curlStateHigh , curlScratchpadLow , curlScratchpadHigh );
151160
152- NEXT_BIT_INDEX :
153- for (int bitIndex = 64 ; bitIndex -- > 0 ; ) {
154-
155- for (int i = minWeightMagnitude ; i -- > 0 ; ) {
156-
157- if ((((int )(curlStateLow [CURL_HASH_LENGTH - 1 - i ] >> bitIndex )) & 1 ) != (((int )(curlStateHigh [CURL_HASH_LENGTH - 1 - i ] >> bitIndex )) & 1 )) {
158-
159- continue NEXT_BIT_INDEX ;
160- }
161+ mask = HIGH_BITS ;
162+ for (int i = minWeightMagnitude ; i -- > 0 ; ) {
163+ mask &= ~(curlStateLow [CURL_HASH_LENGTH - 1 - i ] ^ curlStateHigh [
164+ CURL_HASH_LENGTH - 1 - i ]);
165+ if (mask == 0 ) {
166+ break ;
161167 }
168+ }
169+ if (mask == 0 ) {
170+ continue ;
171+ }
162172
163- synchronized (PearlDiver .this ) {
164-
165- if (state == RUNNING ) {
166-
167- state = COMPLETED ;
168-
169- for (int i = 0 ; i < CURL_HASH_LENGTH ; i ++) {
170-
171- transactionTrits [TRANSACTION_LENGTH - CURL_HASH_LENGTH + i ] = ((((int ) (midCurlStateCopyLow [i ] >> bitIndex )) & 1 ) == 0 ) ? 1 : (((((int ) (midCurlStateCopyHigh [i ] >> bitIndex )) & 1 ) == 0 ) ? -1 : 0 );
172- }
173-
174- PearlDiver .this .notifyAll ();
173+ synchronized (syncObj ) {
174+ if (state == RUNNING ) {
175+ state = COMPLETED ;
176+ while ((outMask & mask ) == 0 ) {
177+ outMask <<= 1 ;
175178 }
179+ for (int i = 0 ; i < CURL_HASH_LENGTH ; i ++) {
180+ transactionTrits [TRANSACTION_LENGTH - CURL_HASH_LENGTH + i ] =
181+ (midCurlStateCopyLow [i ] & outMask ) == 0 ? 1
182+ : (midCurlStateCopyHigh [i ] & outMask ) == 0 ? -1 : 0 ;
183+ }
184+ syncObj .notifyAll ();
176185 }
177-
178- break ;
179186 }
187+ break ;
180188 }
181-
182- }})).start ();
189+ }
190+ });
191+ workers [threadIndex ] = worker ;
192+ worker .start ();
183193 }
184194
185195 try {
186-
187- while (state == RUNNING ) {
188-
189- wait ();
196+ synchronized ( syncObj ) {
197+ if (state == RUNNING ) {
198+ syncObj . wait ();
199+ }
190200 }
191-
192201 } catch (final InterruptedException e ) {
202+ synchronized (syncObj ) {
203+ state = CANCELLED ;
204+ }
205+ }
193206
194- state = CANCELLED ;
207+ for (Thread worker : workers ) {
208+ try {
209+ worker .join ();
210+ } catch (final InterruptedException e ) {
211+ synchronized (syncObj ) {
212+ state = CANCELLED ;
213+ }
214+ }
195215 }
196216
197217 return state == COMPLETED ;
198218 }
199219
200- private static void transform (final long [] curlStateLow , final long [] curlStateHigh , final long [] curlScratchpadLow , final long [] curlScratchpadHigh ) {
220+ private static void transform (final long [] curlStateLow , final long [] curlStateHigh ,
221+ final long [] curlScratchpadLow , final long [] curlScratchpadHigh ) {
201222
202223 int curlScratchpadIndex = 0 ;
203- for (int round = 81 ; round -- > 0 ; ) {
204-
224+ for (int round = 0 ; round < NUMBER_OF_ROUNDSP81 ; round ++) {
205225 System .arraycopy (curlStateLow , 0 , curlScratchpadLow , 0 , CURL_STATE_LENGTH );
206226 System .arraycopy (curlStateHigh , 0 , curlScratchpadHigh , 0 , CURL_STATE_LENGTH );
207227
208228 for (int curlStateIndex = 0 ; curlStateIndex < CURL_STATE_LENGTH ; curlStateIndex ++) {
209-
210229 final long alpha = curlScratchpadLow [curlScratchpadIndex ];
211230 final long beta = curlScratchpadHigh [curlScratchpadIndex ];
212- final long gamma = curlScratchpadHigh [curlScratchpadIndex += (curlScratchpadIndex < 365 ? 364 : -365 )];
231+ if (curlScratchpadIndex < 365 ) {
232+ curlScratchpadIndex += 364 ;
233+ } else {
234+ curlScratchpadIndex += -365 ;
235+ }
236+ final long gamma = curlScratchpadHigh [curlScratchpadIndex ];
213237 final long delta = (alpha | (~gamma )) & (curlScratchpadLow [curlScratchpadIndex ] ^ beta );
214238
215239 curlStateLow [curlStateIndex ] = ~delta ;
@@ -218,26 +242,19 @@ private static void transform(final long[] curlStateLow, final long[] curlStateH
218242 }
219243 }
220244
221- private static void increment (final long [] midCurlStateCopyLow , final long [] midCurlStateCopyHigh , final int fromIndex , final int toIndex ) {
245+ private static void increment (final long [] midCurlStateCopyLow ,
246+ final long [] midCurlStateCopyHigh , final int fromIndex , final int toIndex ) {
222247
223248 for (int i = fromIndex ; i < toIndex ; i ++) {
224-
225- if (midCurlStateCopyLow [i ] == 0b0000000000000000000000000000000000000000000000000000000000000000L) {
226-
227- midCurlStateCopyLow [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
228- midCurlStateCopyHigh [i ] = 0b0000000000000000000000000000000000000000000000000000000000000000L;
229-
249+ if (midCurlStateCopyLow [i ] == LOW_BITS ) {
250+ midCurlStateCopyLow [i ] = HIGH_BITS ;
251+ midCurlStateCopyHigh [i ] = LOW_BITS ;
230252 } else {
231-
232- if (midCurlStateCopyHigh [i ] == 0b0000000000000000000000000000000000000000000000000000000000000000L) {
233-
234- midCurlStateCopyHigh [i ] = 0b1111111111111111111111111111111111111111111111111111111111111111L;
235-
253+ if (midCurlStateCopyHigh [i ] == LOW_BITS ) {
254+ midCurlStateCopyHigh [i ] = HIGH_BITS ;
236255 } else {
237-
238- midCurlStateCopyLow [i ] = 0b0000000000000000000000000000000000000000000000000000000000000000L;
256+ midCurlStateCopyLow [i ] = LOW_BITS ;
239257 }
240-
241258 break ;
242259 }
243260 }
0 commit comments