mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-25 09:36:44 +00:00
ensure grinding for low R is done in the same way as libsecp256k1 so signatures match
This commit is contained in:
parent
db05e09fe5
commit
173743ba0d
4 changed files with 28 additions and 22 deletions
|
@ -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) |
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue