1
1
package jota .pow ;
2
2
3
+ import jota .utils .Pair ;
3
4
import org .bouncycastle .jcajce .provider .digest .Keccak ;
4
5
5
- import java .math . BigInteger ;
6
- import java .util .Arrays ;
6
+ import java .util . LinkedHashSet ;
7
+ import java .util .Set ;
7
8
8
9
public class Kerl extends JCurl {
9
10
@@ -17,75 +18,259 @@ public class Kerl extends JCurl {
17
18
private byte [] byte_state ;
18
19
private int [] trit_state ;
19
20
20
- public Kerl () {
21
+ private static final int [] HALF_3 = new int []{
22
+ 0xa5ce8964 , 0x9f007669 , 0x1484504f , 0x3ade00d9 , 0x0c24486e , 0x50979d57 , 0x79a4c702 , 0x48bbae36 , 0xa9f6808b , 0xaa06a805 , 0xa87fabdf , 0x5e69ebef };
23
+ private static int BYTE_LENGTH = 48 ;
24
+ private static int INT_LENGTH = BYTE_LENGTH / 4 ;
25
+
26
+ Kerl () {
21
27
super ();
22
28
this .keccak = new Keccak .Digest384 ();
23
29
this .byte_state = new byte [BYTE_HASH_LENGTH ];
24
30
this .trit_state = new int [HASH_LENGTH ];
25
31
}
26
32
27
- public static BigInteger convertTritsToBigint (final int [] trits , final int offset , final int size ) {
33
+ private static final long toUnsignedLong (int i ) {
34
+ return i & 0xFFFFFFFFL ;
35
+ }
28
36
29
- BigInteger value = BigInteger .ZERO ;
37
+ private static int toUnsignedInt (byte x ) {
38
+ return x & 0xff ;
39
+ }
30
40
31
- for (int i = size ; i -- > 0 ; ) {
41
+ private static int sum (int [] toSum ) {
42
+ int sum = 0 ;
43
+ for (int i = 0 ; i < toSum .length ; i ++) {
44
+ sum += toSum [i ];
45
+ }
46
+ return sum ;
47
+ }
32
48
33
- value = value .multiply (BigInteger .valueOf (RADIX )).add (BigInteger .valueOf (trits [offset + i ]));
49
+ public static byte [] convertTritsToBytes (final int [] trits ) {
50
+ if (trits .length != Kerl .HASH_LENGTH ) {
51
+ throw new RuntimeException ("Input trits length must be " + Kerl .HASH_LENGTH + "in length" );
34
52
}
53
+ int [] base = new int [INT_LENGTH ];
35
54
36
- return value ;
37
- }
55
+ Set <Integer > setUniqueNumbers = new LinkedHashSet <Integer >();
56
+ for (int x : trits ) {
57
+ setUniqueNumbers .add (x );
58
+ }
59
+ if (setUniqueNumbers .size () == 1 && setUniqueNumbers .contains (-1 )) {
60
+ base = HALF_3 .clone ();
61
+ bigint_not (base );
62
+ bigint_add (base , 1 );
63
+ } else {
64
+ int size = INT_LENGTH ;
65
+ for (int i = Kerl .HASH_LENGTH - 1 ; i -- > 0 ; ) {
66
+ { // Multiply by radix
67
+ int sz = size ;
68
+ int carry = 0 ;
69
+
70
+ for (int j = 0 ; j < sz ; j ++) {
71
+ // full_mul
72
+ long v = Kerl .toUnsignedLong (base [j ]) * (Kerl .toUnsignedLong (RADIX )) + Kerl .toUnsignedLong (carry );
73
+ carry = (int ) ((v >> Integer .SIZE ) & 0xFFFFFFFF );
74
+ base [j ] = (int ) (v & 0xFFFFFFFF );
75
+ }
76
+
77
+ if (carry > 0 ) {
78
+ base [sz ] = carry ;
79
+ size += 1 ;
80
+ }
81
+ }
82
+ final int in = trits [i ] + 1 ;
83
+ { // Add
84
+ int sz = bigint_add (base , in );
85
+ if (sz > size ) {
86
+ size = sz ;
87
+ }
88
+ }
89
+ }
38
90
39
- private static BigInteger convertBytesToBigInt (final byte [] bytes , final int offset , final int size ) {
91
+ if (sum (base ) != 0 ) {
92
+ if (bigint_cmp (HALF_3 , base ) <= 0 ) {
93
+ // base is >= HALF_3.
94
+ // just do base - HALF_3
95
+ base = bigint_sub (base , HALF_3 );
96
+ } else {
97
+ // we don't have a wrapping sub.
98
+ // so we need to be clever.
99
+ base = bigint_sub (HALF_3 , base );
100
+ bigint_not (base );
101
+ bigint_add (base , 1 );
102
+ }
103
+ }
104
+
105
+ }
40
106
41
- return new BigInteger (Arrays .copyOfRange (bytes , offset , offset + size ));
107
+ byte [] out = new byte [BYTE_LENGTH ];
108
+
109
+ for (int i = 0 ; i < INT_LENGTH ; i ++) {
110
+ out [i * 4 + 0 ] = (byte ) ((base [INT_LENGTH - 1 - i ] & 0xFF000000 ) >> 24 );
111
+ out [i * 4 + 1 ] = (byte ) ((base [INT_LENGTH - 1 - i ] & 0x00FF0000 ) >> 16 );
112
+ out [i * 4 + 2 ] = (byte ) ((base [INT_LENGTH - 1 - i ] & 0x0000FF00 ) >> 8 );
113
+ out [i * 4 + 3 ] = (byte ) ((base [INT_LENGTH - 1 - i ] & 0x000000FF ) >> 0 );
114
+ }
115
+ return out ;
42
116
}
43
117
44
- private static int [] convertBigintToTrits (final BigInteger value , int size ) {
118
+ public static int [] convertBytesToTrits (byte [] bytes ) {
119
+ int [] base = new int [INT_LENGTH ];
120
+ int [] out = new int [243 ];
121
+ out [Kerl .HASH_LENGTH - 1 ] = 0 ;
45
122
46
- int [] destination = new int [ size ];
47
- BigInteger absoluteValue = value . compareTo ( BigInteger . ZERO ) < 0 ? value . negate () : value ;
48
- for ( int i = 0 ; i < size ; i ++) {
123
+ if ( bytes . length != BYTE_LENGTH ) {
124
+ throw new RuntimeException ( "Input base must be " + BYTE_LENGTH + " in length" ) ;
125
+ }
49
126
50
- BigInteger [] divRemainder = absoluteValue .divideAndRemainder (BigInteger .valueOf (RADIX ));
51
- int remainder = divRemainder [1 ].intValue ();
52
- absoluteValue = divRemainder [0 ];
127
+ for (int i = 0 ; i < INT_LENGTH ; i ++) {
128
+ base [INT_LENGTH - 1 - i ] = Kerl .toUnsignedInt (bytes [i * 4 ]) << 24 ;
129
+ base [INT_LENGTH - 1 - i ] |= Kerl .toUnsignedInt (bytes [i * 4 + 1 ]) << 16 ;
130
+ base [INT_LENGTH - 1 - i ] |= Kerl .toUnsignedInt (bytes [i * 4 + 2 ]) << 8 ;
131
+ base [INT_LENGTH - 1 - i ] |= Kerl .toUnsignedInt (bytes [i * 4 + 3 ]);
132
+ }
53
133
54
- if (remainder > MAX_TRIT_VALUE ) {
134
+ if (bigint_cmp (base , HALF_3 ) == 0 ) {
135
+ int val = 0 ;
136
+ if (base [0 ] > 0 ) {
137
+ val = -1 ;
138
+ } else if (base [0 ] < 0 ) {
139
+ val = 1 ;
140
+ }
141
+ for (int i = 0 ; i < Kerl .HASH_LENGTH - 1 ; i ++) {
142
+ out [i ] = val ;
143
+ }
55
144
56
- remainder = MIN_TRIT_VALUE ;
57
- absoluteValue = absoluteValue .add (BigInteger .ONE );
145
+ } else {
146
+ boolean flipTrits = false ;
147
+ // See if we have a positive or negative two's complement number.
148
+ if (Kerl .toUnsignedLong (base [INT_LENGTH - 1 ]) >> 31 != 0 ) {
149
+ // negative value.
150
+ bigint_not (base );
151
+ if (bigint_cmp (base , HALF_3 ) > 0 ) {
152
+ base = bigint_sub (base , HALF_3 );
153
+ flipTrits = true ;
154
+ } else {
155
+ bigint_add (base , 1 );
156
+ base = bigint_sub (HALF_3 , base );
157
+ }
158
+ } else {
159
+ // positive. we need to shift right by HALF_3
160
+ base = bigint_add (HALF_3 , base );
58
161
}
59
- destination [i ] = remainder ;
60
- }
61
162
62
- if (value .compareTo (BigInteger .ZERO ) < 0 ) {
163
+ int size = INT_LENGTH ;
164
+
165
+ int remainder = 0 ;
166
+ for (int i = 0 ; i < Kerl .HASH_LENGTH - 1 ; i ++) {
167
+ { //div_rem
168
+ remainder = 0 ;
63
169
64
- for (int i = 0 ; i < size ; i ++) {
170
+ for (int j = size - 1 ; j >= 0 ; j --) {
171
+ long lhs = (Kerl .toUnsignedLong (remainder ) << 32 ) | Kerl .toUnsignedLong (base [j ]);
172
+ long rhs = Kerl .toUnsignedLong (RADIX );
173
+
174
+ int q = (int ) (lhs / rhs );
175
+ int r = (int ) (lhs % rhs );
176
+ base [j ] = q ;
177
+ remainder = r ;
178
+ }
179
+ }
180
+ out [i ] = remainder - 1 ;
181
+ }
65
182
66
- destination [i ] = -destination [i ];
183
+ if (flipTrits ) {
184
+ for (int i = 0 ; i < out .length ; i ++) {
185
+ out [i ] = -out [i ];
186
+ }
67
187
}
68
188
}
69
189
70
- return destination ;
190
+ return out ;
71
191
}
72
192
73
- private static byte [] convertBigintToBytes (final BigInteger value , int size ) {
193
+ private static void bigint_not (int [] base ) {
194
+ for (int i = 0 ; i < base .length ; i ++) {
195
+ base [i ] = ~base [i ];
196
+ }
197
+ }
198
+
199
+ private static int bigint_add (int [] base , final int rh ) {
200
+ Pair <Integer , Boolean > res = full_add (base [0 ], rh , false );
201
+ base [0 ] = res .low ;
74
202
75
- final byte [] result = new byte [BYTE_HASH_LENGTH ];
203
+ int j = 1 ;
204
+ while (res .hi ) {
205
+ res = full_add (base [j ], 0 , true );
206
+ base [j ] = res .low ;
207
+ j += 1 ;
208
+ }
76
209
77
- final byte [] bytes = value .toByteArray ();
78
- int i = 0 ;
79
- while (i + bytes .length < BYTE_HASH_LENGTH ) {
210
+ return j ;
211
+ }
80
212
81
- result [i ++] = (byte ) (bytes [0 ] < 0 ? -1 : 0 );
213
+ private static int [] bigint_add (final int [] lh , final int [] rh ) {
214
+ int [] out = new int [INT_LENGTH ];
215
+ boolean carry = false ;
216
+ Pair <Integer , Boolean > ret ;
217
+ for (int i = 0 ; i < INT_LENGTH ; i ++) {
218
+ ret = full_add (lh [i ], rh [i ], carry );
219
+ out [i ] = ret .low ;
220
+ carry = ret .hi ;
82
221
}
83
- for (int j = bytes .length ; j -- > 0 ; ) {
84
222
85
- result [i ++] = bytes [bytes .length - 1 - j ];
223
+ if (carry ) {
224
+ throw new RuntimeException ("Exceeded max value." );
225
+ }
226
+
227
+ return out ;
228
+ }
229
+
230
+ private static int bigint_cmp (final int [] lh , final int [] rh ) {
231
+ for (int i = INT_LENGTH - 1 ; i >= 0 ; i --) {
232
+ int ret = Long .compare (Kerl .toUnsignedLong (lh [i ]), Kerl .toUnsignedLong (rh [i ]));
233
+ if (ret != 0 ) {
234
+ return ret ;
235
+ }
236
+ }
237
+ return 0 ;
238
+ }
239
+
240
+ private static int [] bigint_sub (final int [] lh , final int [] rh ) {
241
+ int [] out = new int [INT_LENGTH ];
242
+ boolean noborrow = true ;
243
+ Pair <Integer , Boolean > ret ;
244
+ for (int i = 0 ; i < INT_LENGTH ; i ++) {
245
+ ret = full_add (lh [i ], ~rh [i ], noborrow );
246
+ out [i ] = ret .low ;
247
+ noborrow = ret .hi ;
248
+ }
249
+
250
+ if (!noborrow ) {
251
+ throw new RuntimeException ("noborrow" );
252
+ }
253
+
254
+ return out ;
255
+ }
256
+
257
+ private static Pair <Integer , Boolean > full_add (final int ia , final int ib , final boolean carry ) {
258
+ long a = Kerl .toUnsignedLong (ia );
259
+ long b = Kerl .toUnsignedLong (ib );
260
+
261
+ long v = a + b ;
262
+ long l = v >> 32 ;
263
+ long r = v & 0xFFFFFFFF ;
264
+ boolean carry1 = l != 0 ;
265
+
266
+ if (carry ) {
267
+ v = r + 1 ;
86
268
}
269
+ l = (v >> 32 ) & 0xFFFFFFFF ;
270
+ r = v & 0xFFFFFFFF ;
271
+ boolean carry2 = l != 0 ;
87
272
88
- return result ;
273
+ return new Pair <>(( int ) r , carry1 || carry2 ) ;
89
274
}
90
275
91
276
@ Override
@@ -108,7 +293,7 @@ public Kerl absorb(final int[] trits, int offset, int length) {
108
293
109
294
//convert to bits
110
295
trit_state [HASH_LENGTH - 1 ] = 0 ;
111
- byte [] bytes = convertBigintToBytes ( convertTritsToBigint ( trit_state , 0 , HASH_LENGTH ), BYTE_HASH_LENGTH );
296
+ byte [] bytes = convertTritsToBytes ( trit_state );
112
297
113
298
//run keccak
114
299
keccak .update (bytes );
@@ -128,7 +313,7 @@ public int[] squeeze(final int[] trits, int offset, int length) {
128
313
129
314
byte_state = this .keccak .digest ();
130
315
//convert to trits
131
- trit_state = convertBigintToTrits ( convertBytesToBigInt ( byte_state , 0 , BYTE_HASH_LENGTH ), HASH_LENGTH );
316
+ trit_state = convertBytesToTrits ( byte_state );
132
317
133
318
//copy with offset
134
319
trit_state [HASH_LENGTH - 1 ] = 0 ;
0 commit comments