diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Bytes.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Bytes.java index 9ccd50a..bcd505d 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Bytes.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Bytes.java @@ -43,9 +43,24 @@ public class Bytes { return false; } + public static boolean lt(byte[] a, byte[] b, int size) { + for (int i = 0; i < size; i++) { + if (a[i] != b[i]) { + return lt(a[i], b[i]); + } + } + return false; + } + private static boolean lt(byte a, byte b) { if (a < 0) return b < 0 && a < b; if (b < 0) return a >= 0 || a < b; return a < b; } + + public static byte[] expand(byte[] source, int size) { + byte[] result = new byte[size]; + System.arraycopy(source, 0, result, size - source.length, source.length); + return result; + } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java index fdb7d41..fc0ab8e 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java @@ -18,11 +18,14 @@ package ch.dissem.bitmessage.utils; import ch.dissem.bitmessage.entity.ObjectMessage; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import static ch.dissem.bitmessage.utils.Bytes.inc; @@ -31,6 +34,7 @@ import static ch.dissem.bitmessage.utils.Bytes.inc; * Provides some methods to help with hashing and encryption. */ public class Security { + public static final Logger LOG = LoggerFactory.getLogger(Security.class); private static final SecureRandom RANDOM = new SecureRandom(); private static final BigInteger TWO = BigInteger.valueOf(2); @@ -73,24 +77,26 @@ public class Security { byte[] initialHash = getInitialHash(object); byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes); - // start with trialValue = 99999999999999999999 - byte[] trialValue; + if (target.length < 8) { + target = Bytes.expand(target, 8); + } // also start with nonce = 0 where nonce is 8 bytes in length and can be hashed as if it is a string. byte[] nonce = new byte[8]; - MessageDigest mda = md("SHA-512"); + MessageDigest mda = null; + try { + mda = MessageDigest.getInstance("SHA-512"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } do { inc(nonce); mda.update(nonce); mda.update(initialHash); - trialValue = bytes(mda.digest(mda.digest()), 8); - } while (Bytes.lt(target, trialValue)); + } while (Bytes.lt(target, mda.digest(mda.digest()), 8)); object.setNonce(nonce); } /** - * @param object - * @param nonceTrialsPerByte - * @param extraBytes * @throws IOException if proof of work doesn't check out */ public static void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException { @@ -113,6 +119,7 @@ public class Security { private static byte[] getProofOfWorkTarget(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException { BigInteger TTL = BigInteger.valueOf(object.getExpiresTime() - (System.currentTimeMillis() / 1000)); + LOG.debug("TTL: " + TTL + "s"); BigInteger numerator = TWO.pow(64); BigInteger powLength = BigInteger.valueOf(object.getPayloadBytes().length + extraBytes); BigInteger denominator = BigInteger.valueOf(nonceTrialsPerByte).multiply(powLength.add(powLength.multiply(TTL).divide(BigInteger.valueOf(2).pow(16)))); diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java b/domain/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java index 862158f..8a4f25c 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/utils/BytesTest.java @@ -50,4 +50,18 @@ public class BytesTest { assertEquals(a.compareTo(b) == -1, Bytes.lt(a.toByteArray(), b.toByteArray())); } } + + @Test + public void testLowerThanBounded() { + Random rnd = new Random(); + for (int i = 0; i < 1000; i++) { + BigInteger a = BigInteger.valueOf(rnd.nextLong()).pow((rnd.nextInt(5) + 1)).abs(); + BigInteger b = BigInteger.valueOf(rnd.nextLong()).pow((rnd.nextInt(5) + 1)).abs(); + System.out.println("a = " + a.toString(16) + "\tb = " + b.toString(16)); + assertEquals(a.compareTo(b) == -1, Bytes.lt( + Bytes.expand(a.toByteArray(), 100), + Bytes.expand(b.toByteArray(), 100), + 100)); + } + } }