Skip to content

Commit a9426c6

Browse files
committed
add() and sub() byte-based methods introduced
1 parent 807971f commit a9426c6

File tree

2 files changed

+143
-2
lines changed

2 files changed

+143
-2
lines changed

portable/comp-transfer/src/main/java/org/bosik/merklesync/HashUtils.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.bosik.merklesync;
1818

1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.List;
2122
import java.util.Locale;
2223
import java.util.Map.Entry;
@@ -196,6 +197,81 @@ public static String sum(Iterable<String> hashes)
196197
return result;
197198
}
198199

200+
public static byte[] add(byte[] a, byte[] b)
201+
{
202+
if (b == null)
203+
{
204+
return a;
205+
}
206+
207+
if (a == null)
208+
{
209+
return Arrays.copyOf(b, b.length);
210+
}
211+
212+
if (a.length != b.length)
213+
{
214+
throw new IllegalArgumentException(String.format(
215+
Locale.US,
216+
"Mismatched array size: %d != %d",
217+
a.length,
218+
b.length
219+
));
220+
}
221+
222+
for (int i = 0; i < a.length; i++)
223+
{
224+
int highA = (a[i] + 128) / 16;
225+
int lowA = (a[i] + 128) % 16;
226+
227+
int highB = (b[i] + 128) / 16;
228+
int lowB = (b[i] + 128) % 16;
229+
230+
final int highC = (highA + highB) % 16;
231+
final int lowC = (lowA + lowB) % 16;
232+
233+
a[i] = (byte) ((highC * 16 + lowC + 256) % 256);
234+
}
235+
236+
return a;
237+
}
238+
239+
public static byte[] sub(byte[] a, byte[] b)
240+
{
241+
if (b == null) // a - 0
242+
{
243+
return a;
244+
}
245+
246+
if (a != null && a.length != b.length)
247+
{
248+
throw new IllegalArgumentException(String.format(
249+
Locale.US,
250+
"Mismatched array size: %d != %d",
251+
a.length,
252+
b.length
253+
));
254+
}
255+
256+
final byte[] c = new byte[b.length];
257+
258+
for (int i = 0; i < b.length; i++)
259+
{
260+
final int highA = a == null ? 0 : ((a[i] + 256) % 256) / 16;
261+
final int lowA = a == null ? 0 : ((a[i] + 256) % 256) % 16;
262+
263+
final int highB = ((b[i] + 256) % 256) / 16;
264+
final int lowB = ((b[i] + 256) % 256) % 16;
265+
266+
final int highC = (16 + highA - highB) % 16;
267+
final int lowC = (16 + lowA - lowB) % 16;
268+
269+
c[i] = (byte) ((highC * 16 + lowC + 256) % 256);
270+
}
271+
272+
return c;
273+
}
274+
199275
// --------------------------------------------------------------------------------------
200276
// MERKLE TREE OPERATIONS
201277
// --------------------------------------------------------------------------------------

portable/comp-transfer/src/test/java/org/bosik/merklesync/TestHashUtils.java

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import java.util.SortedMap;
2828
import java.util.TreeMap;
2929

30-
import static junit.framework.Assert.fail;
31-
import static junit.framework.TestCase.assertEquals;
30+
import static org.junit.Assert.assertEquals;
31+
import static org.junit.Assert.fail;
3232

3333
@SuppressWarnings("static-method")
3434
public class TestHashUtils
@@ -176,6 +176,71 @@ public void test_sumStrings()
176176
HashUtils.sum("88888888888888888888888888888888", "88888888888888888888888888888888"));
177177
}
178178

179+
@Test
180+
public void test_subHash()
181+
{
182+
// corner cases
183+
assertArraysEquals(new byte[] {}, HashUtils.sub(new byte[] {}, new byte[] {}));
184+
assertArraysEquals(new byte[] { 1, 2, 3 }, HashUtils.sub(new byte[] { 1, 2, 3 }, null));
185+
186+
// "000000" - "010203" = "0f0e0d"
187+
assertArraysEquals(new byte[] { 15, 14, 13 }, HashUtils.sub(new byte[] { 0, 0, 0 }, new byte[] { 1, 2, 3 }));
188+
assertArraysEquals(new byte[] { 15, 14, 13 }, HashUtils.sub(null, new byte[] { 1, 2, 3 }));
189+
190+
// "0f0e0d" - "000000" = "0f0e0d"
191+
assertArraysEquals(new byte[] { 15, 14, 13 }, HashUtils.sub(new byte[] { 15, 14, 13 }, new byte[] { 0, 0, 0 }));
192+
193+
// normal cases
194+
assertArraysEquals(new byte[] { 0, 0, 0 }, HashUtils.sub(new byte[] { 1, 2, 3 }, new byte[] { 1, 2, 3 }));
195+
// "7f" - "ff" = "80"
196+
assertArraysEquals(new byte[] { -128 }, HashUtils.sub(new byte[] { 127 }, new byte[] { -1 }));
197+
198+
// "7f" = 127
199+
// "02" = 2
200+
// "01" = 1
201+
// "00" = 0
202+
// "ff" = -1
203+
// "fe" = -2
204+
// ..
205+
// "82" = -126
206+
// "81" = -127
207+
// "80" = -128
208+
209+
assertArraysEquals(HashUtils.strToByte("8f"), HashUtils.sub(
210+
HashUtils.strToByte("80"),
211+
HashUtils.strToByte("01")
212+
));
213+
}
214+
215+
@Test
216+
public void test_addSubHash()
217+
{
218+
// given
219+
final byte[] a = { 127, -128, 0 };
220+
final byte[] b = { 4, 5, 6 };
221+
222+
// when / then
223+
assertArraysEquals(new byte[] { 127, -128, 0 }, HashUtils.sub(HashUtils.add(a, b), b));
224+
}
225+
226+
@Test
227+
public void test_addHash()
228+
{
229+
// given
230+
final byte[] data = new byte[] { 0, 0, 0, 0 };
231+
232+
// when
233+
HashUtils.add(data, null);
234+
HashUtils.add(data, new byte[] { 0, 0, 0, 0 });
235+
HashUtils.add(data, new byte[] { 1, 2, 3, 4 });
236+
237+
// then
238+
assertEquals(
239+
HashUtils.byteToStr(new byte[] { 1, 2, 3, 4 }),
240+
HashUtils.byteToStr(data)
241+
);
242+
}
243+
179244
@Test
180245
public void test_sumIterable()
181246
{

0 commit comments

Comments
 (0)