diff --git a/src/main/java/com/sparrowwallet/drongo/Utils.java b/src/main/java/com/sparrowwallet/drongo/Utils.java index 827e777..d45b9b3 100644 --- a/src/main/java/com/sparrowwallet/drongo/Utils.java +++ b/src/main/java/com/sparrowwallet/drongo/Utils.java @@ -12,10 +12,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.StandardCharsets; import java.util.*; public class Utils { @@ -115,6 +111,14 @@ public class Utils { return dest; } + public static void reverse(byte[] array) { + for (int i = 0; i < array.length / 2; i++) { + byte temp = array[i]; + array[i] = array[array.length - i - 1]; + array[array.length - i - 1] = temp; + } + } + /** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format. */ public static long readUint32(byte[] bytes, int offset) { return (bytes[offset] & 0xffl) | diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java b/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java index e31442a..1075ef3 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java @@ -470,7 +470,8 @@ public class ECKey implements EncryptableItem { } protected boolean hasLowR() { - return r.toByteArray().length <= 32; + //A low R signature will have less than 71 bytes when encoded to DER + return toCanonicalised().encodeToDER().length < 71; } @Override @@ -530,14 +531,14 @@ public class ECKey implements EncryptableItem { } ECDSASignature signature; - int counter = 0; + Integer counter = null; do { ECDSASigner signer = new ECDSASigner(new HMacDSANonceKCalculator(new SHA256Digest(), counter)); ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeyForSigning, CURVE); signer.init(true, privKey); BigInteger[] components = signer.generateSignature(input.getBytes()); signature = new ECDSASignature(components[0], components[1]).toCanonicalised(); - counter++; + counter = (counter == null ? 1 : counter+1); } while(!signature.hasLowR()); return signature; diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/HMacDSANonceKCalculator.java b/src/main/java/com/sparrowwallet/drongo/crypto/HMacDSANonceKCalculator.java index 90aa721..ee1e499 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/HMacDSANonceKCalculator.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/HMacDSANonceKCalculator.java @@ -21,7 +21,7 @@ public class HMacDSANonceKCalculator implements DSAKCalculator { private final HMac hMac; private final byte[] K; private final byte[] V; - private final long counter; + private final Long counter; private BigInteger n; @@ -31,11 +31,11 @@ public class HMacDSANonceKCalculator implements DSAKCalculator { * @param digest digest to build the HMAC on. * @param counter additional data as per RFC 6979 3.6 */ - public HMacDSANonceKCalculator(Digest digest, int counter) { + public HMacDSANonceKCalculator(Digest digest, Integer counter) { this.hMac = new HMac(digest); this.V = new byte[hMac.getMacSize()]; this.K = new byte[hMac.getMacSize()]; - this.counter = Integer.toUnsignedLong(counter); + this.counter = (counter == null ? null : Integer.toUnsignedLong(counter)); } public boolean isDeterministic() @@ -74,8 +74,12 @@ public class HMacDSANonceKCalculator implements DSAKCalculator { System.arraycopy(mVal, 0, m, m.length - mVal.length, mVal.length); - BigInteger additional = BigInteger.valueOf(counter); - byte[] aData = Utils.bigIntegerToBytes(additional, size); + byte[] c = null; + if(counter != null) { + BigInteger additional = BigInteger.valueOf(counter); + c = Utils.bigIntegerToBytes(additional, size); + Utils.reverse(c); + } hMac.init(new KeyParameter(K)); @@ -83,7 +87,9 @@ public class HMacDSANonceKCalculator implements DSAKCalculator { hMac.update((byte)0x00); hMac.update(x, 0, x.length); hMac.update(m, 0, m.length); - hMac.update(aData, 0, aData.length); + if(c != null) { + hMac.update(c, 0, c.length); + } hMac.doFinal(K, 0); @@ -97,6 +103,9 @@ public class HMacDSANonceKCalculator implements DSAKCalculator { hMac.update((byte)0x01); hMac.update(x, 0, x.length); hMac.update(m, 0, m.length); + if(counter != null) { + hMac.update(c, 0, c.length); + } hMac.doFinal(K, 0); diff --git a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java index 2f80dbe..b505475 100644 --- a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java +++ b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java @@ -83,7 +83,7 @@ public class PSBTEntry { do { bb.get(buf); - reverse(buf); + Utils.reverse(buf); ByteBuffer pbuf = ByteBuffer.wrap(buf); path.add(new ChildNumber(pbuf.getInt())); } while(bb.hasRemaining()); @@ -202,14 +202,6 @@ public class PSBTEntry { return bb.array(); } - private static void reverse(byte[] array) { - for (int i = 0; i < array.length / 2; i++) { - byte temp = array[i]; - array[i] = array[array.length - i - 1]; - array[array.length - i - 1] = temp; - } - } - public void checkOneByteKey() throws PSBTParseException { if(this.getKey().length != 1) { throw new PSBTParseException("PSBT key type must be one byte");